diff --git a/java/src/processing/mode/java/ASTUtils.java b/java/src/processing/mode/java/ASTUtils.java index 11d39287c..bc57f1e45 100644 --- a/java/src/processing/mode/java/ASTUtils.java +++ b/java/src/processing/mode/java/ASTUtils.java @@ -163,7 +163,9 @@ public class ASTUtils { } - protected static List findAllOccurrences(ASTNode root, String bindingKey) { + public static List findAllOccurrences(ASTNode root, + String bindingKey + ) { List occurrences = new ArrayList<>(); root.getRoot().accept(new ASTVisitor() { @Override diff --git a/java/src/processing/mode/java/SketchInterval.java b/java/src/processing/mode/java/SketchInterval.java index e0596bc29..c7f654f5f 100644 --- a/java/src/processing/mode/java/SketchInterval.java +++ b/java/src/processing/mode/java/SketchInterval.java @@ -18,6 +18,6 @@ public class SketchInterval { public final int startTabOffset; public final int stopTabOffset; - final int startPdeOffset; - final int stopPdeOffset; + public final int startPdeOffset; + public final int stopPdeOffset; } \ No newline at end of file diff --git a/java/src/processing/mode/java/lsp/PdeLanguageServer.java b/java/src/processing/mode/java/lsp/PdeLanguageServer.java index ee71754cb..3d865fcc7 100644 --- a/java/src/processing/mode/java/lsp/PdeLanguageServer.java +++ b/java/src/processing/mode/java/lsp/PdeLanguageServer.java @@ -78,6 +78,7 @@ class PdeLanguageServer implements LanguageServer, LanguageClientAware { capabilities.setCompletionProvider(completionOptions); capabilities.setDocumentFormattingProvider(true); capabilities.setDeclarationProvider(true); + capabilities.setReferencesProvider(true); var result = new InitializeResult(capabilities); return CompletableFuture.completedFuture(result); } diff --git a/java/src/processing/mode/java/lsp/PdeSymbolFinder.java b/java/src/processing/mode/java/lsp/PdeSymbolFinder.java index ac2cd5e14..e8f850bc6 100644 --- a/java/src/processing/mode/java/lsp/PdeSymbolFinder.java +++ b/java/src/processing/mode/java/lsp/PdeSymbolFinder.java @@ -18,8 +18,7 @@ import processing.app.SketchCode; import processing.mode.java.PreprocSketch; import processing.mode.java.SketchInterval; -import static processing.mode.java.ASTUtils.getSimpleNameAt; -import static processing.mode.java.ASTUtils.resolveBinding; +import static processing.mode.java.ASTUtils.*; public class PdeSymbolFinder { @@ -77,18 +76,74 @@ public class PdeSymbolFinder { System.out.println("declaration is outside of the sketch"); return Collections.emptyList(); } + + List declarationList = new ArrayList<>(); + declarationList.add(findLocation(ps, si)); + + return declarationList; + } + + + /** + * searches all reference nodes for a provided character offset + * + * @param ps processed sketch, for AST-nodes and sketch + * @param javaOffset character offset for the node we want to look up + * + * @return Location list of all references found, else an empty list. + */ + static public List searchReference(PreprocSketch ps, + int javaOffset + ) { + ASTNode root = ps.compilationUnit; - //Create a location for the found declaration + SimpleName simpleName = getSimpleNameAt(root, javaOffset, javaOffset); + if (simpleName == null) { + System.out.println("no simple name found at location"); + return Collections.emptyList(); + } + + IBinding binding = resolveBinding(simpleName); + if (binding == null) { + System.out.println("binding not resolved"); + return Collections.emptyList(); + } + + // Find usages + String bindingKey = binding.getKey(); + List referenceIntervals = + findAllOccurrences(ps.compilationUnit, bindingKey).stream() + .map(ps::mapJavaToSketch) + // remove occurrences which fall into generated header + .filter(ps::inRange) + // remove empty intervals (happens when occurence was inserted) + .filter(in -> in.startPdeOffset < in.stopPdeOffset) + .collect(java.util.stream.Collectors.toList()); + + List referenceList = new ArrayList<>(); + for (SketchInterval referenceInterval: referenceIntervals) { + referenceList.add(findLocation(ps, referenceInterval)); + } + + return referenceList; + } + + + /** + * Looks for a location(range) for a given sketchInterval + * + * @param ps processed sketch, for finding the uri and code + * @param si The interval to find the location for + * + * @return Location(range) inside a file from the workspace + */ + static private Location findLocation(PreprocSketch ps, SketchInterval si) { SketchCode code = ps.sketch.getCode(si.tabIndex); String program = code.getProgram(); URI uri = PdeAdapter.pathToUri(code.getFile()); - Location location = - PdeAdapter.toLocation(program, si.startTabOffset, si.stopTabOffset, uri); - - List declarationList = new ArrayList<>(); - declarationList.add(location); - - return declarationList; + return PdeAdapter.toLocation(program, si.startTabOffset, si.stopTabOffset, + uri + ); } } diff --git a/java/src/processing/mode/java/lsp/PdeTextDocumentService.java b/java/src/processing/mode/java/lsp/PdeTextDocumentService.java index 4ac167ab8..67044c037 100644 --- a/java/src/processing/mode/java/lsp/PdeTextDocumentService.java +++ b/java/src/processing/mode/java/lsp/PdeTextDocumentService.java @@ -17,6 +17,7 @@ import org.eclipse.lsp4j.DocumentFormattingParams; import org.eclipse.lsp4j.TextEdit; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.LocationLink; +import org.eclipse.lsp4j.ReferenceParams; import java.util.Collections; import java.net.URI; @@ -105,7 +106,7 @@ class PdeTextDocumentService implements TextDocumentService { Optional adapterOptional = pls.getAdapter(uri); - if(adapterOptional.isEmpty()){ + if (adapterOptional.isEmpty()) { System.out.println("pde adapter not found"); return CompletableFutures.computeAsync(_x -> Either .forLeft(Collections.emptyList())); @@ -116,7 +117,7 @@ class PdeTextDocumentService implements TextDocumentService { Optional optionalJavaOffset = adapter.findJavaOffset(uri, lineNumber, colNumber); - if(optionalJavaOffset.isEmpty()){ + if (optionalJavaOffset.isEmpty()) { System.out.println("javaOffset not found"); return CompletableFutures.computeAsync(_x -> Either .forLeft(Collections.emptyList())); @@ -137,4 +138,36 @@ class PdeTextDocumentService implements TextDocumentService { ); } + + @Override + public CompletableFuture> references( + ReferenceParams params + ) { + + System.out.println("searching for references"); + URI uri = URI.create(params.getTextDocument().getUri()); + int lineNumber = params.getPosition().getLine(); + int colNumber = params.getPosition().getCharacter(); + + Optional adapterOptional = pls.getAdapter(uri); + if (adapterOptional.isEmpty()) { + System.out.println("pde adapter not found"); + return CompletableFutures.computeAsync(_x -> Collections.emptyList()); + } + PdeAdapter adapter = adapterOptional.get(); + PreprocSketch preprocSketch = adapter.ps; + + Optional optionalJavaOffset = + adapter.findJavaOffset(uri, lineNumber, colNumber); + if (optionalJavaOffset.isEmpty()) { + System.out.println("javaOffset not found"); + return CompletableFutures.computeAsync(_x -> (Collections.emptyList())); + } + + int javaOffset = optionalJavaOffset.get(); + List locations; + locations = PdeSymbolFinder.searchReference(preprocSketch, javaOffset); + + return CompletableFutures.computeAsync(_x -> locations); + } }