From 898dc095441f1c9737e1ca2444d6b3d7891895e5 Mon Sep 17 00:00:00 2001 From: Chase Coalwell <782571+srchase@users.noreply.github.com> Date: Tue, 22 Aug 2023 09:17:14 -0600 Subject: [PATCH] Fix NPE on trait with implicit null --- .../amazon/smithy/syntax/Formatter.java | 43 +++++++++++-------- .../null-trait-body.formatted.smithy | 8 ++++ .../syntax/formatter/null-trait-body.smithy | 8 ++++ 3 files changed, 42 insertions(+), 17 deletions(-) create mode 100644 smithy-syntax/src/test/resources/software/amazon/smithy/syntax/formatter/null-trait-body.formatted.smithy create mode 100644 smithy-syntax/src/test/resources/software/amazon/smithy/syntax/formatter/null-trait-body.smithy diff --git a/smithy-syntax/src/main/java/software/amazon/smithy/syntax/Formatter.java b/smithy-syntax/src/main/java/software/amazon/smithy/syntax/Formatter.java index 67b93af3188..0d1b6838ced 100644 --- a/smithy-syntax/src/main/java/software/amazon/smithy/syntax/Formatter.java +++ b/smithy-syntax/src/main/java/software/amazon/smithy/syntax/Formatter.java @@ -365,23 +365,32 @@ private Doc visit(TreeCursor cursor) { }) .build(); } else { - // Check the inner trait node for hard line breaks rather than the wrapper. - TreeCursor traitNode = cursor - .getFirstChild(TreeType.TRAIT_NODE) - .getFirstChild(TreeType.NODE_VALUE) - .getFirstChild(); // The actual node value. - return new BracketBuilder() - .open(Doc.text("(")) - .close(Doc.text(")")) - .extractChildren(cursor, traitNode, child -> { - if (child.getTree().getType() == TreeType.TRAIT_NODE) { - // Split WS and NODE_VALUE so that they appear on different lines. - return child.getChildrenByType(TreeType.NODE_VALUE, TreeType.WS).stream(); - } else { - return Stream.empty(); - } - }) - .build(); + if (cursor.getFirstChild(TreeType.TRAIT_NODE) != null) { + // Check the inner trait node for hard line breaks rather than the wrapper. + TreeCursor traitNode = cursor + .getFirstChild(TreeType.TRAIT_NODE) + .getFirstChild(TreeType.NODE_VALUE) + .getFirstChild(); // The actual node value. + return new BracketBuilder() + .open(Doc.text("(")) + .close(Doc.text(")")) + .extractChildren(cursor, traitNode, child -> { + if (child.getTree().getType() == TreeType.TRAIT_NODE) { + // Split WS and NODE_VALUE so that they appear on different lines. + return child.getChildrenByType(TreeType.NODE_VALUE, TreeType.WS).stream(); + } else { + return Stream.empty(); + } + }) + .build(); + } else { + // If the trait node is empty, explicitly set it to `null`. + return new BracketBuilder() + .open(Doc.text("(")) + .close(Doc.text(")")) + .children(Stream.builder().add(Doc.text("null")).build()) + .build(); + } } } diff --git a/smithy-syntax/src/test/resources/software/amazon/smithy/syntax/formatter/null-trait-body.formatted.smithy b/smithy-syntax/src/test/resources/software/amazon/smithy/syntax/formatter/null-trait-body.formatted.smithy new file mode 100644 index 00000000000..53cffa42924 --- /dev/null +++ b/smithy-syntax/src/test/resources/software/amazon/smithy/syntax/formatter/null-trait-body.formatted.smithy @@ -0,0 +1,8 @@ +$version: "2.0" + +namespace smithy.example + +structure Struct { + @default(null) + a: String +} diff --git a/smithy-syntax/src/test/resources/software/amazon/smithy/syntax/formatter/null-trait-body.smithy b/smithy-syntax/src/test/resources/software/amazon/smithy/syntax/formatter/null-trait-body.smithy new file mode 100644 index 00000000000..ddb3db0ba0d --- /dev/null +++ b/smithy-syntax/src/test/resources/software/amazon/smithy/syntax/formatter/null-trait-body.smithy @@ -0,0 +1,8 @@ +$version: "2.0" + +namespace smithy.example + +structure Struct { + @default() + a: String +}