55
66import java .util .ArrayList ;
77import java .util .List ;
8+ import java .util .regex .Matcher ;
89import java .util .regex .Pattern ;
910
1011import org .eclipse .core .runtime .IPath ;
1415import org .eclipse .jdt .core .IJavaElement ;
1516import org .eclipse .jdt .core .IJavaProject ;
1617import org .eclipse .jdt .core .IPackageFragment ;
18+ import org .eclipse .jdt .core .dom .AST ;
19+ import org .eclipse .jdt .core .dom .ASTParser ;
20+ import org .eclipse .jdt .core .dom .CompilationUnit ;
21+ import org .eclipse .jdt .core .dom .ImportDeclaration ;
1722import org .eclipse .jdt .core .search .IJavaSearchConstants ;
1823import org .eclipse .jdt .core .search .IJavaSearchScope ;
1924import org .eclipse .jdt .core .search .SearchEngine ;
2025import org .eclipse .jdt .core .search .SearchParticipant ;
2126import org .eclipse .jdt .core .search .SearchPattern ;
2227import org .eclipse .jdt .internal .core .search .JavaSearchParticipant ;
2328import org .eclipse .jdt .ls .core .internal .IDelegateCommandHandler ;
29+ import org .eclipse .jdt .core .IPackageFragmentRoot ;
2430import org .eclipse .jdt .ls .core .internal .JavaLanguageServerPlugin ;
31+ import org .eclipse .jdt .ls .core .internal .JDTUtils ;
2532import org .eclipse .jdt .ls .core .internal .JobHelpers ;
2633import org .eclipse .jdt .ls .core .internal .ProjectUtils ;
2734import org .eclipse .jdt .ls .core .internal .ResourceUtils ;
35+ import org .eclipse .lsp4j .Location ;
2836import org .eclipse .lsp4j .SymbolInformation ;
37+ import org .eclipse .lsp4j .SymbolKind ;
2938
3039import io .konveyor .tackle .core .internal .query .AnnotationQuery ;
3140import io .konveyor .tackle .core .internal .util .OpenSourceFilteredSearchScope ;
@@ -77,11 +86,11 @@ private static SearchPattern mapLocationToSearchPatternLocation(int location, St
7786 var startListIndex = query .indexOf ("(" );
7887 var endListIndex = query .indexOf (")" );
7988 var startQuery = query .substring (0 , startListIndex );
80- var endQuery = query .substring (endListIndex + 1 , query .length ());
89+ var endQuery = query .substring (endListIndex + 1 , query .length ());
8190 var optionalList = endQuery .startsWith ("?" );
8291
8392 // This should strip the ( ) chars
84- var listString = query .substring (startListIndex + 1 , endListIndex );
93+ var listString = query .substring (startListIndex + 1 , endListIndex );
8594 var list = listString .split ("\\ |" );
8695 ArrayList <SearchPattern > l = new ArrayList <SearchPattern >();
8796
@@ -91,11 +100,11 @@ private static SearchPattern mapLocationToSearchPatternLocation(int location, St
91100 l .add (mapLocationToSearchPatternLocation (location , startQuery + endQuery ));
92101 }
93102
94- for (String s : list ) {
103+ for (String s : list ) {
95104 var p = mapLocationToSearchPatternLocation (location , startQuery + s + endQuery );
96105 l .add (p );
97106 }
98-
107+
99108 // Get the end pattern
100109 SearchPattern p = l .subList (1 , l .size ()).stream ().reduce (l .get (0 ), (SearchPattern ::createOrPattern ));
101110 return p ;
@@ -130,26 +139,26 @@ private static SearchPattern mapLocationToSearchPatternLocation(int location, St
130139
131140 /**
132141 * Location correspondence from java provider (TYPE is the default):
133- * "": 0,
134- * "inheritance": 1,
135- * "method_call": 2,
136- * "constructor_call": 3,
137- * "annotation": 4,
138- * "implements_type": 5,
139- * "enum_constant": 6,
140- * "return_type": 7,
141- * "import": 8,
142- * "variable_declaration": 9,
143- * "type": 10,
144- * "package": 11,
145- * "field": 12,
146- * "method_declaration": 13,
147- * "class_declaration": 14,
142+ * "": 0,
143+ * "inheritance": 1,
144+ * "method_call": 2,
145+ * "constructor_call": 3,
146+ * "annotation": 4,
147+ * "implements_type": 5,
148+ * "enum_constant": 6,
149+ * "return_type": 7,
150+ * "import": 8,
151+ * "variable_declaration": 9,
152+ * "type": 10,
153+ * "package": 11,
154+ * "field": 12,
155+ * "method_declaration": 13,
156+ * "class_declaration": 14,
148157 *
149158 * @param location
150159 * @param query
151160 * @return
152- * @throws Exception
161+ * @throws Exception TODO: move these to enums
153162 */
154163 private static SearchPattern getPatternSingleQuery (int location , String query ) throws Exception {
155164 var pattern = SearchPattern .R_PATTERN_MATCH ;
@@ -158,52 +167,52 @@ private static SearchPattern getPatternSingleQuery(int location, String query) t
158167 pattern = SearchPattern .R_EXACT_MATCH | SearchPattern .R_CASE_SENSITIVE ;
159168 }
160169 switch (location ) {
161- // Using type for both type and annotation.
162- // Type and annotation
163- case 10 :
164- case 4 :
165- case 8 :
166- return SearchPattern .createPattern (query , IJavaSearchConstants .TYPE , IJavaSearchConstants .ALL_OCCURRENCES , pattern );
167- case 5 :
168- case 1 :
169- return SearchPattern .createPattern (query , IJavaSearchConstants .TYPE , IJavaSearchConstants .IMPLEMENTORS , pattern );
170- case 7 :
171- case 9 :
172- return SearchPattern .createPattern (query , IJavaSearchConstants .TYPE , IJavaSearchConstants .REFERENCES , pattern );
173- case 2 :
174- if (query .contains ("." )) {
175- return SearchPattern .createPattern (query , IJavaSearchConstants .METHOD , IJavaSearchConstants .QUALIFIED_REFERENCE , SearchPattern .R_PATTERN_MATCH | SearchPattern .R_ERASURE_MATCH );
176- }
177- // Switched back to referenced
178- return SearchPattern .createPattern (query , IJavaSearchConstants .METHOD , IJavaSearchConstants .REFERENCES , SearchPattern .R_PATTERN_MATCH | SearchPattern .R_ERASURE_MATCH );
179- case 3 :
180- return SearchPattern .createPattern (query , IJavaSearchConstants .CONSTRUCTOR , IJavaSearchConstants .ALL_OCCURRENCES , pattern );
181- case 11 :
182- return SearchPattern .createPattern (query , IJavaSearchConstants .PACKAGE , IJavaSearchConstants .ALL_OCCURRENCES , pattern );
183- case 12 :
184- return SearchPattern .createPattern (query , IJavaSearchConstants .TYPE , IJavaSearchConstants .FIELD_DECLARATION_TYPE_REFERENCE , pattern );
185- case 13 :
186- return SearchPattern .createPattern (query , IJavaSearchConstants .METHOD , IJavaSearchConstants .DECLARATIONS , SearchPattern .R_EXACT_MATCH | SearchPattern .R_PATTERN_MATCH );
187- case 14 :
188- return SearchPattern .createPattern (query , IJavaSearchConstants .CLASS , IJavaSearchConstants .DECLARATIONS , SearchPattern .R_EXACT_MATCH | SearchPattern .R_PATTERN_MATCH );
170+ // Using type for both type and annotation.
171+ // Type and annotation
172+ case 10 :
173+ case 4 :
174+ case 8 :
175+ return SearchPattern .createPattern (query , IJavaSearchConstants .TYPE , IJavaSearchConstants .ALL_OCCURRENCES , pattern );
176+ case 5 :
177+ case 1 :
178+ return SearchPattern .createPattern (query , IJavaSearchConstants .TYPE , IJavaSearchConstants .IMPLEMENTORS , pattern );
179+ case 7 :
180+ case 9 :
181+ return SearchPattern .createPattern (query , IJavaSearchConstants .TYPE , IJavaSearchConstants .REFERENCES , pattern );
182+ case 2 :
183+ if (query .contains ("." )) {
184+ return SearchPattern .createPattern (query , IJavaSearchConstants .METHOD , IJavaSearchConstants .QUALIFIED_REFERENCE , SearchPattern .R_PATTERN_MATCH | SearchPattern .R_ERASURE_MATCH );
185+ }
186+ // Switched back to referenced
187+ return SearchPattern .createPattern (query , IJavaSearchConstants .METHOD , IJavaSearchConstants .REFERENCES , SearchPattern .R_PATTERN_MATCH | SearchPattern .R_ERASURE_MATCH );
188+ case 3 :
189+ return SearchPattern .createPattern (query , IJavaSearchConstants .CONSTRUCTOR , IJavaSearchConstants .ALL_OCCURRENCES , pattern );
190+ case 11 :
191+ return SearchPattern .createPattern (query , IJavaSearchConstants .PACKAGE , IJavaSearchConstants .ALL_OCCURRENCES , pattern );
192+ case 12 :
193+ return SearchPattern .createPattern (query , IJavaSearchConstants .TYPE , IJavaSearchConstants .FIELD_DECLARATION_TYPE_REFERENCE , pattern );
194+ case 13 :
195+ return SearchPattern .createPattern (query , IJavaSearchConstants .METHOD , IJavaSearchConstants .DECLARATIONS , SearchPattern .R_EXACT_MATCH | SearchPattern .R_PATTERN_MATCH );
196+ case 14 :
197+ return SearchPattern .createPattern (query , IJavaSearchConstants .CLASS , IJavaSearchConstants .DECLARATIONS , SearchPattern .R_EXACT_MATCH | SearchPattern .R_PATTERN_MATCH );
189198 }
190- throw new Exception ("unable to create search pattern" );
199+ throw new Exception ("unable to create search pattern" );
191200 }
192201
193202 private static List <SymbolInformation > search (String projectName , ArrayList <String > includedPaths , String query , AnnotationQuery annotationQuery , int location , String analysisMode ,
194- boolean includeOpenSourceLibraries , String mavenLocalRepoPath , String mavenIndexPath , IProgressMonitor monitor ) throws Exception {
203+ boolean includeOpenSourceLibraries , String mavenLocalRepoPath , String mavenIndexPath , IProgressMonitor monitor ) throws Exception {
195204 IJavaProject [] targetProjects ;
196205 IJavaProject project = ProjectUtils .getJavaProject (projectName );
197206 if (project != null ) {
198- targetProjects = new IJavaProject [] { project };
199- } else {
200- targetProjects = ProjectUtils .getJavaProjects ();
201- }
202-
207+ targetProjects = new IJavaProject []{ project };
208+ } else {
209+ targetProjects = ProjectUtils .getJavaProjects ();
210+ }
211+
203212 logInfo ("Searching in target project: " + targetProjects );
204213
205214 // For Partial results, we are going to filter out based on a list in the engine
206- int s = IJavaSearchScope .SOURCES | IJavaSearchScope .REFERENCED_PROJECTS | IJavaSearchScope .APPLICATION_LIBRARIES ;
215+ int s = IJavaSearchScope .SOURCES | IJavaSearchScope .REFERENCED_PROJECTS | IJavaSearchScope .APPLICATION_LIBRARIES ;
207216 if (analysisMode .equals (sourceOnlyAnalysisMode )) {
208217 logInfo ("KONVEYOR_LOG: source-only analysis mode only scoping to Sources" );
209218 s = IJavaSearchScope .SOURCES ;
@@ -217,17 +226,19 @@ private static List<SymbolInformation> search(String projectName, ArrayList<Stri
217226 var errors = ResourceUtils .getErrorMarkers (iJavaProject .getProject ());
218227 var warnings = ResourceUtils .getWarningMarkers (iJavaProject .getProject ());
219228 logInfo ("KONVEYOR_LOG:" +
220- " found errors: " + errors .toString ().replace ("\n " , " " ) +
221- " warnings: " + warnings .toString ().replace ("\n " , " " ));
229+ " found errors: " + errors .toString ().replace ("\n " , " " ) +
230+ " warnings: " + warnings .toString ().replace ("\n " , " " ));
222231 }
223232
224- IJavaSearchScope scope ;
233+ IJavaSearchScope scope ;
225234 var workspaceDirectoryLocation = JavaLanguageServerPlugin .getPreferencesManager ().getPreferences ().getRootPaths ();
226235 if (workspaceDirectoryLocation == null || workspaceDirectoryLocation .size () == 0 ) {
227236 logInfo ("unable to find workspace directory location" );
228237 return new ArrayList <>();
229238 }
230-
239+
240+ List <ICompilationUnit > units = new ArrayList <>();
241+
231242 if (includedPaths != null && includedPaths .size () > 0 ) {
232243 ArrayList <IJavaElement > includedFragments = new ArrayList <IJavaElement >();
233244 for (IJavaProject proj : targetProjects ) {
@@ -292,9 +303,14 @@ private static List<SymbolInformation> search(String projectName, ArrayList<Stri
292303 // instead of comparing path strings, comparing segments is better for 2 reasons:
293304 // - we don't have to worry about redundant . / etc in input
294305 // - matching sub-trees is easier with segments than strings
295- if (includedIPath .segmentCount () <= fragmentPath .segmentCount () &&
296- includedIPath .matchingFirstSegments (fragmentPath ) == includedIPath .segmentCount ()) {
306+ if (includedIPath .segmentCount () <= fragmentPath .segmentCount () &&
307+ includedIPath .matchingFirstSegments (fragmentPath ) == includedIPath .segmentCount ()) {
297308 includedFragments .add (fragment );
309+
310+ // Get all compilation units for included fragments
311+ if (fragment .getKind () == IPackageFragmentRoot .K_SOURCE ) {
312+ units .addAll (List .of (fragment .getCompilationUnits ()));
313+ }
298314 }
299315 }
300316 }
@@ -313,6 +329,8 @@ private static List<SymbolInformation> search(String projectName, ArrayList<Stri
313329 }
314330 logInfo ("scope: " + scope );
315331
332+ List <SymbolInformation > symbols = new ArrayList <SymbolInformation >();
333+
316334 SearchPattern pattern ;
317335 try {
318336 pattern = mapLocationToSearchPatternLocation (location , query );
@@ -325,8 +343,6 @@ private static List<SymbolInformation> search(String projectName, ArrayList<Stri
325343
326344 SearchEngine searchEngine = new SearchEngine ();
327345
328- List <SymbolInformation > symbols = new ArrayList <SymbolInformation >();
329-
330346 SymbolInformationTypeRequestor requestor = new SymbolInformationTypeRequestor (symbols , 0 , monitor , location , query , annotationQuery );
331347
332348 //Use the default search participents
@@ -340,12 +356,63 @@ private static List<SymbolInformation> search(String projectName, ArrayList<Stri
340356 logInfo ("KONVEYOR_LOG: unable to get search " + e .toString ().replace ("\n " , " " ));
341357 }
342358
359+ // For on-demand imports (things like <code>import javax.ejb.*;</code>) we need to
360+ // do a special search, since on-demand imports are only resolved at compilation time
361+ if (location == 8 ) {
362+ Matcher matcher = Pattern .compile ("[^A-Z*]+\\ *" ).matcher (query );
363+ if (matcher .matches ()) {
364+ // Get all compilation units in scope
365+ for (IJavaProject p : targetProjects ) {
366+ for (IPackageFragment pkg : p .getPackageFragments ()) {
367+ if (pkg .getKind () == IPackageFragmentRoot .K_SOURCE ) {
368+ for (ICompilationUnit unit : pkg .getCompilationUnits ()) {
369+ if (scope .encloses (unit )) {
370+ units .add (unit );
371+ }
372+ }
373+ }
374+ }
375+ }
376+
377+ // Now run ImportScanner only on units in scope
378+ ASTParser parser = ASTParser .newParser (AST .getJLSLatest ());
379+ Pattern regex = Pattern .compile (query );
380+ for (ICompilationUnit unit : units ) {
381+ parser .setSource (unit );
382+ CompilationUnit cu = (CompilationUnit ) parser .createAST (null );
383+ for (Object o : cu .imports ()) {
384+ ImportDeclaration imp = (ImportDeclaration ) o ;
385+ if (imp .isOnDemand ()) {
386+ if (regex .matcher (imp .getName ().getFullyQualifiedName ()).matches ()) {
387+ SymbolInformation symbol = new SymbolInformation ();
388+ symbol .setName (imp .getName ().getFullyQualifiedName ());
389+ symbol .setKind (SymbolKind .Namespace );
390+ symbol .setContainerName (unit .getElementName ());
391+ symbol .setLocation (getLocationForImport (unit , imp , cu ));
392+ System .out .println ("Found in " + unit .getElementName ());
393+ symbols .add (symbol );
394+ }
395+ }
396+ }
397+ }
398+ }
399+ }
400+
343401 logInfo ("KONVEYOR_LOG: got: " + requestor .getAllSearchMatches () +
344- " search matches for " + query +
345- " location " + location
346- + " matches" + requestor .getSymbols ().size ());
402+ " search matches for " + query +
403+ " location " + location
404+ + " matches" + requestor .getSymbols ().size ());
405+
406+ return symbols ;
347407
348- return requestor . getSymbols ();
408+ }
349409
410+ public static Location getLocationForImport (ICompilationUnit icu , ImportDeclaration imp , CompilationUnit cuAst ) {
411+ try {
412+ return JDTUtils .toLocation (icu , imp .getStartPosition (), imp .getLength ());
413+ } catch (Exception e ) {
414+ logInfo ("Unable to get location for import: " + e );
415+ return null ;
416+ }
350417 }
351- }
418+ }
0 commit comments