From 7d59a0451692c24b6b75bc8e142a9d296606ecaf Mon Sep 17 00:00:00 2001 From: Miles Ziemer Date: Thu, 13 Feb 2025 18:33:54 -0500 Subject: [PATCH] Fix parse errors for empty build files Document::rangeBetween would return `null` if the document was empty, but I wasn't checking for that in ToSmithyNode (which creates parse events). The reason the range is `null` is because Document.lineOfIndex returns oob for an index of 0 into an empty document. Makes sense, as an empty document has no lines. I updated a DocumentTest to clarify this behavior. --- .../amazon/smithy/lsp/project/ToSmithyNode.java | 7 ++++++- .../smithy/lsp/document/DocumentTest.java | 1 + .../smithy/lsp/project/ProjectConfigTest.java | 17 +++++++++++++++++ 3 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/main/java/software/amazon/smithy/lsp/project/ToSmithyNode.java b/src/main/java/software/amazon/smithy/lsp/project/ToSmithyNode.java index 5460003..865a959 100644 --- a/src/main/java/software/amazon/smithy/lsp/project/ToSmithyNode.java +++ b/src/main/java/software/amazon/smithy/lsp/project/ToSmithyNode.java @@ -6,6 +6,7 @@ package software.amazon.smithy.lsp.project; import java.util.List; +import org.eclipse.lsp4j.Range; import software.amazon.smithy.lsp.document.Document; import software.amazon.smithy.lsp.protocol.LspAdapter; import software.amazon.smithy.lsp.syntax.Syntax; @@ -104,6 +105,10 @@ yield switch (value) { } private SourceLocation nodeStartSourceLocation(Syntax.Node node) { - return LspAdapter.toSourceLocation(path, document.rangeBetween(node.start(), node.end())); + Range range = document.rangeBetween(node.start(), node.end()); + if (range == null) { + range = LspAdapter.origin(); + } + return LspAdapter.toSourceLocation(path, range); } } diff --git a/src/test/java/software/amazon/smithy/lsp/document/DocumentTest.java b/src/test/java/software/amazon/smithy/lsp/document/DocumentTest.java index 3a9975b..32e9e0e 100644 --- a/src/test/java/software/amazon/smithy/lsp/document/DocumentTest.java +++ b/src/test/java/software/amazon/smithy/lsp/document/DocumentTest.java @@ -293,6 +293,7 @@ public void getsLineOfIndex() { Document leadingAndTrailingWs = makeDocument("\nabc\n"); Document threeLine = makeDocument("abc\ndef\nhij\n"); + assertThat(empty.lineOfIndex(0), is(-1)); // empty has no lines, so oob assertThat(empty.lineOfIndex(1), is(-1)); // oob assertThat(single.lineOfIndex(0), is(0)); // start assertThat(single.lineOfIndex(2), is(0)); // end diff --git a/src/test/java/software/amazon/smithy/lsp/project/ProjectConfigTest.java b/src/test/java/software/amazon/smithy/lsp/project/ProjectConfigTest.java index 2383bd5..2ff2694 100644 --- a/src/test/java/software/amazon/smithy/lsp/project/ProjectConfigTest.java +++ b/src/test/java/software/amazon/smithy/lsp/project/ProjectConfigTest.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.function.Supplier; import java.util.stream.Collectors; +import org.eclipse.lsp4j.Position; import org.junit.jupiter.api.Test; import software.amazon.smithy.build.model.MavenRepository; import software.amazon.smithy.cli.dependencies.DependencyResolver; @@ -32,6 +33,7 @@ import software.amazon.smithy.lsp.ServerState; import software.amazon.smithy.lsp.TextWithPositions; import software.amazon.smithy.lsp.document.Document; +import software.amazon.smithy.lsp.protocol.LspAdapter; public class ProjectConfigTest { @Test @@ -78,6 +80,21 @@ public void mergesBuildExts() { assertThat(config.maven().getDependencies(), containsInAnyOrder("foo")); } + @Test + public void handlesEmptyFiles() { + var root = Path.of("foo"); + var buildFiles = createBuildFiles(root, BuildFileType.SMITHY_BUILD, ""); + var result = load(root, buildFiles); + + var smithyBuild = buildFiles.getByType(BuildFileType.SMITHY_BUILD); + assertThat(smithyBuild, notNullValue()); + assertThat(result.events(), containsInAnyOrder(allOf( + eventWithId(equalTo("Model")), + eventWithMessage(containsString("Error parsing JSON")), + eventWithSourceLocation(equalTo(LspAdapter.toSourceLocation(smithyBuild.path(), new Position(0, 0)))) + ))); + } + @Test public void validatesSmithyBuildJson() { var text = TextWithPositions.from("""