22
22
import java .util .ArrayList ;
23
23
import java .util .Arrays ;
24
24
import java .util .List ;
25
+ import java .util .Optional ;
25
26
import java .util .Set ;
27
+ import java .util .concurrent .CompletableFuture ;
26
28
import java .util .concurrent .atomic .AtomicReference ;
27
29
import java .util .stream .Collectors ;
28
30
35
37
import org .eclipse .lsp4j .LocationLink ;
36
38
import org .eclipse .lsp4j .Position ;
37
39
import org .eclipse .lsp4j .Range ;
40
+ import org .eclipse .lsp4j .ShowDocumentParams ;
38
41
import org .eclipse .lsp4j .TextDocumentIdentifier ;
39
42
import org .eclipse .lsp4j .jsonrpc .CancelChecker ;
40
43
import org .slf4j .Logger ;
46
49
import org .springframework .ide .vscode .commons .java .IClasspathUtil ;
47
50
import org .springframework .ide .vscode .commons .java .IJavaProject ;
48
51
import org .springframework .ide .vscode .commons .java .SpringProjectUtil ;
52
+ import org .springframework .ide .vscode .commons .languageserver .java .JavaProjectFinder ;
53
+ import org .springframework .ide .vscode .commons .languageserver .util .SimpleLanguageServer ;
49
54
import org .springframework .ide .vscode .commons .languageserver .util .SimpleTextDocumentService ;
50
55
import org .springframework .ide .vscode .commons .util .BadLocationException ;
51
56
57
+ import com .google .gson .Gson ;
58
+ import com .google .gson .JsonElement ;
59
+
52
60
public class GenAotQueryMethodDefinitionProvider implements IJavaDefinitionProvider {
53
61
54
62
private static Logger log = LoggerFactory .getLogger (GenAotQueryMethodDefinitionProvider .class );
55
63
64
+ public static final String CMD_NAVIGATE_TO_IMPL = "sts/boot/open-data-query-method-aot-definition" ;
65
+
56
66
private final CompilationUnitCache cuCache ;
57
67
private final SimpleTextDocumentService docService ;
68
+ private final JavaProjectFinder projectFinder ;
58
69
59
- public GenAotQueryMethodDefinitionProvider (CompilationUnitCache cuCache , SimpleTextDocumentService docService ) {
70
+ public GenAotQueryMethodDefinitionProvider (SimpleLanguageServer server , CompilationUnitCache cuCache , JavaProjectFinder projectFinder ) {
60
71
this .cuCache = cuCache ;
61
- this .docService = docService ;
72
+ this .docService = server .getTextDocumentService ();
73
+ this .projectFinder = projectFinder ;
74
+ registerCommands (server );
62
75
}
63
76
64
77
@ Override
@@ -73,17 +86,29 @@ public List<LocationLink> getDefinitions(CancelChecker cancelToken, IJavaProject
73
86
&& methodBinding .getDeclaringClass () != null
74
87
&& ASTUtils .isAnyTypeInHierarchy (methodBinding .getDeclaringClass (),
75
88
List .of (Constants .REPOSITORY_TYPE ))) {
76
- String genRepoFqn = methodBinding .getDeclaringClass ().getQualifiedName () + "Impl__Aot" ;
77
- Path relativeGenSourcePath = Paths .get ("%s.java" .formatted (genRepoFqn .replace ('.' , '/' )));
78
- List <LocationLink > defs = findInSourceFolder (project , relativeGenSourcePath , docId , md , methodBinding , genRepoFqn );
79
- return defs .isEmpty () ? findInBuildFolder (project , relativeGenSourcePath , docId , md , methodBinding , genRepoFqn ) : defs ;
89
+
90
+ try {
91
+ Range originRange = docService .getLatestSnapshot (docId .getUri ()).toRange (md .getName ().getStartPosition (), md .getName ().getLength ());
92
+ GoToImplParams params = new GoToImplParams (docId , methodBinding .getDeclaringClass ().getQualifiedName (), methodBinding .getName (), Arrays .stream (methodBinding .getParameterTypes ()).map (b -> b .getQualifiedName ()).toArray (String []::new ), originRange );
93
+ return findDefinitions (project , params );
94
+ } catch (BadLocationException e ) {
95
+ log .error ("" , e );
96
+ }
97
+
80
98
}
81
99
}
82
100
}
83
101
return List .of ();
84
102
}
85
103
86
- private List <LocationLink > getLocationInGenFile (IJavaProject project , TextDocumentIdentifier docId , MethodDeclaration md , IMethodBinding methodBinding , Path genRepoSourcePath , String genRepoFqn ) {
104
+ private List <LocationLink > findDefinitions (IJavaProject project , GoToImplParams implParams ) {
105
+ String genRepoFqn = implParams .repoFqName () + "Impl__Aot" ;
106
+ Path relativeGenSourcePath = Paths .get ("%s.java" .formatted (genRepoFqn .replace ('.' , '/' )));
107
+ List <LocationLink > defs = findInSourceFolder (project , relativeGenSourcePath , genRepoFqn , implParams );
108
+ return defs .isEmpty () ? findInBuildFolder (project , relativeGenSourcePath , genRepoFqn , implParams ) : defs ;
109
+ }
110
+
111
+ private List <LocationLink > getLocationInGenFile (IJavaProject project , Path genRepoSourcePath , String genRepoFqn , GoToImplParams params ) {
87
112
if (Files .exists (genRepoSourcePath )) {
88
113
URI genUri = genRepoSourcePath .toUri ();
89
114
return cuCache .withCompilationUnit (project , genUri , genCu -> {
@@ -94,21 +119,18 @@ private List<LocationLink> getLocationInGenFile(IJavaProject project, TextDocume
94
119
public boolean visit (MethodDeclaration node ) {
95
120
IMethodBinding genBinding = node .resolveBinding ();
96
121
if (genBinding != null
97
- && genBinding .getName ().equals (methodBinding . getName ())
98
- && Arrays .equals (Arrays .stream (genBinding .getParameterTypes ()).map (b -> b .getQualifiedName ()).toArray (), Arrays . stream ( methodBinding . getParameterTypes ()). map ( b -> b . getQualifiedName ()). toArray () )
122
+ && genBinding .getName ().equals (params . queryMethodName ())
123
+ && Arrays .equals (Arrays .stream (genBinding .getParameterTypes ()).map (b -> b .getQualifiedName ()).toArray (), params . paramTypes )
99
124
&& genRepoFqn .equals (genBinding .getDeclaringClass ().getQualifiedName ())) {
100
125
LocationLink ll = new LocationLink ();
101
126
ll .setTargetUri (genUri .toASCIIString ());
102
- try {
103
- ll .setOriginSelectionRange (docService .getLatestSnapshot (docId .getUri ()).toRange (md .getName ().getStartPosition (), md .getName ().getLength ()));
104
- } catch (BadLocationException e ) {
105
- log .error ("" , e );
106
- }
127
+ ll .setOriginSelectionRange (params .originSelection ());
107
128
SimpleName genName = node .getName ();
108
129
int startLine = genCu .getLineNumber (genName .getStartPosition ());
109
- Position targetStartPosition = new Position (startLine , genName .getStartPosition () - genCu .getPosition (startLine , 0 ));
130
+ // LSP line are 0-based hence -1 from line number when building LSP Range/Position
131
+ Position targetStartPosition = new Position (startLine - 1 , genName .getStartPosition () - genCu .getPosition (startLine , 0 ));
110
132
int endLine = genCu .getLineNumber (genName .getStartPosition () + genName .getLength ());
111
- Position targetEndPosition = new Position (endLine , genName .getStartPosition () + genName .getLength () - genCu .getPosition (endLine , 0 ));
133
+ Position targetEndPosition = new Position (endLine - 1 , genName .getStartPosition () + genName .getLength () - genCu .getPosition (endLine , 0 ));
112
134
Range targetRange = new Range (targetStartPosition , targetEndPosition );
113
135
ll .setTargetRange (targetRange );
114
136
ll .setTargetSelectionRange (targetRange );
@@ -124,15 +146,15 @@ public boolean visit(MethodDeclaration node) {
124
146
return List .of ();
125
147
}
126
148
127
- private List <LocationLink > findInSourceFolder (IJavaProject project , Path relativeGenSourcePath , TextDocumentIdentifier docId , MethodDeclaration md , IMethodBinding methodBinding , String genRepoFqn ) {
149
+ private List <LocationLink > findInSourceFolder (IJavaProject project , Path relativeGenSourcePath , String genRepoFqn , GoToImplParams params ) {
128
150
for (File f : IClasspathUtil .getSourceFolders (project .getClasspath ()).collect (Collectors .toSet ())) {
129
151
Path genRepoSourcePath = f .toPath ().resolve (relativeGenSourcePath );
130
- return getLocationInGenFile (project , docId , md , methodBinding , genRepoSourcePath , genRepoFqn );
152
+ return getLocationInGenFile (project , genRepoSourcePath , genRepoFqn , params );
131
153
}
132
154
return List .of ();
133
155
}
134
156
135
- private List <LocationLink > findInBuildFolder (IJavaProject project , Path relativeGenSourcePath , TextDocumentIdentifier docId , MethodDeclaration md , IMethodBinding methodBinding , String genRepoFqn ) {
157
+ private List <LocationLink > findInBuildFolder (IJavaProject project , Path relativeGenSourcePath , String genRepoFqn , GoToImplParams params ) {
136
158
Path buildDirRelativePath = null ;
137
159
Path projectPath = Paths .get (project .getLocationUri ());
138
160
Set <Path > outputFolders = IClasspathUtil .getOutputFolders (project .getClasspath ()).map (f -> f .toPath ()).collect (Collectors .toSet ());
@@ -182,7 +204,30 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
182
204
} catch (IOException e ) {
183
205
log .error ("" , e );
184
206
}
185
- return genSourceFilePathRef .get () == null ? List .of () : getLocationInGenFile (project , docId , md , methodBinding , genSourceFilePathRef .get (), genRepoFqn );
207
+ return genSourceFilePathRef .get () == null ? List .of () : getLocationInGenFile (project , genSourceFilePathRef .get (), genRepoFqn , params );
186
208
}
187
209
210
+ private void registerCommands (SimpleLanguageServer server ) {
211
+ server .onCommand (CMD_NAVIGATE_TO_IMPL , params -> {
212
+ return CompletableFuture .supplyAsync (() -> {
213
+ GoToImplParams implParams = new Gson ().fromJson ((JsonElement ) params .getArguments ().get (0 ), GoToImplParams .class );
214
+ Optional <IJavaProject > project = projectFinder .find (implParams .docId ());
215
+ if (project .isEmpty ()) {
216
+ return List .<LocationLink >of ();
217
+ }
218
+ return findDefinitions (project .get (), implParams );
219
+ }).thenCompose (links -> {
220
+ if (links .isEmpty ()) {
221
+ return CompletableFuture .completedFuture (null );
222
+ } else {
223
+ ShowDocumentParams showDocParams = new ShowDocumentParams (links .get (0 ).getTargetUri ());
224
+ showDocParams .setSelection (links .get (0 ).getTargetRange ());
225
+ return server .getClient ().showDocument (showDocParams );
226
+ }
227
+ });
228
+ });
229
+ }
230
+
231
+ public record GoToImplParams (TextDocumentIdentifier docId , String repoFqName , String queryMethodName , String [] paramTypes , Range originSelection ) {}
232
+
188
233
}
0 commit comments