Skip to content

Commit 290a825

Browse files
committed
Disallow traits applied to public prelude shapes
Applying a trait to a prelude shape is a recipe for disaster. For example, if someone marked the smithy.api#String shape as private, virtually every model would break.
1 parent 83514ec commit 290a825

File tree

4 files changed

+31
-2
lines changed

4 files changed

+31
-2
lines changed

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

+17-2
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ public void onTrait(ShapeId target, ShapeId trait, Node traitValue) {
282282
onTrait(target, traitDef);
283283
} else {
284284
PendingTrait pendingTrait = new PendingTrait(trait, traitValue);
285-
pendingTraits.computeIfAbsent(target, targetId -> new ArrayList<>()).add(pendingTrait);
285+
addPendingTrait(target, traitValue.getSourceLocation(), trait, pendingTrait);
286286
}
287287
}
288288

@@ -294,7 +294,22 @@ public void onTrait(ShapeId target, ShapeId trait, Node traitValue) {
294294
*/
295295
public void onTrait(ShapeId target, Trait trait) {
296296
PendingTrait pending = new PendingTrait(target, trait);
297-
pendingTraits.computeIfAbsent(target, targetId -> new ArrayList<>()).add(pending);
297+
addPendingTrait(target, trait.getSourceLocation(), trait.toShapeId(), pending);
298+
}
299+
300+
private void addPendingTrait(ShapeId target, SourceLocation sourceLocation, ShapeId trait, PendingTrait pending) {
301+
if (Prelude.isImmutablePublicPreludeShape(target)) {
302+
onError(ValidationEvent.builder()
303+
.severity(Severity.ERROR)
304+
.eventId(Validator.MODEL_ERROR)
305+
.sourceLocation(sourceLocation)
306+
.shapeId(target)
307+
.message(String.format(
308+
"Cannot apply `%s` to an immutable prelude shape defined in `smithy.api`.", trait))
309+
.build());
310+
} else {
311+
pendingTraits.computeIfAbsent(target, targetId -> new ArrayList<>()).add(pending);
312+
}
298313
}
299314

300315
/**

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

+10
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,16 @@ public static boolean isPublicPreludeShape(ToShapeId id) {
235235
return PUBLIC_PRELUDE_SHAPE_IDS.contains(toId) || PRELUDE_TRAITS.contains(toId);
236236
}
237237

238+
/**
239+
* Checks if the given shape is an immutable public shape.
240+
*
241+
* @param id Shape to check.
242+
* @return Returns true if the shape is immutable.
243+
*/
244+
static boolean isImmutablePublicPreludeShape(ToShapeId id) {
245+
return PUBLIC_PRELUDE_SHAPE_IDS.contains(id.toShapeId());
246+
}
247+
238248
// Used by the ModelAssembler to load the prelude into another visitor.
239249
static Model getPreludeModel() {
240250
return PreludeHolder.PRELUDE;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[ERROR] smithy.api#String: Cannot apply `smithy.api#deprecated` to an immutable prelude shape defined in `smithy.api`. | Model
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
namespace com.foo
2+
3+
apply smithy.api#String @deprecated

0 commit comments

Comments
 (0)