-
Notifications
You must be signed in to change notification settings - Fork 20
🐛 Do special search for on-demand imports #143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
4649fee
34e06fe
4d2ae79
67a2fef
0c70a81
892d9e9
fb2f68d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -5,6 +5,7 @@ | |||||
|
|
||||||
| import java.util.ArrayList; | ||||||
| import java.util.List; | ||||||
| import java.util.regex.Matcher; | ||||||
| import java.util.regex.Pattern; | ||||||
|
|
||||||
| import org.eclipse.core.runtime.IPath; | ||||||
|
|
@@ -14,18 +15,26 @@ | |||||
| import org.eclipse.jdt.core.IJavaElement; | ||||||
| import org.eclipse.jdt.core.IJavaProject; | ||||||
| import org.eclipse.jdt.core.IPackageFragment; | ||||||
| import org.eclipse.jdt.core.dom.AST; | ||||||
| import org.eclipse.jdt.core.dom.ASTParser; | ||||||
| import org.eclipse.jdt.core.dom.CompilationUnit; | ||||||
| import org.eclipse.jdt.core.dom.ImportDeclaration; | ||||||
| import org.eclipse.jdt.core.search.IJavaSearchConstants; | ||||||
| import org.eclipse.jdt.core.search.IJavaSearchScope; | ||||||
| import org.eclipse.jdt.core.search.SearchEngine; | ||||||
| import org.eclipse.jdt.core.search.SearchParticipant; | ||||||
| import org.eclipse.jdt.core.search.SearchPattern; | ||||||
| import org.eclipse.jdt.internal.core.search.JavaSearchParticipant; | ||||||
| import org.eclipse.jdt.ls.core.internal.IDelegateCommandHandler; | ||||||
| import org.eclipse.jdt.core.IPackageFragmentRoot; | ||||||
| import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; | ||||||
| import org.eclipse.jdt.ls.core.internal.JDTUtils; | ||||||
| import org.eclipse.jdt.ls.core.internal.JobHelpers; | ||||||
| import org.eclipse.jdt.ls.core.internal.ProjectUtils; | ||||||
| import org.eclipse.jdt.ls.core.internal.ResourceUtils; | ||||||
| import org.eclipse.lsp4j.Location; | ||||||
| import org.eclipse.lsp4j.SymbolInformation; | ||||||
| import org.eclipse.lsp4j.SymbolKind; | ||||||
|
|
||||||
| import io.konveyor.tackle.core.internal.query.AnnotationQuery; | ||||||
| import io.konveyor.tackle.core.internal.util.OpenSourceFilteredSearchScope; | ||||||
|
|
@@ -77,11 +86,11 @@ private static SearchPattern mapLocationToSearchPatternLocation(int location, St | |||||
| var startListIndex = query.indexOf("("); | ||||||
| var endListIndex = query.indexOf(")"); | ||||||
| var startQuery = query.substring(0, startListIndex); | ||||||
| var endQuery = query.substring(endListIndex+1, query.length()); | ||||||
| var endQuery = query.substring(endListIndex + 1, query.length()); | ||||||
| var optionalList = endQuery.startsWith("?"); | ||||||
|
|
||||||
| // This should strip the ( ) chars | ||||||
| var listString = query.substring(startListIndex+1, endListIndex); | ||||||
| var listString = query.substring(startListIndex + 1, endListIndex); | ||||||
| var list = listString.split("\\|"); | ||||||
| ArrayList<SearchPattern> l = new ArrayList<SearchPattern>(); | ||||||
|
|
||||||
|
|
@@ -91,11 +100,11 @@ private static SearchPattern mapLocationToSearchPatternLocation(int location, St | |||||
| l.add(mapLocationToSearchPatternLocation(location, startQuery + endQuery)); | ||||||
| } | ||||||
|
|
||||||
| for (String s: list) { | ||||||
| for (String s : list) { | ||||||
| var p = mapLocationToSearchPatternLocation(location, startQuery + s + endQuery); | ||||||
| l.add(p); | ||||||
| } | ||||||
|
|
||||||
| // Get the end pattern | ||||||
| SearchPattern p = l.subList(1, l.size()).stream().reduce(l.get(0), (SearchPattern::createOrPattern)); | ||||||
| return p; | ||||||
|
|
@@ -130,26 +139,26 @@ private static SearchPattern mapLocationToSearchPatternLocation(int location, St | |||||
|
|
||||||
| /** | ||||||
| * Location correspondence from java provider (TYPE is the default): | ||||||
| * "": 0, | ||||||
| * "inheritance": 1, | ||||||
| * "method_call": 2, | ||||||
| * "constructor_call": 3, | ||||||
| * "annotation": 4, | ||||||
| * "implements_type": 5, | ||||||
| * "enum_constant": 6, | ||||||
| * "return_type": 7, | ||||||
| * "import": 8, | ||||||
| * "variable_declaration": 9, | ||||||
| * "type": 10, | ||||||
| * "package": 11, | ||||||
| * "field": 12, | ||||||
| * "method_declaration": 13, | ||||||
| * "class_declaration": 14, | ||||||
| * "": 0, | ||||||
| * "inheritance": 1, | ||||||
| * "method_call": 2, | ||||||
| * "constructor_call": 3, | ||||||
| * "annotation": 4, | ||||||
| * "implements_type": 5, | ||||||
| * "enum_constant": 6, | ||||||
| * "return_type": 7, | ||||||
| * "import": 8, | ||||||
| * "variable_declaration": 9, | ||||||
| * "type": 10, | ||||||
| * "package": 11, | ||||||
| * "field": 12, | ||||||
| * "method_declaration": 13, | ||||||
| * "class_declaration": 14, | ||||||
| * | ||||||
| * @param location | ||||||
| * @param query | ||||||
| * @return | ||||||
| * @throws Exception | ||||||
| * @throws Exception TODO: move these to enums | ||||||
| */ | ||||||
| private static SearchPattern getPatternSingleQuery(int location, String query) throws Exception { | ||||||
| var pattern = SearchPattern.R_PATTERN_MATCH; | ||||||
|
|
@@ -158,52 +167,52 @@ private static SearchPattern getPatternSingleQuery(int location, String query) t | |||||
| pattern = SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE; | ||||||
| } | ||||||
| switch (location) { | ||||||
| // Using type for both type and annotation. | ||||||
| // Type and annotation | ||||||
| case 10: | ||||||
| case 4: | ||||||
| case 8: | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.TYPE, IJavaSearchConstants.ALL_OCCURRENCES, pattern); | ||||||
| case 5: | ||||||
| case 1: | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.TYPE, IJavaSearchConstants.IMPLEMENTORS, pattern); | ||||||
| case 7: | ||||||
| case 9: | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.TYPE, IJavaSearchConstants.REFERENCES, pattern); | ||||||
| case 2: | ||||||
| if (query.contains(".")) { | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.METHOD, IJavaSearchConstants.QUALIFIED_REFERENCE, SearchPattern.R_PATTERN_MATCH | SearchPattern.R_ERASURE_MATCH); | ||||||
| } | ||||||
| // Switched back to referenced | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.METHOD, IJavaSearchConstants.REFERENCES, SearchPattern.R_PATTERN_MATCH | SearchPattern.R_ERASURE_MATCH); | ||||||
| case 3: | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.CONSTRUCTOR, IJavaSearchConstants.ALL_OCCURRENCES, pattern); | ||||||
| case 11: | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.PACKAGE, IJavaSearchConstants.ALL_OCCURRENCES, pattern); | ||||||
| case 12: | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.TYPE, IJavaSearchConstants.FIELD_DECLARATION_TYPE_REFERENCE, pattern); | ||||||
| case 13: | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.METHOD, IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH | SearchPattern.R_PATTERN_MATCH); | ||||||
| case 14: | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.CLASS, IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH | SearchPattern.R_PATTERN_MATCH); | ||||||
| // Using type for both type and annotation. | ||||||
| // Type and annotation | ||||||
| case 10: | ||||||
| case 4: | ||||||
| case 8: | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.TYPE, IJavaSearchConstants.ALL_OCCURRENCES, pattern); | ||||||
| case 5: | ||||||
| case 1: | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.TYPE, IJavaSearchConstants.IMPLEMENTORS, pattern); | ||||||
| case 7: | ||||||
| case 9: | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.TYPE, IJavaSearchConstants.REFERENCES, pattern); | ||||||
| case 2: | ||||||
| if (query.contains(".")) { | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.METHOD, IJavaSearchConstants.QUALIFIED_REFERENCE, SearchPattern.R_PATTERN_MATCH | SearchPattern.R_ERASURE_MATCH); | ||||||
| } | ||||||
| // Switched back to referenced | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.METHOD, IJavaSearchConstants.REFERENCES, SearchPattern.R_PATTERN_MATCH | SearchPattern.R_ERASURE_MATCH); | ||||||
| case 3: | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.CONSTRUCTOR, IJavaSearchConstants.ALL_OCCURRENCES, pattern); | ||||||
| case 11: | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.PACKAGE, IJavaSearchConstants.ALL_OCCURRENCES, pattern); | ||||||
| case 12: | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.TYPE, IJavaSearchConstants.FIELD_DECLARATION_TYPE_REFERENCE, pattern); | ||||||
| case 13: | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.METHOD, IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH | SearchPattern.R_PATTERN_MATCH); | ||||||
| case 14: | ||||||
| return SearchPattern.createPattern(query, IJavaSearchConstants.CLASS, IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH | SearchPattern.R_PATTERN_MATCH); | ||||||
| } | ||||||
| throw new Exception("unable to create search pattern"); | ||||||
| throw new Exception("unable to create search pattern"); | ||||||
| } | ||||||
|
|
||||||
| private static List<SymbolInformation> search(String projectName, ArrayList<String> includedPaths, String query, AnnotationQuery annotationQuery, int location, String analysisMode, | ||||||
| boolean includeOpenSourceLibraries, String mavenLocalRepoPath, String mavenIndexPath, IProgressMonitor monitor) throws Exception { | ||||||
| boolean includeOpenSourceLibraries, String mavenLocalRepoPath, String mavenIndexPath, IProgressMonitor monitor) throws Exception { | ||||||
| IJavaProject[] targetProjects; | ||||||
| IJavaProject project = ProjectUtils.getJavaProject(projectName); | ||||||
| if (project != null) { | ||||||
| targetProjects = new IJavaProject[] { project }; | ||||||
| } else { | ||||||
| targetProjects= ProjectUtils.getJavaProjects(); | ||||||
| } | ||||||
| targetProjects = new IJavaProject[]{project}; | ||||||
| } else { | ||||||
| targetProjects = ProjectUtils.getJavaProjects(); | ||||||
| } | ||||||
|
|
||||||
| logInfo("Searching in target project: " + targetProjects); | ||||||
|
|
||||||
| // For Partial results, we are going to filter out based on a list in the engine | ||||||
| int s = IJavaSearchScope.SOURCES | IJavaSearchScope.REFERENCED_PROJECTS | IJavaSearchScope.APPLICATION_LIBRARIES; | ||||||
| int s = IJavaSearchScope.SOURCES | IJavaSearchScope.REFERENCED_PROJECTS | IJavaSearchScope.APPLICATION_LIBRARIES; | ||||||
| if (analysisMode.equals(sourceOnlyAnalysisMode)) { | ||||||
| logInfo("KONVEYOR_LOG: source-only analysis mode only scoping to Sources"); | ||||||
| s = IJavaSearchScope.SOURCES; | ||||||
|
|
@@ -217,17 +226,19 @@ private static List<SymbolInformation> search(String projectName, ArrayList<Stri | |||||
| var errors = ResourceUtils.getErrorMarkers(iJavaProject.getProject()); | ||||||
| var warnings = ResourceUtils.getWarningMarkers(iJavaProject.getProject()); | ||||||
| logInfo("KONVEYOR_LOG:" + | ||||||
| " found errors: " + errors.toString().replace("\n", " ") + | ||||||
| " warnings: " + warnings.toString().replace("\n", " ")); | ||||||
| " found errors: " + errors.toString().replace("\n", " ") + | ||||||
| " warnings: " + warnings.toString().replace("\n", " ")); | ||||||
| } | ||||||
|
|
||||||
| IJavaSearchScope scope; | ||||||
| IJavaSearchScope scope; | ||||||
| var workspaceDirectoryLocation = JavaLanguageServerPlugin.getPreferencesManager().getPreferences().getRootPaths(); | ||||||
| if (workspaceDirectoryLocation == null || workspaceDirectoryLocation.size() == 0) { | ||||||
| logInfo("unable to find workspace directory location"); | ||||||
| return new ArrayList<>(); | ||||||
| } | ||||||
|
|
||||||
|
|
||||||
| List<ICompilationUnit> units = new ArrayList<>(); | ||||||
|
|
||||||
| if (includedPaths != null && includedPaths.size() > 0) { | ||||||
| ArrayList<IJavaElement> includedFragments = new ArrayList<IJavaElement>(); | ||||||
| for (IJavaProject proj : targetProjects) { | ||||||
|
|
@@ -292,9 +303,14 @@ private static List<SymbolInformation> search(String projectName, ArrayList<Stri | |||||
| // instead of comparing path strings, comparing segments is better for 2 reasons: | ||||||
| // - we don't have to worry about redundant . / etc in input | ||||||
| // - matching sub-trees is easier with segments than strings | ||||||
| if (includedIPath.segmentCount() <= fragmentPath.segmentCount() && | ||||||
| includedIPath.matchingFirstSegments(fragmentPath) == includedIPath.segmentCount()) { | ||||||
| if (includedIPath.segmentCount() <= fragmentPath.segmentCount() && | ||||||
| includedIPath.matchingFirstSegments(fragmentPath) == includedIPath.segmentCount()) { | ||||||
| includedFragments.add(fragment); | ||||||
|
|
||||||
| // Get all compilation units for included fragments | ||||||
| if (fragment.getKind() == IPackageFragmentRoot.K_SOURCE) { | ||||||
| units.addAll(List.of(fragment.getCompilationUnits())); | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
@@ -313,6 +329,8 @@ private static List<SymbolInformation> search(String projectName, ArrayList<Stri | |||||
| } | ||||||
| logInfo("scope: " + scope); | ||||||
|
|
||||||
| List<SymbolInformation> symbols = new ArrayList<SymbolInformation>(); | ||||||
|
|
||||||
| SearchPattern pattern; | ||||||
| try { | ||||||
| pattern = mapLocationToSearchPatternLocation(location, query); | ||||||
|
|
@@ -325,8 +343,6 @@ private static List<SymbolInformation> search(String projectName, ArrayList<Stri | |||||
|
|
||||||
| SearchEngine searchEngine = new SearchEngine(); | ||||||
|
|
||||||
| List<SymbolInformation> symbols = new ArrayList<SymbolInformation>(); | ||||||
|
|
||||||
| SymbolInformationTypeRequestor requestor = new SymbolInformationTypeRequestor(symbols, 0, monitor, location, query, annotationQuery); | ||||||
|
|
||||||
| //Use the default search participents | ||||||
|
|
@@ -340,12 +356,63 @@ private static List<SymbolInformation> search(String projectName, ArrayList<Stri | |||||
| logInfo("KONVEYOR_LOG: unable to get search " + e.toString().replace("\n", " ")); | ||||||
| } | ||||||
|
|
||||||
| // For on-demand imports (things like <code>import javax.ejb.*;</code>) we need to | ||||||
| // do a special search, since on-demand imports are only resolved at compilation time | ||||||
| if (location == 8) { | ||||||
| Matcher matcher = Pattern.compile("[^A-Z*]+\\*").matcher(query); | ||||||
| if (matcher.matches()) { | ||||||
| // Get all compilation units in scope | ||||||
| for (IJavaProject p : targetProjects) { | ||||||
| for (IPackageFragment pkg : p.getPackageFragments()) { | ||||||
| if (pkg.getKind() == IPackageFragmentRoot.K_SOURCE) { | ||||||
| for (ICompilationUnit unit : pkg.getCompilationUnits()) { | ||||||
| if (scope.encloses(unit)) { | ||||||
| units.add(unit); | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| // Now run ImportScanner only on units in scope | ||||||
| ASTParser parser = ASTParser.newParser(AST.getJLSLatest()); | ||||||
| Pattern regex = Pattern.compile(query); | ||||||
| for (ICompilationUnit unit : units) { | ||||||
| parser.setSource(unit); | ||||||
| CompilationUnit cu = (CompilationUnit) parser.createAST(null); | ||||||
| for (Object o : cu.imports()) { | ||||||
| ImportDeclaration imp = (ImportDeclaration) o; | ||||||
| if (imp.isOnDemand()) { | ||||||
| if (regex.matcher(imp.getName().getFullyQualifiedName()).matches()) { | ||||||
| SymbolInformation symbol = new SymbolInformation(); | ||||||
| symbol.setName(imp.getName().getFullyQualifiedName()); | ||||||
| symbol.setKind(SymbolKind.Namespace); | ||||||
| symbol.setContainerName(unit.getElementName()); | ||||||
| symbol.setLocation(getLocationForImport(unit, imp, cu)); | ||||||
| System.out.println("Found in " + unit.getElementName()); | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remove debug print statement. The - System.out.println("Found in " + unit.getElementName());
+ logInfo("Found on-demand import in " + unit.getElementName());📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||
| symbols.add(symbol); | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
|
|
||||||
| logInfo("KONVEYOR_LOG: got: " + requestor.getAllSearchMatches() + | ||||||
| " search matches for " + query + | ||||||
| " location " + location | ||||||
| + " matches" + requestor.getSymbols().size()); | ||||||
| " search matches for " + query + | ||||||
| " location " + location | ||||||
| + " matches" + requestor.getSymbols().size()); | ||||||
|
|
||||||
| return symbols; | ||||||
|
|
||||||
| return requestor.getSymbols(); | ||||||
| } | ||||||
|
|
||||||
| public static Location getLocationForImport(ICompilationUnit icu, ImportDeclaration imp, CompilationUnit cuAst) { | ||||||
| try { | ||||||
| return JDTUtils.toLocation(icu, imp.getStartPosition(), imp.getLength()); | ||||||
| } catch (Exception e) { | ||||||
| logInfo("Unable to get location for import: " + e); | ||||||
| return null; | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
| } | ||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid redundant compilation unit collection.
When
includedPathsis specified, compilation units are already collected from included fragments at lines 310-313. The code then re-collects all units from all target projects (lines 364-375), creating duplicates and wasting resources.Apply this fix to collect units only when not already gathered:
📝 Committable suggestion
🤖 Prompt for AI Agents