Skip to content

Commit 698593c

Browse files
authored
fix: leverage jdtutils to get project correct (#940)
* fix: leverage jdtutils to get project filepath * fix: update in project resolver * fix: update * fix: update
1 parent 3effb19 commit 698593c

File tree

3 files changed

+65
-105
lines changed

3 files changed

+65
-105
lines changed

jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/ProjectCommand.java

Lines changed: 24 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
import org.eclipse.core.runtime.MultiStatus;
4545
import org.eclipse.core.runtime.OperationCanceledException;
4646
import org.eclipse.core.runtime.Path;
47-
import org.eclipse.jdt.core.IJavaElement;
4847
import org.eclipse.jdt.core.IJavaProject;
4948
import org.eclipse.jdt.core.IMethod;
5049
import org.eclipse.jdt.core.IModuleDescription;
@@ -58,6 +57,7 @@
5857
import org.eclipse.jdt.core.search.SearchPattern;
5958
import org.eclipse.jdt.core.search.SearchRequestor;
6059
import org.eclipse.jdt.launching.JavaRuntime;
60+
import org.eclipse.jdt.ls.core.internal.JDTUtils;
6161
import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin;
6262
import org.eclipse.jdt.ls.core.internal.ProjectUtils;
6363
import org.eclipse.jdt.ls.core.internal.ResourceUtils;
@@ -155,7 +155,7 @@ public String getMessage() {
155155
* Error context information for operations
156156
*/
157157
public static class ErrorContext {
158-
public final String errorValue; // The value that caused the error (e.g., invalid URI, null parsedPath, etc.)
158+
public final String errorValue; // The value that caused the error (e.g., invalid URI, null parsedPath, etc.)
159159

160160
public ErrorContext(String errorValue) {
161161
this.errorValue = errorValue;
@@ -491,7 +491,7 @@ public static ImportClassContentResult getImportClassContent(List<Object> argume
491491
// Record start time for timeout control
492492
long startTime = System.currentTimeMillis();
493493
final long TIMEOUT_MS = 80; // 80ms timeout
494-
494+
495495
if (arguments == null || arguments.isEmpty()) {
496496
return new ImportClassContentResult(ImportClassContentErrorReason.NULL_ARGUMENTS);
497497
}
@@ -501,43 +501,24 @@ public static ImportClassContentResult getImportClassContent(List<Object> argume
501501
if (fileUri == null || fileUri.trim().isEmpty()) {
502502
return new ImportClassContentResult(ImportClassContentErrorReason.INVALID_URI, fileUri);
503503
}
504-
// Parse URI manually to avoid restricted API
505-
java.net.URI uri = new java.net.URI(fileUri);
506-
String filePath = uri.getPath();
507-
if (filePath == null) {
508-
return new ImportClassContentResult(ImportClassContentErrorReason.URI_PARSE_FAILED, filePath);
509-
}
510504

511-
IPath path = new Path(filePath);
505+
// Directly resolve compilation unit from URI using JDTUtils
506+
java.net.URI uri = JDTUtils.toURI(fileUri);
507+
org.eclipse.jdt.core.ICompilationUnit compilationUnit = JDTUtils.resolveCompilationUnit(uri);
512508

513-
// Get the file resource
514-
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
515-
IFile file = root.getFileForLocation(path);
516-
if (file == null || !file.exists()) {
517-
return new ImportClassContentResult(ImportClassContentErrorReason.FILE_NOT_FOUND, filePath);
518-
}
519-
if (!file.exists()) {
520-
return new ImportClassContentResult(ImportClassContentErrorReason.FILE_NOT_EXISTS, filePath);
509+
if (compilationUnit == null || !compilationUnit.exists()) {
510+
return new ImportClassContentResult(ImportClassContentErrorReason.FILE_NOT_FOUND, fileUri);
521511
}
522512

523-
// Get the Java project
524-
IJavaProject javaProject = JavaCore.create(file.getProject());
525-
if (javaProject == null) {
526-
return new ImportClassContentResult(ImportClassContentErrorReason.NOT_JAVA_PROJECT, filePath);
527-
}
528-
if (!javaProject.exists()) {
529-
String projectName = javaProject.getProject().getName();
513+
// Get the Java project from the compilation unit
514+
IJavaProject javaProject = compilationUnit.getJavaProject();
515+
if (javaProject == null || !javaProject.exists()) {
516+
String projectName = javaProject != null && javaProject.getProject() != null
517+
? javaProject.getProject().getName()
518+
: "unknown";
530519
return new ImportClassContentResult(ImportClassContentErrorReason.PROJECT_NOT_EXISTS, projectName);
531520
}
532521

533-
// Find the compilation unit
534-
IJavaElement javaElement = JavaCore.create(file);
535-
if (!(javaElement instanceof org.eclipse.jdt.core.ICompilationUnit)) {
536-
return new ImportClassContentResult(ImportClassContentErrorReason.NOT_COMPILATION_UNIT, filePath);
537-
}
538-
539-
org.eclipse.jdt.core.ICompilationUnit compilationUnit = (org.eclipse.jdt.core.ICompilationUnit) javaElement;
540-
541522
// Parse imports and resolve local project files
542523
List<ImportClassInfo> classInfoList = new ArrayList<>();
543524

@@ -580,28 +561,30 @@ public static ImportClassContentResult getImportClassContent(List<Object> argume
580561
// Check if we have exceeded the timeout before starting external resolution
581562
long currentTime = System.currentTimeMillis();
582563
long elapsedTime = currentTime - startTime;
583-
564+
584565
if (elapsedTime >= TIMEOUT_MS) {
585566
// Return early due to timeout, but still return what we have collected so far
586567
if (classInfoList.isEmpty()) {
587-
return new ImportClassContentResult(ImportClassContentErrorReason.TIME_LIMIT_EXCEEDED, String.valueOf(elapsedTime) + "ms");
568+
return new ImportClassContentResult(ImportClassContentErrorReason.TIME_LIMIT_EXCEEDED,
569+
String.valueOf(elapsedTime) + "ms");
588570
}
589571
return new ImportClassContentResult(classInfoList);
590572
}
591-
573+
592574
List<ImportClassInfo> externalClasses = new ArrayList<>();
593575

594576
for (org.eclipse.jdt.core.IImportDeclaration importDecl : imports) {
595577
// Check cancellation before each external resolution
596578
if (monitor.isCanceled()) {
597579
break;
598580
}
599-
581+
600582
// Check timeout before each external resolution
601583
currentTime = System.currentTimeMillis();
602584
elapsedTime = currentTime - startTime;
603585
if (elapsedTime >= TIMEOUT_MS) {
604-
// Timeout reached, stop processing external dependencies but keep existing results
586+
// Timeout reached, stop processing external dependencies but keep existing
587+
// results
605588
break;
606589
}
607590

@@ -673,8 +656,9 @@ private static String getSeverityString(int severity) {
673656
* Get project dependencies information including JDK version.
674657
*
675658
* @param arguments List containing the file URI as the first element
676-
* @param monitor Progress monitor for cancellation support
677-
* @return List of DependencyInfo containing key-value pairs of project information
659+
* @param monitor Progress monitor for cancellation support
660+
* @return List of DependencyInfo containing key-value pairs of project
661+
* information
678662
*/
679663
public static ProjectDependenciesResult getProjectDependencies(List<Object> arguments,
680664
IProgressMonitor monitor) {

jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/parser/ContextResolver.java

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import org.eclipse.jdt.core.IPackageFragmentRoot;
2424
import org.eclipse.jdt.core.IJavaProject;
2525
import org.eclipse.jdt.core.JavaModelException;
26+
import org.eclipse.jdt.ls.core.internal.JDTUtils;
2627

2728
import com.microsoft.jdtls.ext.core.JdtlsExtActivator;
2829

@@ -184,15 +185,19 @@ public static void resolveSingleType(IJavaProject javaProject, String typeName,
184185
if (packageFragment != null && packageFragment.exists()) {
185186
// Look for compilation unit with matching name
186187
org.eclipse.jdt.core.ICompilationUnit cu = packageFragment.getCompilationUnit(simpleName + ".java");
187-
if (cu != null && cu.exists() && cu.getResource() != null && cu.getResource().exists()) {
188-
// Get primary type from compilation unit
189-
org.eclipse.jdt.core.IType primaryType = cu.findPrimaryType();
190-
if (primaryType != null && primaryType.exists() &&
191-
typeName.equals(primaryType.getFullyQualifiedName())) {
192-
// Found local project source type via fallback method
193-
processedTypes.add(typeName);
194-
extractTypeInfo(primaryType, classInfoList, monitor);
195-
return;
188+
if (cu != null && cu.exists()) {
189+
// Use JDTUtils to check if the compilation unit is accessible
190+
String cuUri = JDTUtils.toUri(cu);
191+
if (cuUri != null) {
192+
// Get primary type from compilation unit
193+
org.eclipse.jdt.core.IType primaryType = cu.findPrimaryType();
194+
if (primaryType != null && primaryType.exists() &&
195+
typeName.equals(primaryType.getFullyQualifiedName())) {
196+
// Found local project source type via fallback method
197+
processedTypes.add(typeName);
198+
extractTypeInfo(primaryType, classInfoList, monitor);
199+
return;
200+
}
196201
}
197202

198203
// Also check for inner types in the compilation unit
@@ -685,18 +690,19 @@ public static String getTypeUri(org.eclipse.jdt.core.IType type) {
685690
// Get the compilation unit that contains this type
686691
org.eclipse.jdt.core.ICompilationUnit compilationUnit = type.getCompilationUnit();
687692
if (compilationUnit != null) {
688-
// Get the underlying resource (file)
689-
org.eclipse.core.resources.IResource resource = compilationUnit.getUnderlyingResource();
690-
if (resource != null && resource instanceof org.eclipse.core.resources.IFile) {
691-
org.eclipse.core.resources.IFile file = (org.eclipse.core.resources.IFile) resource;
692-
// Get the file location as a file URI
693-
java.net.URI fileUri = file.getLocationURI();
694-
if (fileUri != null) {
695-
return fileUri.toString();
696-
}
697-
698-
// Fallback: use workspace-relative path as URI
699-
return file.getFullPath().toString();
693+
// Use JDTUtils to get URI (consistent with other parts of the codebase)
694+
String uri = JDTUtils.toUri(compilationUnit);
695+
if (uri != null) {
696+
return uri;
697+
}
698+
}
699+
700+
// For class files (binary types), try to get URI from class file
701+
org.eclipse.jdt.core.IClassFile classFile = type.getClassFile();
702+
if (classFile != null) {
703+
String uri = JDTUtils.toUri(classFile);
704+
if (uri != null) {
705+
return uri;
700706
}
701707
}
702708

jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/parser/ProjectResolver.java

Lines changed: 14 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
import org.eclipse.core.resources.IResourceChangeListener;
1212
import org.eclipse.core.resources.IResourceDelta;
1313
import org.eclipse.core.resources.IResourceDeltaVisitor;
14-
import org.eclipse.core.resources.IWorkspaceRoot;
1514
import org.eclipse.core.resources.ResourcesPlugin;
1615
import org.eclipse.core.runtime.CoreException;
1716
import org.eclipse.core.runtime.IPath;
@@ -25,7 +24,7 @@
2524
import org.eclipse.jdt.core.JavaCore;
2625
import org.eclipse.jdt.core.JavaModelException;
2726
import org.eclipse.jdt.launching.JavaRuntime;
28-
import org.eclipse.jdt.ls.core.internal.ResourceUtils;
27+
import org.eclipse.jdt.ls.core.internal.JDTUtils;
2928

3029
import com.microsoft.jdtls.ext.core.JdtlsExtActivator;
3130

@@ -171,10 +170,9 @@ private static void invalidateCache(IProject project) {
171170
return;
172171
}
173172

174-
String projectPath = project.getLocation() != null ?
175-
project.getLocation().toOSString() : project.getName();
173+
String projectUri = JDTUtils.getFileURI(project);
176174

177-
if (dependencyCache.remove(projectPath) != null) {
175+
if (dependencyCache.remove(projectUri) != null) {
178176
JdtlsExtActivator.logInfo("Cache invalidated for project: " + project.getName());
179177
}
180178
}
@@ -214,7 +212,6 @@ private static long calculateClasspathHash(IJavaProject javaProject) {
214212
private static final String KEY_MODULE_NAME = "moduleName";
215213
private static final String KEY_TOTAL_LIBRARIES = "totalLibraries";
216214
private static final String KEY_TOTAL_PROJECT_REFS = "totalProjectReferences";
217-
private static final String KEY_JRE_CONTAINER_PATH = "jreContainerPath";
218215
private static final String KEY_JRE_CONTAINER = "jreContainer";
219216

220217
public static class DependencyInfo {
@@ -242,12 +239,16 @@ public static List<DependencyInfo> resolveProjectDependencies(String fileUri, IP
242239
List<DependencyInfo> result = new ArrayList<>();
243240

244241
try {
245-
IPath fileIPath = ResourceUtils.canonicalFilePathFromURI(fileUri);
242+
// Use JDTUtils to convert URI and find the resource
243+
java.net.URI uri = JDTUtils.toURI(fileUri);
244+
IResource resource = JDTUtils.findResource(uri,
245+
ResourcesPlugin.getWorkspace().getRoot()::findFilesForLocationURI);
246246

247-
// Find the project
248-
IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot();
249-
IProject project = findProjectByPath(root, fileIPath);
247+
if (resource == null) {
248+
return result;
249+
}
250250

251+
IProject project = resource.getProject();
251252
if (project == null || !project.isAccessible()) {
252253
return result;
253254
}
@@ -258,8 +259,8 @@ public static List<DependencyInfo> resolveProjectDependencies(String fileUri, IP
258259
return result;
259260
}
260261

261-
// Generate cache key based on project location
262-
String cacheKey = project.getLocation().toOSString();
262+
// Generate cache key based on project URI
263+
String cacheKey = JDTUtils.getFileURI(project);
263264

264265
// Calculate current classpath hash for validation
265266
long currentClasspathHash = calculateClasspathHash(javaProject);
@@ -290,44 +291,13 @@ public static List<DependencyInfo> resolveProjectDependencies(String fileUri, IP
290291
return result;
291292
}
292293

293-
/**
294-
* Find project by path from all projects in workspace.
295-
* The path can be either a project root path or a file/folder path within a project.
296-
* This method will find the project that contains the given path.
297-
*
298-
* @param root The workspace root
299-
* @param filePath The path to search for (can be project root or file within project)
300-
* @return The project that contains the path, or null if not found
301-
*/
302-
private static IProject findProjectByPath(IWorkspaceRoot root, IPath filePath) {
303-
IProject[] allProjects = root.getProjects();
304-
305-
// First pass: check for exact project location match (most efficient)
306-
for (IProject p : allProjects) {
307-
if (p.getLocation() != null && p.getLocation().equals(filePath)) {
308-
return p;
309-
}
310-
}
311-
312-
// Second pass: check if the file path is within any project directory
313-
// This handles cases where filePath points to a file or folder inside a project
314-
for (IProject p : allProjects) {
315-
if (p.getLocation() != null && p.getLocation().isPrefixOf(filePath)) {
316-
return p;
317-
}
318-
}
319-
320-
return null;
321-
}
322-
323294
/**
324295
* Add basic project information including name, location, and Java version settings.
325296
*/
326297
private static void addBasicProjectInfo(List<DependencyInfo> result, IProject project, IJavaProject javaProject) {
327298
result.add(new DependencyInfo(KEY_PROJECT_NAME, project.getName()));
328299

329-
addIfNotNull(result, KEY_PROJECT_LOCATION,
330-
project.getLocation() != null ? project.getLocation().toOSString() : null);
300+
addIfNotNull(result, KEY_PROJECT_LOCATION, JDTUtils.getFileURI(project));
331301

332302
addIfNotNull(result, KEY_JAVA_VERSION,
333303
javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true));

0 commit comments

Comments
 (0)