Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ $version: "2.0"
namespace smithy.example

@unstable
@trait
structure exampleUnstable {}

@exampleUnstable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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<LoadOperation> {

Expand Down Expand Up @@ -125,9 +129,11 @@ Model buildModel() {
Model.Builder modelBuilder = Model.builder();
modelBuilder.metadata(metadata.getData());
resolveForwardReferences();
traitMap.applyTraitsToNonMixinsInShapeMap(shapeMap);
List<ShapeId> undefinedTraits = new ArrayList<>();
traitMap.applyTraitsToNonMixinsInShapeMap(shapeMap, undefinedTraits);
shapeMap.buildShapesAndClaimMixinTraits(modelBuilder, traitMap::claimTraitsForShape);
traitMap.emitUnclaimedTraits();
validateTraitWithTraitDefinition(undefinedTraits, modelBuilder);
if (prelude != null) {
modelBuilder.addShapes(prelude);
}
Expand All @@ -138,6 +144,28 @@ List<ValidationEvent> events() {
return events;
}

private void validateTraitWithTraitDefinition(List<ShapeId> undefiedTraits, Model.Builder modelBuilder) {
Map<ShapeId, Shape> 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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -46,7 +47,7 @@ final class LoaderTraitMap {
this.allowUnknownTraits = allowUnknownTraits;
}

void applyTraitsToNonMixinsInShapeMap(LoaderShapeMap shapeMap) {
void applyTraitsToNonMixinsInShapeMap(LoaderShapeMap shapeMap, List<ShapeId> undefinedTraits) {
for (Map.Entry<ShapeId, Map<ShapeId, Node>> entry : traits.entrySet()) {
ShapeId target = entry.getKey();
ShapeId root = target.withoutMember();
Expand All @@ -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.
Expand Down Expand Up @@ -144,6 +146,13 @@ private void validateTraitIsKnown(
}
}

private void validateTraitWithTraitDefinition(ShapeId traitId, List<ShapeId> undefinedTraits) {
Map<ShapeId, Node> 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);
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
$version: "1.0"

namespace com.foo

document MyDoc

@MyDoc(name: "aa")
structure MyStruct {}
Loading