7171import com .google .gson .GsonBuilder ;
7272import com .microsoft .jdtls .ext .core .parser .ContextResolver ;
7373import com .microsoft .jdtls .ext .core .parser .ContextResolver .ImportClassInfo ;
74+ import com .microsoft .jdtls .ext .core .parser .ProjectResolver ;
7475import com .microsoft .jdtls .ext .core .model .PackageNode ;
7576
7677public final class ProjectCommand {
@@ -87,7 +88,15 @@ public MainClassInfo(String name, String path) {
8788 }
8889 }
8990
91+ private static class DependencyInfo {
92+ public String key ;
93+ public String value ;
9094
95+ public DependencyInfo (String key , String value ) {
96+ this .key = key ;
97+ this .value = value ;
98+ }
99+ }
91100
92101 private static class Classpath {
93102 public String source ;
@@ -344,6 +353,7 @@ public static boolean checkImportStatus() {
344353 /**
345354 * Get import class content for Copilot integration.
346355 * This method extracts information about imported classes from a Java file.
356+ * Uses a time-controlled strategy: prioritizes internal classes, adds external classes only if time permits.
347357 *
348358 * @param arguments List containing the file URI as the first element
349359 * @param monitor Progress monitor for cancellation support
@@ -354,6 +364,11 @@ public static List<ImportClassInfo> getImportClassContent(List<Object> arguments
354364 return Collections .emptyList ();
355365 }
356366
367+ // Time control: total budget 80ms, early return at 75ms
368+ long startTime = System .currentTimeMillis ();
369+ final long TIME_BUDGET_MS = 80 ;
370+ final long EARLY_RETURN_MS = 75 ;
371+
357372 try {
358373 String fileUri = (String ) arguments .get (0 );
359374
@@ -388,16 +403,18 @@ public static List<ImportClassInfo> getImportClassContent(List<Object> arguments
388403 org .eclipse .jdt .core .ICompilationUnit compilationUnit = (org .eclipse .jdt .core .ICompilationUnit ) javaElement ;
389404
390405 // Parse imports and resolve local project files
391- // Delegate to JavaContentParser for processing
392406 List <ImportClassInfo > classInfoList = new ArrayList <>();
393407
394408 // Get all imports from the compilation unit
395409 org .eclipse .jdt .core .IImportDeclaration [] imports = compilationUnit .getImports ();
396410 Set <String > processedTypes = new HashSet <>();
397411
412+ // Phase 1: Priority - Resolve project source classes (internal)
398413 for (org .eclipse .jdt .core .IImportDeclaration importDecl : imports ) {
399- if (monitor .isCanceled ()) {
400- break ;
414+ // Check time budget before each operation
415+ long elapsed = System .currentTimeMillis () - startTime ;
416+ if (monitor .isCanceled () || elapsed >= EARLY_RETURN_MS ) {
417+ return classInfoList ; // Early return if approaching time limit
401418 }
402419
403420 String importName = importDecl .getElementName ();
@@ -416,6 +433,43 @@ public static List<ImportClassInfo> getImportClassContent(List<Object> arguments
416433 }
417434 }
418435
436+ // Phase 2: If time permits, resolve external dependencies
437+ long elapsedAfterInternal = System .currentTimeMillis () - startTime ;
438+ if (elapsedAfterInternal < EARLY_RETURN_MS && !monitor .isCanceled ()) {
439+ // Calculate remaining time budget for external classes
440+ long remainingTime = TIME_BUDGET_MS - elapsedAfterInternal ;
441+
442+ // Only proceed with external if we have reasonable time left (at least 15ms)
443+ if (remainingTime >= 15 ) {
444+ List <ImportClassInfo > externalClasses = new ArrayList <>();
445+
446+ for (org .eclipse .jdt .core .IImportDeclaration importDecl : imports ) {
447+ // Check time before each external resolution
448+ long currentElapsed = System .currentTimeMillis () - startTime ;
449+ if (monitor .isCanceled () || currentElapsed >= EARLY_RETURN_MS ) {
450+ break ;
451+ }
452+
453+ String importName = importDecl .getElementName ();
454+ boolean isStatic = (importDecl .getFlags () & org .eclipse .jdt .core .Flags .AccStatic ) != 0 ;
455+
456+ // Skip package imports (*.* ) - too broad for external dependencies
457+ if (importName .endsWith (".*" )) {
458+ continue ;
459+ }
460+
461+ // Resolve external (binary) types with simplified content
462+ if (!isStatic ) {
463+ ContextResolver .resolveBinaryType (javaProject , importName , externalClasses ,
464+ processedTypes , Integer .MAX_VALUE , monitor );
465+ }
466+ }
467+
468+ // Append external classes after project sources
469+ classInfoList .addAll (externalClasses );
470+ }
471+ }
472+
419473 return classInfoList ;
420474
421475 } catch (Exception e ) {
@@ -449,6 +503,30 @@ private static String getSeverityString(int severity) {
449503 }
450504 }
451505
506+ /**
507+ * Get project dependencies information including JDK version.
508+ *
509+ * @param arguments List containing the project URI as the first element
510+ * @param monitor Progress monitor for cancellation support
511+ * @return List of DependencyInfo containing key-value pairs of project information
512+ */
513+ public static List <DependencyInfo > getProjectDependencies (List <Object > arguments , IProgressMonitor monitor ) {
514+ if (arguments == null || arguments .isEmpty ()) {
515+ return new ArrayList <>();
516+ }
517+
518+ String projectUri = (String ) arguments .get (0 );
519+ List <ProjectResolver .DependencyInfo > resolverResult = ProjectResolver .resolveProjectDependencies (projectUri , monitor );
520+
521+ // Convert ProjectResolver.DependencyInfo to ProjectCommand.DependencyInfo
522+ List <DependencyInfo > result = new ArrayList <>();
523+ for (ProjectResolver .DependencyInfo info : resolverResult ) {
524+ result .add (new DependencyInfo (info .key , info .value ));
525+ }
526+
527+ return result ;
528+ }
529+
452530 private static final class LinkedFolderVisitor implements IResourceVisitor {
453531
454532 private boolean belongsToWorkspace ;
0 commit comments