Skip to content

Commit c9991ab

Browse files
committed
Fix using shapes without TaritDefinition as trait
1 parent 3803222 commit c9991ab

4 files changed

Lines changed: 48 additions & 2 deletions

File tree

smithy-model/src/main/java/software/amazon/smithy/model/loader/LoadOperationProcessor.java

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
*/
55
package software.amazon.smithy.model.loader;
66

7+
import static software.amazon.smithy.model.validation.Severity.ERROR;
8+
79
import java.util.ArrayDeque;
810
import java.util.ArrayList;
911
import java.util.Collection;
@@ -18,9 +20,11 @@
1820
import software.amazon.smithy.model.shapes.Shape;
1921
import software.amazon.smithy.model.shapes.ShapeId;
2022
import software.amazon.smithy.model.shapes.ShapeType;
23+
import software.amazon.smithy.model.traits.TraitDefinition;
2124
import software.amazon.smithy.model.traits.TraitFactory;
2225
import software.amazon.smithy.model.validation.ValidationEvent;
2326
import software.amazon.smithy.model.validation.ValidationEventDecorator;
27+
import software.amazon.smithy.model.validation.Validator;
2428

2529
final class LoadOperationProcessor implements Consumer<LoadOperation> {
2630

@@ -125,9 +129,11 @@ Model buildModel() {
125129
Model.Builder modelBuilder = Model.builder();
126130
modelBuilder.metadata(metadata.getData());
127131
resolveForwardReferences();
128-
traitMap.applyTraitsToNonMixinsInShapeMap(shapeMap);
132+
List<ShapeId> undefinedTraits = new ArrayList<>();
133+
traitMap.applyTraitsToNonMixinsInShapeMap(shapeMap, undefinedTraits);
129134
shapeMap.buildShapesAndClaimMixinTraits(modelBuilder, traitMap::claimTraitsForShape);
130135
traitMap.emitUnclaimedTraits();
136+
validateTraitWithTraitDefinition(undefinedTraits, modelBuilder);
131137
if (prelude != null) {
132138
modelBuilder.addShapes(prelude);
133139
}
@@ -138,6 +144,28 @@ List<ValidationEvent> events() {
138144
return events;
139145
}
140146

147+
private void validateTraitWithTraitDefinition(List<ShapeId> undefiedTraits, Model.Builder modelBuilder) {
148+
Map<ShapeId, Shape> shapes = modelBuilder.getCurrentShapes();
149+
for (ShapeId traitId : undefiedTraits) {
150+
if (shapes.containsKey(traitId)) {
151+
Shape traitShape = shapes.get(traitId);
152+
if (!traitShape.hasTrait(TraitDefinition.ID)) {
153+
events.add(ValidationEvent.builder()
154+
.id(Validator.MODEL_ERROR)
155+
.severity(ERROR)
156+
.sourceLocation(traitShape.getSourceLocation())
157+
.shapeId(traitId)
158+
.message(
159+
String.format(
160+
"Shape `%s` cannot be applied as a trait. If this is a custom trait, " +
161+
"please add `@trait` to this shape.",
162+
traitId))
163+
.build());
164+
}
165+
}
166+
}
167+
}
168+
141169
private void resolveForwardReferences() {
142170
while (!forwardReferences.isEmpty()) {
143171
LoadOperation.ForwardReference reference = forwardReferences.poll();

smithy-model/src/main/java/software/amazon/smithy/model/loader/LoaderTraitMap.java

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import software.amazon.smithy.model.shapes.ShapeId;
2424
import software.amazon.smithy.model.traits.DynamicTrait;
2525
import software.amazon.smithy.model.traits.Trait;
26+
import software.amazon.smithy.model.traits.TraitDefinition;
2627
import software.amazon.smithy.model.traits.TraitFactory;
2728
import software.amazon.smithy.model.validation.Severity;
2829
import software.amazon.smithy.model.validation.ValidationEvent;
@@ -46,7 +47,7 @@ final class LoaderTraitMap {
4647
this.allowUnknownTraits = allowUnknownTraits;
4748
}
4849

49-
void applyTraitsToNonMixinsInShapeMap(LoaderShapeMap shapeMap) {
50+
void applyTraitsToNonMixinsInShapeMap(LoaderShapeMap shapeMap, List<ShapeId> undefinedTraits) {
5051
for (Map.Entry<ShapeId, Map<ShapeId, Node>> entry : traits.entrySet()) {
5152
ShapeId target = entry.getKey();
5253
ShapeId root = target.withoutMember();
@@ -64,6 +65,7 @@ void applyTraitsToNonMixinsInShapeMap(LoaderShapeMap shapeMap) {
6465
Node traitNode = traitEntry.getValue();
6566
Trait created = createTrait(target, traitId, traitNode);
6667
validateTraitIsKnown(target, traitId, created, traitNode.getSourceLocation(), shapeMap);
68+
validateTraitWithTraitDefinition(traitId, undefinedTraits);
6769

6870
if (target.hasMember()) {
6971
// Apply the trait to a member by reaching into the members of each LoadOperation.DefineShape.
@@ -144,6 +146,13 @@ private void validateTraitIsKnown(
144146
}
145147
}
146148

149+
private void validateTraitWithTraitDefinition(ShapeId traitId, List<ShapeId> undefinedTraits) {
150+
Map<ShapeId, Node> appliedTraits = traits.get(traitId);
151+
if (appliedTraits == null || !appliedTraits.containsKey(TraitDefinition.ID)) {
152+
undefinedTraits.add(traitId);
153+
}
154+
}
155+
147156
private void applyTraitsToShape(AbstractShapeBuilder<?, ?> shape, Trait trait) {
148157
if (trait != null) {
149158
shape.addTrait(trait);
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[ERROR] com.foo#MyDoc: Shape `com.foo#MyDoc` cannot be applied as a trait. If this is a custom trait, please add `@trait` to this shape. | Model
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
$version: "1.0"
2+
3+
namespace com.foo
4+
5+
document MyDoc
6+
7+
@MyDoc(name: "aa")
8+
structure MyStruct {}

0 commit comments

Comments
 (0)