From c9991abb793fb46b28d02fac417ae79b5a918545 Mon Sep 17 00:00:00 2001 From: Joe Wu Date: Thu, 7 Aug 2025 16:08:37 -0700 Subject: [PATCH 1/2] Fix using shapes without TaritDefinition as trait --- .../model/loader/LoadOperationProcessor.java | 30 ++++++++++++++++++- .../smithy/model/loader/LoaderTraitMap.java | 11 ++++++- .../invalid-other-shapes-as-trait.errors | 1 + .../invalid-other-shapes-as-trait.smithy | 8 +++++ 4 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/loader/invalid-other-shapes-as-trait.errors create mode 100644 smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/loader/invalid-other-shapes-as-trait.smithy diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/loader/LoadOperationProcessor.java b/smithy-model/src/main/java/software/amazon/smithy/model/loader/LoadOperationProcessor.java index 6574e49a3ea..844f6532cdd 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/loader/LoadOperationProcessor.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/loader/LoadOperationProcessor.java @@ -4,6 +4,8 @@ */ package software.amazon.smithy.model.loader; +import static software.amazon.smithy.model.validation.Severity.ERROR; + import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collection; @@ -18,9 +20,11 @@ import software.amazon.smithy.model.shapes.Shape; import software.amazon.smithy.model.shapes.ShapeId; import software.amazon.smithy.model.shapes.ShapeType; +import software.amazon.smithy.model.traits.TraitDefinition; import software.amazon.smithy.model.traits.TraitFactory; import software.amazon.smithy.model.validation.ValidationEvent; import software.amazon.smithy.model.validation.ValidationEventDecorator; +import software.amazon.smithy.model.validation.Validator; final class LoadOperationProcessor implements Consumer { @@ -125,9 +129,11 @@ Model buildModel() { Model.Builder modelBuilder = Model.builder(); modelBuilder.metadata(metadata.getData()); resolveForwardReferences(); - traitMap.applyTraitsToNonMixinsInShapeMap(shapeMap); + List undefinedTraits = new ArrayList<>(); + traitMap.applyTraitsToNonMixinsInShapeMap(shapeMap, undefinedTraits); shapeMap.buildShapesAndClaimMixinTraits(modelBuilder, traitMap::claimTraitsForShape); traitMap.emitUnclaimedTraits(); + validateTraitWithTraitDefinition(undefinedTraits, modelBuilder); if (prelude != null) { modelBuilder.addShapes(prelude); } @@ -138,6 +144,28 @@ List events() { return events; } + private void validateTraitWithTraitDefinition(List undefiedTraits, Model.Builder modelBuilder) { + Map shapes = modelBuilder.getCurrentShapes(); + for (ShapeId traitId : undefiedTraits) { + if (shapes.containsKey(traitId)) { + Shape traitShape = shapes.get(traitId); + if (!traitShape.hasTrait(TraitDefinition.ID)) { + events.add(ValidationEvent.builder() + .id(Validator.MODEL_ERROR) + .severity(ERROR) + .sourceLocation(traitShape.getSourceLocation()) + .shapeId(traitId) + .message( + String.format( + "Shape `%s` cannot be applied as a trait. If this is a custom trait, " + + "please add `@trait` to this shape.", + traitId)) + .build()); + } + } + } + } + private void resolveForwardReferences() { while (!forwardReferences.isEmpty()) { LoadOperation.ForwardReference reference = forwardReferences.poll(); diff --git a/smithy-model/src/main/java/software/amazon/smithy/model/loader/LoaderTraitMap.java b/smithy-model/src/main/java/software/amazon/smithy/model/loader/LoaderTraitMap.java index 5a907b4a28e..a021728c3f5 100644 --- a/smithy-model/src/main/java/software/amazon/smithy/model/loader/LoaderTraitMap.java +++ b/smithy-model/src/main/java/software/amazon/smithy/model/loader/LoaderTraitMap.java @@ -23,6 +23,7 @@ import software.amazon.smithy.model.shapes.ShapeId; import software.amazon.smithy.model.traits.DynamicTrait; import software.amazon.smithy.model.traits.Trait; +import software.amazon.smithy.model.traits.TraitDefinition; import software.amazon.smithy.model.traits.TraitFactory; import software.amazon.smithy.model.validation.Severity; import software.amazon.smithy.model.validation.ValidationEvent; @@ -46,7 +47,7 @@ final class LoaderTraitMap { this.allowUnknownTraits = allowUnknownTraits; } - void applyTraitsToNonMixinsInShapeMap(LoaderShapeMap shapeMap) { + void applyTraitsToNonMixinsInShapeMap(LoaderShapeMap shapeMap, List undefinedTraits) { for (Map.Entry> entry : traits.entrySet()) { ShapeId target = entry.getKey(); ShapeId root = target.withoutMember(); @@ -64,6 +65,7 @@ void applyTraitsToNonMixinsInShapeMap(LoaderShapeMap shapeMap) { Node traitNode = traitEntry.getValue(); Trait created = createTrait(target, traitId, traitNode); validateTraitIsKnown(target, traitId, created, traitNode.getSourceLocation(), shapeMap); + validateTraitWithTraitDefinition(traitId, undefinedTraits); if (target.hasMember()) { // Apply the trait to a member by reaching into the members of each LoadOperation.DefineShape. @@ -144,6 +146,13 @@ private void validateTraitIsKnown( } } + private void validateTraitWithTraitDefinition(ShapeId traitId, List undefinedTraits) { + Map appliedTraits = traits.get(traitId); + if (appliedTraits == null || !appliedTraits.containsKey(TraitDefinition.ID)) { + undefinedTraits.add(traitId); + } + } + private void applyTraitsToShape(AbstractShapeBuilder shape, Trait trait) { if (trait != null) { shape.addTrait(trait); diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/loader/invalid-other-shapes-as-trait.errors b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/loader/invalid-other-shapes-as-trait.errors new file mode 100644 index 00000000000..380975a3e1d --- /dev/null +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/loader/invalid-other-shapes-as-trait.errors @@ -0,0 +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 \ No newline at end of file diff --git a/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/loader/invalid-other-shapes-as-trait.smithy b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/loader/invalid-other-shapes-as-trait.smithy new file mode 100644 index 00000000000..96e035fa922 --- /dev/null +++ b/smithy-model/src/test/resources/software/amazon/smithy/model/errorfiles/loader/invalid-other-shapes-as-trait.smithy @@ -0,0 +1,8 @@ +$version: "1.0" + +namespace com.foo + +document MyDoc + +@MyDoc(name: "aa") +structure MyStruct {} From 4c7c4fc8a1324992a7e767ba1f9cdbadab66b123 Mon Sep 17 00:00:00 2001 From: Joe Wu Date: Fri, 8 Aug 2025 10:39:24 -0700 Subject: [PATCH 2/2] Fix cli-integ failures --- .../smithy/cli/projects/model-with-warning/model/main.smithy | 1 + 1 file changed, 1 insertion(+) diff --git a/smithy-cli/src/it/resources/software/amazon/smithy/cli/projects/model-with-warning/model/main.smithy b/smithy-cli/src/it/resources/software/amazon/smithy/cli/projects/model-with-warning/model/main.smithy index 2f3d3cf475c..db03e36a710 100644 --- a/smithy-cli/src/it/resources/software/amazon/smithy/cli/projects/model-with-warning/model/main.smithy +++ b/smithy-cli/src/it/resources/software/amazon/smithy/cli/projects/model-with-warning/model/main.smithy @@ -2,6 +2,7 @@ $version: "2.0" namespace smithy.example @unstable +@trait structure exampleUnstable {} @exampleUnstable