-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathAnnotationSearchService.java
More file actions
132 lines (111 loc) · 5.61 KB
/
AnnotationSearchService.java
File metadata and controls
132 lines (111 loc) · 5.61 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
package dev.snowdrop.lsp.common.services;
import org.eclipse.jdt.core.dom.*;
import org.eclipse.lsp4j.*;
import org.eclipse.lsp4j.services.LanguageServer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.file.Path;
import java.util.*;
import java.util.concurrent.CompletableFuture;
public class AnnotationSearchService {
private static final Logger logger = LoggerFactory.getLogger(AnnotationSearchService.class);
private final LanguageServer languageServer;
private final ASTParser astParser;
public AnnotationSearchService(LanguageServer languageServer) {
this.languageServer = languageServer;
this.astParser = createASTParser();
}
/**
* Creates and configures an AST parser for Java source code analysis.
*/
private ASTParser createASTParser() {
ASTParser parser = ASTParser.newParser(AST.getJLSLatest());
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setResolveBindings(true); // Enable binding resolution for IAnnotation support
parser.setBindingsRecovery(true);
return parser;
}
/**
* Searches for annotations using LSP workspace operations.
*
* @param projectRoot The root directory to search
* @param annotationName The annotation name to search for (without @)
* @return CompletableFuture containing search results
*/
public CompletableFuture<List<? extends Location>> searchAnnotation(Path projectRoot, String annotationName) {
logger.info("Starting LSP search for @{} annotation in project: {}", annotationName, projectRoot);
// First use LSP to discover workspace symbols
return findUsingLsSymbol(annotationName)
// If a definition is found, use it to find all Text references.
.thenCompose(optionalDefinition -> {
if (optionalDefinition.isEmpty()) {
logger.warn("Could not find a definition for annotation '{}'. Cannot search for references.", annotationName);
return CompletableFuture.completedFuture(new ArrayList<Location>());
}
// If definition is found, proceed to find its references
// TODO: Improve this code to iterate
return findAnnotationReferences(optionalDefinition.get(0));
});
}
/**
* Uses LSP workspace/symbol to find potential Java files containing the annotation.
*/
private CompletableFuture<List<LSPSymbolInfo>> findUsingLsSymbol(String annotationName) {
if (languageServer == null) {
logger.error("No LanguageServer available, skipping LSP discovery");
return CompletableFuture.completedFuture(new ArrayList<>());
}
WorkspaceSymbolParams symbolParams = new WorkspaceSymbolParams(annotationName);
return languageServer.getWorkspaceService().symbol(symbolParams)
.thenApply(eitherResult -> {
List<LSPSymbolInfo> lspSymbols = new ArrayList<>();
if (eitherResult.isLeft()) {
List<? extends SymbolInformation> symbols = eitherResult.getLeft();
for (SymbolInformation symbol : symbols) {
lspSymbols.add(new LSPSymbolInfo(
symbol.getName(),
symbol.getLocation().getUri(),
symbol.getKind(),
symbol.getLocation()
));
}
} else {
List<? extends WorkspaceSymbol> symbols = eitherResult.getRight();
for (WorkspaceSymbol symbol : symbols) {
if (symbol.getLocation().isLeft()) {
Location location = symbol.getLocation().getLeft();
lspSymbols.add(new LSPSymbolInfo(
symbol.getName(),
location.getUri(),
symbol.getKind(),
location
));
}
}
}
logger.info("LSP workspace/symbol found {} symbols for '{}'", lspSymbols.size(), annotationName);
return lspSymbols;
});
}
/**
* Given the symbol for an annotation's definition, this method finds all its references.
*/
private CompletableFuture<List<? extends Location>> findAnnotationReferences(LSPSymbolInfo definitionSymbol) {
if (languageServer == null) {
return CompletableFuture.completedFuture(new ArrayList<>());
}
logger.info("Found definition of '{}' at {}. Now searching for all references...",
definitionSymbol.getName(), definitionSymbol.getFileUri());
// 1. Create a ReferenceParams object for the request
ReferenceParams params = new ReferenceParams();
// 2. Set the document identifier from the definition we found in step 1
params.setTextDocument(new TextDocumentIdentifier(definitionSymbol.getFileUri()));
// 3. Set the position of the symbol in that document
params.setPosition(definitionSymbol.getLocation().getRange().getStart());
// 4. Set the context to include the declaration itself in the results
params.setContext(new ReferenceContext(true));
// 5. Call the 'textDocument/references' endpoint
logger.debug("Issuing 'textDocument/references' request with params: {}", params);
return languageServer.getTextDocumentService().references(params);
}
}