Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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>();

Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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) {
Expand Down Expand Up @@ -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()));
}
}
}
}
Expand All @@ -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);
Expand All @@ -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
Expand All @@ -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);
}
}
}
}
}
Comment on lines +364 to +375
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid redundant compilation unit collection.

When includedPaths is 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:

-                // 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);
-                                }
-                            }
-                        }
-                    }
-                }
+                // Get all compilation units in scope (if not already collected via included paths)
+                if (units.isEmpty()) {
+                    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);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// 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);
}
}
}
}
}
// Get all compilation units in scope (if not already collected via included paths)
if (units.isEmpty()) {
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);
}
}
}
}
}
}
🤖 Prompt for AI Agents
In
java-analyzer-bundle.core/src/main/java/io/konveyor/tackle/core/internal/SampleDelegateCommandHandler.java
around lines 364-375, the code re-collects compilation units from all target
projects even when includedPaths already added units earlier, producing
duplicates and wasting resources; change the logic to skip this full-project
collection when units were already gathered from included fragments (e.g., check
a flag or whether includedPaths is non-null/non-empty or units is non-empty) so
the loop over all package fragments only runs if no units were previously
collected; optionally ensure the collection uses a Set or deduplication if you
must merge sources.


// 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());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Remove debug print statement.

The System.out.println statement should be replaced with proper logging using logInfo.

-                                System.out.println("Found in " + unit.getElementName());
+                                logInfo("Found on-demand import in " + unit.getElementName());
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
System.out.println("Found in " + unit.getElementName());
logInfo("Found on-demand import in " + unit.getElementName());
🤖 Prompt for AI Agents
In
java-analyzer-bundle.core/src/main/java/io/konveyor/tackle/core/internal/SampleDelegateCommandHandler.java
around line 384, replace the debug System.out.println("Found in " +
unit.getElementName()); with a proper logging call using logInfo; remove the
println and invoke logInfo with a clear message (e.g., "Found in " plus
unit.getElementName()) so the information is recorded via the project's logging
facility instead of standard output.

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;
}
}
}
}
Loading