From b81eb1e0f5e060ae4a7d0f2198fe57ff1d11ba9f Mon Sep 17 00:00:00 2001 From: trihims Date: Thu, 28 Mar 2024 09:58:47 +0530 Subject: [PATCH 1/7] getEnclosingNode of type infinite loop due to same parent --- .../compiler/util/GroovyASTUtils.java | 20 +++++++------------ 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java b/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java index 58d0403..b0ed68f 100644 --- a/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java +++ b/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java @@ -19,20 +19,10 @@ //////////////////////////////////////////////////////////////////////////////// package net.prominic.groovyls.compiler.util; -import java.util.Collections; -import java.util.Comparator; -import java.util.List; +import java.util.*; import java.util.stream.Collectors; -import org.codehaus.groovy.ast.ASTNode; -import org.codehaus.groovy.ast.ClassNode; -import org.codehaus.groovy.ast.FieldNode; -import org.codehaus.groovy.ast.ImportNode; -import org.codehaus.groovy.ast.MethodNode; -import org.codehaus.groovy.ast.ModuleNode; -import org.codehaus.groovy.ast.Parameter; -import org.codehaus.groovy.ast.PropertyNode; -import org.codehaus.groovy.ast.Variable; +import org.codehaus.groovy.ast.*; import org.codehaus.groovy.ast.expr.ArgumentListExpression; import org.codehaus.groovy.ast.expr.BinaryExpression; import org.codehaus.groovy.ast.expr.ClassExpression; @@ -59,7 +49,11 @@ public static ASTNode getEnclosingNodeOfType(ASTNode offsetNode, Class Date: Thu, 28 Mar 2024 10:00:19 +0530 Subject: [PATCH 2/7] getReferences Nodes other than classes cannot be compared with equals. --- .../compiler/util/GroovyASTUtils.java | 81 ++++++++++++++++++- 1 file changed, 77 insertions(+), 4 deletions(-) diff --git a/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java b/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java index b0ed68f..bc0ccfd 100644 --- a/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java +++ b/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java @@ -132,10 +132,25 @@ public static List getReferences(ASTNode node, ASTNodeVisitor ast) { if (definitionNode == null) { return Collections.emptyList(); } - return ast.getNodes().stream().filter(otherNode -> { - ASTNode otherDefinition = getDefinition(otherNode, false, ast); - return definitionNode.equals(otherDefinition) && node.getLineNumber() != -1 && node.getColumnNumber() != -1; - }).collect(Collectors.toList()); + + if(node.getLineNumber() == -1 || node.getColumnNumber() == -1){ + return new ArrayList<>(); + } + + ArrayList outNodes = new ArrayList<>(); + for (ASTNode otherNode : ast.getNodes()){ + if(otherNode.getLineNumber()!=-1 && otherNode.getColumnNumber() != -1){ + ASTNode otherDefinition = getDefinition(otherNode,false,ast); + if(otherDefinition!=null && isAnnotatedNodeEqual(definitionNode,otherDefinition,ast)){ + outNodes.add(otherNode); + } + } + } + return outNodes; +// return ast.getNodes().stream().filter(otherNode -> { +// ASTNode otherDefinition = getDefinition(otherNode, false, ast); +// return definitionNode.equals(otherDefinition) && node.getLineNumber() != -1 && node.getColumnNumber() != -1; +// }).collect(Collectors.toList()); } private static ClassNode tryToResolveOriginalClassNode(ClassNode node, boolean strict, ASTNodeVisitor ast) { @@ -367,4 +382,62 @@ public static Range findAddImportRange(ASTNode offsetNode, ASTNodeVisitor astVis Position position = new Position(nodeRange.getEnd().getLine() + 1, 0); return new Range(position, position); } + + static boolean isAnnotatedNodeEqual(ASTNode declaringNode, ASTNode otherNode,ASTNodeVisitor ast){ + if(Objects.equals(declaringNode,otherNode)){ + return true; + }else if (declaringNode instanceof MethodNode) { + if(otherNode instanceof MethodNode){ + MethodNode dn = (MethodNode) declaringNode; + MethodNode on = (MethodNode) otherNode; + return on.getName().equals(dn.getName()) && on.getDeclaringClass().equals(dn.getDeclaringClass()) + && on.getLineNumber() == dn.getLineNumber() && on.getColumnNumber() == dn.getColumnNumber() + && on.getLastLineNumber() == dn.getLastLineNumber() && on.getLastColumnNumber() == dn.getLastColumnNumber(); + + } + } + + return false; + +// else if (node instanceof ConstructorCallExpression) { +// ConstructorCallExpression callExpression = (ConstructorCallExpression) node; +// return GroovyASTUtils.getMethodFromCallExpression(callExpression, astVisitor); +// } else if (node instanceof DeclarationExpression) { +// DeclarationExpression declExpression = (DeclarationExpression) node; +// if (!declExpression.isMultipleAssignmentDeclaration()) { +// ClassNode originType = declExpression.getVariableExpression().getOriginType(); +// return tryToResolveOriginalClassNode(originType, strict, astVisitor); +// } +// } else if (node instanceof ClassExpression) { +// ClassExpression classExpression = (ClassExpression) node; +// return tryToResolveOriginalClassNode(classExpression.getType(), strict, astVisitor); +// } else if (node instanceof ImportNode) { +// ImportNode importNode = (ImportNode) node; +// return tryToResolveOriginalClassNode(importNode.getType(), strict, astVisitor); +// } else if (node instanceof MethodNode) { +// return node; +// } else if (node instanceof ConstantExpression && parentNode != null) { +// if (parentNode instanceof MethodCallExpression) { +// MethodCallExpression methodCallExpression = (MethodCallExpression) parentNode; +// return GroovyASTUtils.getMethodFromCallExpression(methodCallExpression, astVisitor); +// } else if (parentNode instanceof PropertyExpression) { +// PropertyExpression propertyExpression = (PropertyExpression) parentNode; +// PropertyNode propNode = GroovyASTUtils.getPropertyFromExpression(propertyExpression, astVisitor); +// if (propNode != null) { +// return propNode; +// } +// return GroovyASTUtils.getFieldFromExpression(propertyExpression, astVisitor); +// } +// } else if (node instanceof VariableExpression) { +// VariableExpression variableExpression = (VariableExpression) node; +// Variable accessedVariable = variableExpression.getAccessedVariable(); +// if (accessedVariable instanceof ASTNode) { +// return (ASTNode) accessedVariable; +// } +// // DynamicVariable is not an ASTNode, so skip it +// return null; +// } else if (node instanceof Variable) { +// return node; +// } + } } \ No newline at end of file From 9b0970486e7195944cb2d84626bd7777f2faf2ec Mon Sep 17 00:00:00 2001 From: trihims Date: Thu, 28 Mar 2024 10:00:56 +0530 Subject: [PATCH 3/7] Added extra test for finding definitions in adjacent class --- .../GroovyServicesTypeDefinitionTests.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/test/java/net/prominic/groovyls/GroovyServicesTypeDefinitionTests.java b/src/test/java/net/prominic/groovyls/GroovyServicesTypeDefinitionTests.java index 5611c52..6f80564 100644 --- a/src/test/java/net/prominic/groovyls/GroovyServicesTypeDefinitionTests.java +++ b/src/test/java/net/prominic/groovyls/GroovyServicesTypeDefinitionTests.java @@ -255,6 +255,34 @@ void testMemberMethodTypeDefinitionFromDeclaration() throws Exception { Assertions.assertEquals(3, location.getRange().getEnd().getLine()); Assertions.assertEquals(1, location.getRange().getEnd().getCharacter()); } + @Test + void testMemberAdjacentMethodTypeDefinitionFromDeclaration() throws Exception { + Path filePath = srcRoot.resolve("Definitions.groovy"); + String uri = filePath.toUri().toString(); + StringBuilder contents = new StringBuilder(); + contents.append("class TypeDefinitions {\n"); + contents.append(" public TypeDefinitions memberMethod() {\n"); + contents.append(" }\n"); + contents.append("}\n"); + contents.append("\n"); + contents.append("class Util {\n"); + contents.append(" TypeDefinitions getTypeDef(){\n"); + contents.append(" }\n"); + contents.append("}\n"); + TextDocumentItem textDocumentItem = new TextDocumentItem(uri, LANGUAGE_GROOVY, 1, contents.toString()); + services.didOpen(new DidOpenTextDocumentParams(textDocumentItem)); + TextDocumentIdentifier textDocument = new TextDocumentIdentifier(uri); + Position position = new Position(6, 12); + List locations = services.typeDefinition(new TypeDefinitionParams(textDocument, position)) + .get().getLeft(); + Assertions.assertEquals(1, locations.size()); + Location location = locations.get(0); + Assertions.assertEquals(uri, location.getUri()); + Assertions.assertEquals(0, location.getRange().getStart().getLine()); + Assertions.assertEquals(0, location.getRange().getStart().getCharacter()); + Assertions.assertEquals(3, location.getRange().getEnd().getLine()); + Assertions.assertEquals(1, location.getRange().getEnd().getCharacter()); + } @Test void testMemberMethodTypeDefinitionFromCall() throws Exception { From f5cbd05957e54657f20b862655a8a2c1133800d6 Mon Sep 17 00:00:00 2001 From: trihims Date: Thu, 28 Mar 2024 10:01:29 +0530 Subject: [PATCH 4/7] URI might be null in provideReferences --- .../net/prominic/groovyls/providers/ReferenceProvider.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/main/java/net/prominic/groovyls/providers/ReferenceProvider.java b/src/main/java/net/prominic/groovyls/providers/ReferenceProvider.java index 8bafb8b..a96c5a5 100644 --- a/src/main/java/net/prominic/groovyls/providers/ReferenceProvider.java +++ b/src/main/java/net/prominic/groovyls/providers/ReferenceProvider.java @@ -57,6 +57,9 @@ public CompletableFuture> provideReferences(TextDocumen List references = GroovyASTUtils.getReferences(offsetNode, ast); List locations = references.stream().map(node -> { URI uri = ast.getURI(node); + if(uri == null){ + return null; + } return GroovyLanguageServerUtils.astNodeToLocation(node, uri); }).filter(location -> location != null).collect(Collectors.toList()); From b3bf975506530e38b2ff929f0cc7aa82c215152b Mon Sep 17 00:00:00 2001 From: trihims Date: Thu, 28 Mar 2024 22:20:29 +0530 Subject: [PATCH 5/7] getReferences of Fields --- .../compiler/util/GroovyASTUtils.java | 47 ++++++++++++++++++- .../groovyls/providers/ReferenceProvider.java | 2 +- .../groovyls/providers/RenameProvider.java | 2 +- 3 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java b/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java index bc0ccfd..c46eb78 100644 --- a/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java +++ b/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java @@ -22,6 +22,7 @@ import java.util.*; import java.util.stream.Collectors; +import net.prominic.lsp.utils.Ranges; import org.codehaus.groovy.ast.*; import org.codehaus.groovy.ast.expr.ArgumentListExpression; import org.codehaus.groovy.ast.expr.BinaryExpression; @@ -127,7 +128,7 @@ public static ASTNode getTypeDefinition(ASTNode node, ASTNodeVisitor astVisitor) return null; } - public static List getReferences(ASTNode node, ASTNodeVisitor ast) { + public static List getReferences(ASTNode node, ASTNodeVisitor ast, Position currentPosition) { ASTNode definitionNode = getDefinition(node, true, ast); if (definitionNode == null) { return Collections.emptyList(); @@ -137,6 +138,22 @@ public static List getReferences(ASTNode node, ASTNodeVisitor ast) { return new ArrayList<>(); } + + if((definitionNode instanceof Variable) && currentPosition !=null){ + ClassNode variableType = tryToResolveOriginalClassNode(((Variable) definitionNode).getOriginType(),true,ast); + FieldNode variableField = ((PropertyNode) definitionNode).getField(); //Get field from property + + Range typeRange = variableType==null?null:GroovyLanguageServerUtils.astNodeToRange(variableType); + Range fieldRange = variableField==null?null:GroovyLanguageServerUtils.astNodeToRange(variableField); + + // Give preference to variable where possible + if(fieldRange !=null && Ranges.contains(fieldRange,currentPosition)){ + definitionNode = variableField; + }else if(typeRange!=null && Ranges.contains(typeRange,currentPosition)){ + definitionNode = variableField; + } + } + ArrayList outNodes = new ArrayList<>(); for (ASTNode otherNode : ast.getNodes()){ if(otherNode.getLineNumber()!=-1 && otherNode.getColumnNumber() != -1){ @@ -395,6 +412,34 @@ static boolean isAnnotatedNodeEqual(ASTNode declaringNode, ASTNode otherNode,AST && on.getLastLineNumber() == dn.getLastLineNumber() && on.getLastColumnNumber() == dn.getLastColumnNumber(); } + } else if (declaringNode instanceof FieldNode) { + if (otherNode instanceof FieldNode){ + FieldNode dn = (FieldNode) declaringNode; + FieldNode on = (FieldNode) otherNode; + return on.getName().equals(dn.getName()) && on.getOriginType().equals(dn.getOriginType()) + && on.getOwner().equals(dn.getOwner()) + && on.getLineNumber() == dn.getLineNumber() && on.getColumnNumber() == dn.getColumnNumber() + && on.getLastLineNumber() == dn.getLastLineNumber() && on.getLastColumnNumber() == dn.getLastColumnNumber(); + } else if (otherNode instanceof PropertyNode) { + FieldNode dn = (FieldNode) declaringNode; + FieldNode on = ((PropertyNode) otherNode).getField(); + if(on!=null) { + return on.getName().equals(dn.getName()) && on.getOriginType().equals(dn.getOriginType()) + && on.getOwner().equals(dn.getOwner()) + && on.getLineNumber() == dn.getLineNumber() && on.getColumnNumber() == dn.getColumnNumber() + && on.getLastLineNumber() == dn.getLastLineNumber() && on.getLastColumnNumber() == dn.getLastColumnNumber(); + } + } + else if(otherNode instanceof PropertyExpression){ + FieldNode dn = (FieldNode) declaringNode; + FieldNode on = GroovyASTUtils.getFieldFromExpression((PropertyExpression) otherNode,ast); + if(on!=null) { + return on.getName().equals(dn.getName()) && on.getOriginType().equals(dn.getOriginType()) + && on.getOwner().equals(dn.getOwner()) + && on.getLineNumber() == dn.getLineNumber() && on.getColumnNumber() == dn.getColumnNumber() + && on.getLastLineNumber() == dn.getLastLineNumber() && on.getLastColumnNumber() == dn.getLastColumnNumber(); + } + } } return false; diff --git a/src/main/java/net/prominic/groovyls/providers/ReferenceProvider.java b/src/main/java/net/prominic/groovyls/providers/ReferenceProvider.java index a96c5a5..2e5340b 100644 --- a/src/main/java/net/prominic/groovyls/providers/ReferenceProvider.java +++ b/src/main/java/net/prominic/groovyls/providers/ReferenceProvider.java @@ -54,7 +54,7 @@ public CompletableFuture> provideReferences(TextDocumen return CompletableFuture.completedFuture(Collections.emptyList()); } - List references = GroovyASTUtils.getReferences(offsetNode, ast); + List references = GroovyASTUtils.getReferences(offsetNode, ast, position); List locations = references.stream().map(node -> { URI uri = ast.getURI(node); if(uri == null){ diff --git a/src/main/java/net/prominic/groovyls/providers/RenameProvider.java b/src/main/java/net/prominic/groovyls/providers/RenameProvider.java index cce9d9e..e2e3f19 100644 --- a/src/main/java/net/prominic/groovyls/providers/RenameProvider.java +++ b/src/main/java/net/prominic/groovyls/providers/RenameProvider.java @@ -81,7 +81,7 @@ public CompletableFuture provideRename(RenameParams renameParams) return CompletableFuture.completedFuture(workspaceEdit); } - List references = GroovyASTUtils.getReferences(offsetNode, ast); + List references = GroovyASTUtils.getReferences(offsetNode, ast, position); references.forEach(node -> { URI uri = ast.getURI(node); if (uri == null) { From 2e44aa599aeca071aeaa563ccf4522459e114459 Mon Sep 17 00:00:00 2001 From: trihims Date: Sat, 30 Mar 2024 19:03:52 +0530 Subject: [PATCH 6/7] Add reference unit tests --- .../GroovyServicesReferenceTests.java | 238 ++++++++++++++++++ 1 file changed, 238 insertions(+) create mode 100644 src/test/java/net/prominic/groovyls/GroovyServicesReferenceTests.java diff --git a/src/test/java/net/prominic/groovyls/GroovyServicesReferenceTests.java b/src/test/java/net/prominic/groovyls/GroovyServicesReferenceTests.java new file mode 100644 index 0000000..fdee6aa --- /dev/null +++ b/src/test/java/net/prominic/groovyls/GroovyServicesReferenceTests.java @@ -0,0 +1,238 @@ +package net.prominic.groovyls; + +import net.prominic.groovyls.config.CompilationUnitFactory; +import org.eclipse.lsp4j.*; +import org.eclipse.lsp4j.services.LanguageClient; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.List; +import java.util.Optional; +import java.util.concurrent.CompletableFuture; +import java.util.stream.Collectors; + +public class GroovyServicesReferenceTests { + private static final String LANGUAGE_GROOVY = "groovy"; + private static final String PATH_WORKSPACE = "./build/test_workspace/"; + private static final String PATH_SRC = "./src/main/groovy"; + + private GroovyServices services; + private Path workspaceRoot; + private Path srcRoot; + + @BeforeEach + void setup() { + workspaceRoot = Paths.get(System.getProperty("user.dir")).resolve(PATH_WORKSPACE); + srcRoot = workspaceRoot.resolve(PATH_SRC); + if (!Files.exists(srcRoot)) { + srcRoot.toFile().mkdirs(); + } + + services = new GroovyServices(new CompilationUnitFactory()); + services.setWorkspaceRoot(workspaceRoot); + services.connect(new LanguageClient() { + + @Override + public void telemetryEvent(Object object) { + + } + + @Override + public CompletableFuture showMessageRequest(ShowMessageRequestParams requestParams) { + return null; + } + + @Override + public void showMessage(MessageParams messageParams) { + + } + + @Override + public void publishDiagnostics(PublishDiagnosticsParams diagnostics) { + + } + + @Override + public void logMessage(MessageParams message) { + + } + }); + } + + @AfterEach + void tearDown() { + services = null; + workspaceRoot = null; + srcRoot = null; + } + + + @Test + void getUsagesOfMethodFromClass() throws Exception{ + List textDocumentItem = getTextDocumentForUsage(srcRoot); + services.didOpen(new DidOpenTextDocumentParams(textDocumentItem.get(0))); + services.didOpen(new DidOpenTextDocumentParams(textDocumentItem.get(1))); + TextDocumentIdentifier textDocument = new TextDocumentIdentifier(textDocumentItem.get(0).getUri()); + Position position = new Position(1, 15); + List locations = services.references(new ReferenceParams(textDocument, position,new ReferenceContext(true))).get(); + Assertions.assertEquals(3, locations.size()); + List locationList = locations.stream().filter(r->r.getUri().equals(textDocumentItem.get(1).getUri())).collect(Collectors.toList()); + Location location = locationList.get(0); + Assertions.assertEquals(textDocumentItem.get(1).getUri(), location.getUri()); + Assertions.assertEquals(7, location.getRange().getStart().getLine()); + Assertions.assertEquals(59, location.getRange().getStart().getCharacter()); + Assertions.assertEquals(7, location.getRange().getEnd().getLine()); + Assertions.assertEquals(76, location.getRange().getEnd().getCharacter()); + Location location2 = locationList.get(1); + Assertions.assertEquals(textDocumentItem.get(1).getUri(), location2.getUri()); + Assertions.assertEquals(11, location2.getRange().getStart().getLine()); + Assertions.assertEquals(21, location2.getRange().getStart().getCharacter()); + Assertions.assertEquals(11, location2.getRange().getEnd().getLine()); + Assertions.assertEquals(38, location2.getRange().getEnd().getCharacter()); + } + + private static List getTextDocumentForUsage(Path srcRoot) { + + Path filePath = srcRoot.resolve("MyClass.groovy"); + String uri = filePath.toUri().toString(); + StringBuilder contents = new StringBuilder(); + + contents.append("class MyClass{\n"); + contents.append(" String getMyClassVersion(){\n"); + contents.append(" return \"1.0.0\";\n"); + contents.append(" }\n"); + contents.append("}\n"); + + TextDocumentItem textDocumentMyClass = new TextDocumentItem(uri, LANGUAGE_GROOVY, 1, contents.toString()); + + Path userfilePath = srcRoot.resolve("User.groovy"); + String userfileuri = userfilePath.toUri().toString(); + StringBuilder userFileContents = new StringBuilder(); + + userFileContents.append("class User{\n"); + userFileContents.append(" MyClass myclass;\n"); + userFileContents.append("\n"); + userFileContents.append(" User(MyClass ref){\n"); + userFileContents.append(" myclass = ref;\n"); + userFileContents.append(" }\n"); + userFileContents.append(" void doStuff(){\n"); + userFileContents.append(" String out = \"The version of my class is \" + myclass.getMyClassVersion();\n"); + userFileContents.append(" }\n"); + userFileContents.append("\n"); + userFileContents.append(" String getLocalClassVersion() {\n"); + userFileContents.append(" return myclass.getMyClassVersion();\n"); + userFileContents.append(" }\n"); + userFileContents.append("}\n"); + + TextDocumentItem textDocumentUser = new TextDocumentItem(userfileuri, LANGUAGE_GROOVY, 1, userFileContents.toString()); + + return Arrays.asList(textDocumentMyClass,textDocumentUser); + } + + + @Test + void getUsagesOfMethodFromClassObjectDeclaration() throws Exception{ + List textDocumentItems = getTextDocumentForUsageObjectDeclaration(srcRoot); + + services.didOpen(new DidOpenTextDocumentParams(textDocumentItems.get(0))); + services.didOpen(new DidOpenTextDocumentParams(textDocumentItems.get(1))); + TextDocumentIdentifier textDocument = new TextDocumentIdentifier(textDocumentItems.get(0).getUri()); + Position position = new Position(1, 15); + List locations = services.references(new ReferenceParams(textDocument, position,new ReferenceContext(true))).get(); + Assertions.assertEquals(2, locations.size()); + Optional location = locations.stream().filter(it-> it.getUri().equals(textDocumentItems.get(1).getUri())).findFirst(); + Assertions.assertTrue(location.isPresent()); + Assertions.assertEquals(textDocumentItems.get(1).getUri(), location.get().getUri()); + Assertions.assertEquals(3, location.get().getRange().getStart().getLine()); + Assertions.assertEquals(9, location.get().getRange().getStart().getCharacter()); + Assertions.assertEquals(3, location.get().getRange().getEnd().getLine()); + Assertions.assertEquals(26, location.get().getRange().getEnd().getCharacter()); + } + private static List getTextDocumentForUsageObjectDeclaration(Path srcRoot){ + Path filePath = srcRoot.resolve("MyClass.groovy"); + String uri = filePath.toUri().toString(); + StringBuilder contents = new StringBuilder(); + + contents.append("class MyClass{\n"); + contents.append(" String getMyClassVersion(){\n"); + contents.append(" return \"1.0.0\";\n"); + contents.append(" }\n"); + contents.append("}\n"); + TextDocumentItem textDocumentMyClass = new TextDocumentItem(uri, LANGUAGE_GROOVY, 1, contents.toString()); + + Path userfilePath = srcRoot.resolve("User.groovy"); + String userfileuri = userfilePath.toUri().toString(); + StringBuilder userFileContents = new StringBuilder(); + + userFileContents.append("class User{\n"); + userFileContents.append(" void doStuff(){\n"); + userFileContents.append(" MyClass mc = new MyClass();\n"); + userFileContents.append(" mc.getMyClassVersion();\n"); + userFileContents.append(" }\n"); + userFileContents.append("}\n"); + TextDocumentItem textDocumentUser = new TextDocumentItem(userfileuri, LANGUAGE_GROOVY, 1, userFileContents.toString()); + + return Arrays.asList(textDocumentMyClass,textDocumentUser); + + } + + + @Test + void getUsagesOfVariableFromClassDeclaration() throws Exception{ + List textDocumentItems = getTextDocumentForUsageVariable(srcRoot); + + services.didOpen(new DidOpenTextDocumentParams(textDocumentItems.get(0))); + services.didOpen(new DidOpenTextDocumentParams(textDocumentItems.get(1))); + TextDocumentIdentifier textDocument = new TextDocumentIdentifier(textDocumentItems.get(0).getUri()); + Position position = new Position(1, 13); + List locations = services.references(new ReferenceParams(textDocument, position,new ReferenceContext(true))).get(); + Assertions.assertEquals(3, locations.size()); + List locationFiltered = locations.stream().filter(it->it.getUri().equals(textDocumentItems.get(1).getUri())).collect(Collectors.toList()); + + Assertions.assertEquals(locationFiltered.size(),2); + Location location1 = locationFiltered.get(0); + Assertions.assertEquals(3, location1.getRange().getStart().getLine()); + Assertions.assertEquals(26, location1.getRange().getStart().getCharacter()); + Assertions.assertEquals(3, location1.getRange().getEnd().getLine()); + Assertions.assertEquals(33, location1.getRange().getEnd().getCharacter()); + + Location location2 = locationFiltered.get(1); + Assertions.assertEquals(4, location2.getRange().getStart().getLine()); + Assertions.assertEquals(48, location2.getRange().getStart().getCharacter()); + Assertions.assertEquals(4, location2.getRange().getEnd().getLine()); + Assertions.assertEquals(55, location2.getRange().getEnd().getCharacter()); + } + private static List getTextDocumentForUsageVariable(Path srcRoot){ + Path filePath = srcRoot.resolve("MyClass.groovy"); + String uri = filePath.toUri().toString(); + StringBuilder contents = new StringBuilder(); + contents.append("class MyClass{\n"); + contents.append(" String version = \"1.0\";\n"); + contents.append("}\n"); + contents.append("\n"); + contents.append("\n"); + TextDocumentItem textDocumentMyClass = new TextDocumentItem(uri, LANGUAGE_GROOVY, 1, contents.toString()); + + Path userfilePath = srcRoot.resolve("User.groovy"); + String userfileuri = userfilePath.toUri().toString(); + StringBuilder userFileContents = new StringBuilder(); + + userFileContents.append("class User{\n"); + userFileContents.append(" void doStuff(){\n"); + userFileContents.append(" MyClass mc = new MyClass();\n"); + userFileContents.append(" String version = mc.version;\n"); + userFileContents.append(" return \"The version of my class is \" + mc.version;\n"); + userFileContents.append(" }\n"); + userFileContents.append("}\n"); + TextDocumentItem textDocumentUser = new TextDocumentItem(userfileuri, LANGUAGE_GROOVY, 1, userFileContents.toString()); + + return Arrays.asList(textDocumentMyClass,textDocumentUser); + + } +} From 1c8d2f92b9b0a84d5b9749ff0b0da93228e81873 Mon Sep 17 00:00:00 2001 From: trihims Date: Sat, 30 Mar 2024 19:13:15 +0530 Subject: [PATCH 7/7] Cleanup some dead code. --- .../compiler/util/GroovyASTUtils.java | 45 ------------------- 1 file changed, 45 deletions(-) diff --git a/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java b/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java index c46eb78..d0640f2 100644 --- a/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java +++ b/src/main/java/net/prominic/groovyls/compiler/util/GroovyASTUtils.java @@ -164,10 +164,6 @@ public static List getReferences(ASTNode node, ASTNodeVisitor ast, Posi } } return outNodes; -// return ast.getNodes().stream().filter(otherNode -> { -// ASTNode otherDefinition = getDefinition(otherNode, false, ast); -// return definitionNode.equals(otherDefinition) && node.getLineNumber() != -1 && node.getColumnNumber() != -1; -// }).collect(Collectors.toList()); } private static ClassNode tryToResolveOriginalClassNode(ClassNode node, boolean strict, ASTNodeVisitor ast) { @@ -443,46 +439,5 @@ else if(otherNode instanceof PropertyExpression){ } return false; - -// else if (node instanceof ConstructorCallExpression) { -// ConstructorCallExpression callExpression = (ConstructorCallExpression) node; -// return GroovyASTUtils.getMethodFromCallExpression(callExpression, astVisitor); -// } else if (node instanceof DeclarationExpression) { -// DeclarationExpression declExpression = (DeclarationExpression) node; -// if (!declExpression.isMultipleAssignmentDeclaration()) { -// ClassNode originType = declExpression.getVariableExpression().getOriginType(); -// return tryToResolveOriginalClassNode(originType, strict, astVisitor); -// } -// } else if (node instanceof ClassExpression) { -// ClassExpression classExpression = (ClassExpression) node; -// return tryToResolveOriginalClassNode(classExpression.getType(), strict, astVisitor); -// } else if (node instanceof ImportNode) { -// ImportNode importNode = (ImportNode) node; -// return tryToResolveOriginalClassNode(importNode.getType(), strict, astVisitor); -// } else if (node instanceof MethodNode) { -// return node; -// } else if (node instanceof ConstantExpression && parentNode != null) { -// if (parentNode instanceof MethodCallExpression) { -// MethodCallExpression methodCallExpression = (MethodCallExpression) parentNode; -// return GroovyASTUtils.getMethodFromCallExpression(methodCallExpression, astVisitor); -// } else if (parentNode instanceof PropertyExpression) { -// PropertyExpression propertyExpression = (PropertyExpression) parentNode; -// PropertyNode propNode = GroovyASTUtils.getPropertyFromExpression(propertyExpression, astVisitor); -// if (propNode != null) { -// return propNode; -// } -// return GroovyASTUtils.getFieldFromExpression(propertyExpression, astVisitor); -// } -// } else if (node instanceof VariableExpression) { -// VariableExpression variableExpression = (VariableExpression) node; -// Variable accessedVariable = variableExpression.getAccessedVariable(); -// if (accessedVariable instanceof ASTNode) { -// return (ASTNode) accessedVariable; -// } -// // DynamicVariable is not an ASTNode, so skip it -// return null; -// } else if (node instanceof Variable) { -// return node; -// } } } \ No newline at end of file