Skip to content
Merged
Show file tree
Hide file tree
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
1 change: 1 addition & 0 deletions jdtls.ext/com.microsoft.jdtls.ext.core/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<command id="java.project.generateJar" />
<command id="java.project.checkImportStatus" />
<command id="java.project.getImportClassContent" />
<command id="java.project.getDependencies" />
</delegateCommandHandler>
</extension>
<extension
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public Object executeCommand(String commandId, List<Object> arguments, IProgress
return ProjectCommand.checkImportStatus();
case "java.project.getImportClassContent":
return ProjectCommand.getImportClassContent(arguments, monitor);
case "java.project.getDependencies":
return ProjectCommand.getProjectDependencies(arguments, monitor);
default:
break;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
import com.google.gson.GsonBuilder;
import com.microsoft.jdtls.ext.core.parser.ContextResolver;
import com.microsoft.jdtls.ext.core.parser.ContextResolver.ImportClassInfo;
import com.microsoft.jdtls.ext.core.parser.ProjectResolver;
import com.microsoft.jdtls.ext.core.model.PackageNode;

public final class ProjectCommand {
Expand All @@ -87,7 +88,15 @@ public MainClassInfo(String name, String path) {
}
}

private static class DependencyInfo {
public String key;
public String value;

public DependencyInfo(String key, String value) {
this.key = key;
this.value = value;
}
}

private static class Classpath {
public String source;
Expand Down Expand Up @@ -344,6 +353,7 @@ public static boolean checkImportStatus() {
/**
* Get import class content for Copilot integration.
* This method extracts information about imported classes from a Java file.
* Uses a time-controlled strategy: prioritizes internal classes, adds external classes only if time permits.
*
* @param arguments List containing the file URI as the first element
* @param monitor Progress monitor for cancellation support
Expand All @@ -354,6 +364,11 @@ public static List<ImportClassInfo> getImportClassContent(List<Object> arguments
return Collections.emptyList();
}

// Time control: total budget 80ms, early return at 75ms
long startTime = System.currentTimeMillis();
final long TIME_BUDGET_MS = 80;
final long EARLY_RETURN_MS = 75;

try {
String fileUri = (String) arguments.get(0);

Expand Down Expand Up @@ -388,16 +403,18 @@ public static List<ImportClassInfo> getImportClassContent(List<Object> arguments
org.eclipse.jdt.core.ICompilationUnit compilationUnit = (org.eclipse.jdt.core.ICompilationUnit) javaElement;

// Parse imports and resolve local project files
// Delegate to JavaContentParser for processing
List<ImportClassInfo> classInfoList = new ArrayList<>();

// Get all imports from the compilation unit
org.eclipse.jdt.core.IImportDeclaration[] imports = compilationUnit.getImports();
Set<String> processedTypes = new HashSet<>();

// Phase 1: Priority - Resolve project source classes (internal)
for (org.eclipse.jdt.core.IImportDeclaration importDecl : imports) {
if (monitor.isCanceled()) {
break;
// Check time budget before each operation
long elapsed = System.currentTimeMillis() - startTime;
if (monitor.isCanceled() || elapsed >= EARLY_RETURN_MS) {
return classInfoList; // Early return if approaching time limit
}

String importName = importDecl.getElementName();
Expand All @@ -416,6 +433,43 @@ public static List<ImportClassInfo> getImportClassContent(List<Object> arguments
}
}

// Phase 2: If time permits, resolve external dependencies
long elapsedAfterInternal = System.currentTimeMillis() - startTime;
if (elapsedAfterInternal < EARLY_RETURN_MS && !monitor.isCanceled()) {
// Calculate remaining time budget for external classes
long remainingTime = TIME_BUDGET_MS - elapsedAfterInternal;

// Only proceed with external if we have reasonable time left (at least 15ms)
if (remainingTime >= 15) {
List<ImportClassInfo> externalClasses = new ArrayList<>();

for (org.eclipse.jdt.core.IImportDeclaration importDecl : imports) {
// Check time before each external resolution
long currentElapsed = System.currentTimeMillis() - startTime;
if (monitor.isCanceled() || currentElapsed >= EARLY_RETURN_MS) {
break;
}

String importName = importDecl.getElementName();
boolean isStatic = (importDecl.getFlags() & org.eclipse.jdt.core.Flags.AccStatic) != 0;

// Skip package imports (*.* ) - too broad for external dependencies
if (importName.endsWith(".*")) {
continue;
}

// Resolve external (binary) types with simplified content
if (!isStatic) {
ContextResolver.resolveBinaryType(javaProject, importName, externalClasses,
processedTypes, Integer.MAX_VALUE, monitor);
}
}

// Append external classes after project sources
classInfoList.addAll(externalClasses);
}
}

return classInfoList;

} catch (Exception e) {
Expand Down Expand Up @@ -449,6 +503,30 @@ private static String getSeverityString(int severity) {
}
}

/**
* Get project dependencies information including JDK version.
*
* @param arguments List containing the project URI as the first element
* @param monitor Progress monitor for cancellation support
* @return List of DependencyInfo containing key-value pairs of project information
*/
public static List<DependencyInfo> getProjectDependencies(List<Object> arguments, IProgressMonitor monitor) {
if (arguments == null || arguments.isEmpty()) {
return new ArrayList<>();
}

String projectUri = (String) arguments.get(0);
List<ProjectResolver.DependencyInfo> resolverResult = ProjectResolver.resolveProjectDependencies(projectUri, monitor);

// Convert ProjectResolver.DependencyInfo to ProjectCommand.DependencyInfo
List<DependencyInfo> result = new ArrayList<>();
for (ProjectResolver.DependencyInfo info : resolverResult) {
result.add(new DependencyInfo(info.key, info.value));
}

return result;
}

private static final class LinkedFolderVisitor implements IResourceVisitor {

private boolean belongsToWorkspace;
Expand Down
Loading
Loading