diff --git a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/ProjectCommand.java b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/ProjectCommand.java index 86a82282..9d0009fb 100644 --- a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/ProjectCommand.java +++ b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/ProjectCommand.java @@ -44,7 +44,6 @@ import org.eclipse.core.runtime.MultiStatus; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.Path; -import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IModuleDescription; @@ -58,6 +57,7 @@ import org.eclipse.jdt.core.search.SearchPattern; import org.eclipse.jdt.core.search.SearchRequestor; import org.eclipse.jdt.launching.JavaRuntime; +import org.eclipse.jdt.ls.core.internal.JDTUtils; import org.eclipse.jdt.ls.core.internal.JavaLanguageServerPlugin; import org.eclipse.jdt.ls.core.internal.ProjectUtils; import org.eclipse.jdt.ls.core.internal.ResourceUtils; @@ -155,7 +155,7 @@ public String getMessage() { * Error context information for operations */ public static class ErrorContext { - public final String errorValue; // The value that caused the error (e.g., invalid URI, null parsedPath, etc.) + public final String errorValue; // The value that caused the error (e.g., invalid URI, null parsedPath, etc.) public ErrorContext(String errorValue) { this.errorValue = errorValue; @@ -491,7 +491,7 @@ public static ImportClassContentResult getImportClassContent(List argume // Record start time for timeout control long startTime = System.currentTimeMillis(); final long TIMEOUT_MS = 80; // 80ms timeout - + if (arguments == null || arguments.isEmpty()) { return new ImportClassContentResult(ImportClassContentErrorReason.NULL_ARGUMENTS); } @@ -501,43 +501,24 @@ public static ImportClassContentResult getImportClassContent(List argume if (fileUri == null || fileUri.trim().isEmpty()) { return new ImportClassContentResult(ImportClassContentErrorReason.INVALID_URI, fileUri); } - // Parse URI manually to avoid restricted API - java.net.URI uri = new java.net.URI(fileUri); - String filePath = uri.getPath(); - if (filePath == null) { - return new ImportClassContentResult(ImportClassContentErrorReason.URI_PARSE_FAILED, filePath); - } - IPath path = new Path(filePath); + // Directly resolve compilation unit from URI using JDTUtils + java.net.URI uri = JDTUtils.toURI(fileUri); + org.eclipse.jdt.core.ICompilationUnit compilationUnit = JDTUtils.resolveCompilationUnit(uri); - // Get the file resource - IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - IFile file = root.getFileForLocation(path); - if (file == null || !file.exists()) { - return new ImportClassContentResult(ImportClassContentErrorReason.FILE_NOT_FOUND, filePath); - } - if (!file.exists()) { - return new ImportClassContentResult(ImportClassContentErrorReason.FILE_NOT_EXISTS, filePath); + if (compilationUnit == null || !compilationUnit.exists()) { + return new ImportClassContentResult(ImportClassContentErrorReason.FILE_NOT_FOUND, fileUri); } - // Get the Java project - IJavaProject javaProject = JavaCore.create(file.getProject()); - if (javaProject == null) { - return new ImportClassContentResult(ImportClassContentErrorReason.NOT_JAVA_PROJECT, filePath); - } - if (!javaProject.exists()) { - String projectName = javaProject.getProject().getName(); + // Get the Java project from the compilation unit + IJavaProject javaProject = compilationUnit.getJavaProject(); + if (javaProject == null || !javaProject.exists()) { + String projectName = javaProject != null && javaProject.getProject() != null + ? javaProject.getProject().getName() + : "unknown"; return new ImportClassContentResult(ImportClassContentErrorReason.PROJECT_NOT_EXISTS, projectName); } - // Find the compilation unit - IJavaElement javaElement = JavaCore.create(file); - if (!(javaElement instanceof org.eclipse.jdt.core.ICompilationUnit)) { - return new ImportClassContentResult(ImportClassContentErrorReason.NOT_COMPILATION_UNIT, filePath); - } - - org.eclipse.jdt.core.ICompilationUnit compilationUnit = (org.eclipse.jdt.core.ICompilationUnit) javaElement; - // Parse imports and resolve local project files List classInfoList = new ArrayList<>(); @@ -580,15 +561,16 @@ public static ImportClassContentResult getImportClassContent(List argume // Check if we have exceeded the timeout before starting external resolution long currentTime = System.currentTimeMillis(); long elapsedTime = currentTime - startTime; - + if (elapsedTime >= TIMEOUT_MS) { // Return early due to timeout, but still return what we have collected so far if (classInfoList.isEmpty()) { - return new ImportClassContentResult(ImportClassContentErrorReason.TIME_LIMIT_EXCEEDED, String.valueOf(elapsedTime) + "ms"); + return new ImportClassContentResult(ImportClassContentErrorReason.TIME_LIMIT_EXCEEDED, + String.valueOf(elapsedTime) + "ms"); } return new ImportClassContentResult(classInfoList); } - + List externalClasses = new ArrayList<>(); for (org.eclipse.jdt.core.IImportDeclaration importDecl : imports) { @@ -596,12 +578,13 @@ public static ImportClassContentResult getImportClassContent(List argume if (monitor.isCanceled()) { break; } - + // Check timeout before each external resolution currentTime = System.currentTimeMillis(); elapsedTime = currentTime - startTime; if (elapsedTime >= TIMEOUT_MS) { - // Timeout reached, stop processing external dependencies but keep existing results + // Timeout reached, stop processing external dependencies but keep existing + // results break; } @@ -673,8 +656,9 @@ private static String getSeverityString(int severity) { * Get project dependencies information including JDK version. * * @param arguments List containing the file URI as the first element - * @param monitor Progress monitor for cancellation support - * @return List of DependencyInfo containing key-value pairs of project information + * @param monitor Progress monitor for cancellation support + * @return List of DependencyInfo containing key-value pairs of project + * information */ public static ProjectDependenciesResult getProjectDependencies(List arguments, IProgressMonitor monitor) { diff --git a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/parser/ContextResolver.java b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/parser/ContextResolver.java index ab063ef0..4adcef08 100644 --- a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/parser/ContextResolver.java +++ b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/parser/ContextResolver.java @@ -23,6 +23,7 @@ import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaModelException; +import org.eclipse.jdt.ls.core.internal.JDTUtils; import com.microsoft.jdtls.ext.core.JdtlsExtActivator; @@ -184,15 +185,19 @@ public static void resolveSingleType(IJavaProject javaProject, String typeName, if (packageFragment != null && packageFragment.exists()) { // Look for compilation unit with matching name org.eclipse.jdt.core.ICompilationUnit cu = packageFragment.getCompilationUnit(simpleName + ".java"); - if (cu != null && cu.exists() && cu.getResource() != null && cu.getResource().exists()) { - // Get primary type from compilation unit - org.eclipse.jdt.core.IType primaryType = cu.findPrimaryType(); - if (primaryType != null && primaryType.exists() && - typeName.equals(primaryType.getFullyQualifiedName())) { - // Found local project source type via fallback method - processedTypes.add(typeName); - extractTypeInfo(primaryType, classInfoList, monitor); - return; + if (cu != null && cu.exists()) { + // Use JDTUtils to check if the compilation unit is accessible + String cuUri = JDTUtils.toUri(cu); + if (cuUri != null) { + // Get primary type from compilation unit + org.eclipse.jdt.core.IType primaryType = cu.findPrimaryType(); + if (primaryType != null && primaryType.exists() && + typeName.equals(primaryType.getFullyQualifiedName())) { + // Found local project source type via fallback method + processedTypes.add(typeName); + extractTypeInfo(primaryType, classInfoList, monitor); + return; + } } // Also check for inner types in the compilation unit @@ -685,18 +690,19 @@ public static String getTypeUri(org.eclipse.jdt.core.IType type) { // Get the compilation unit that contains this type org.eclipse.jdt.core.ICompilationUnit compilationUnit = type.getCompilationUnit(); if (compilationUnit != null) { - // Get the underlying resource (file) - org.eclipse.core.resources.IResource resource = compilationUnit.getUnderlyingResource(); - if (resource != null && resource instanceof org.eclipse.core.resources.IFile) { - org.eclipse.core.resources.IFile file = (org.eclipse.core.resources.IFile) resource; - // Get the file location as a file URI - java.net.URI fileUri = file.getLocationURI(); - if (fileUri != null) { - return fileUri.toString(); - } - - // Fallback: use workspace-relative path as URI - return file.getFullPath().toString(); + // Use JDTUtils to get URI (consistent with other parts of the codebase) + String uri = JDTUtils.toUri(compilationUnit); + if (uri != null) { + return uri; + } + } + + // For class files (binary types), try to get URI from class file + org.eclipse.jdt.core.IClassFile classFile = type.getClassFile(); + if (classFile != null) { + String uri = JDTUtils.toUri(classFile); + if (uri != null) { + return uri; } } diff --git a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/parser/ProjectResolver.java b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/parser/ProjectResolver.java index b41aaa6c..f00c7b39 100644 --- a/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/parser/ProjectResolver.java +++ b/jdtls.ext/com.microsoft.jdtls.ext.core/src/com/microsoft/jdtls/ext/core/parser/ProjectResolver.java @@ -11,7 +11,6 @@ import org.eclipse.core.resources.IResourceChangeListener; import org.eclipse.core.resources.IResourceDelta; import org.eclipse.core.resources.IResourceDeltaVisitor; -import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; @@ -25,7 +24,7 @@ import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.launching.JavaRuntime; -import org.eclipse.jdt.ls.core.internal.ResourceUtils; +import org.eclipse.jdt.ls.core.internal.JDTUtils; import com.microsoft.jdtls.ext.core.JdtlsExtActivator; @@ -171,10 +170,9 @@ private static void invalidateCache(IProject project) { return; } - String projectPath = project.getLocation() != null ? - project.getLocation().toOSString() : project.getName(); + String projectUri = JDTUtils.getFileURI(project); - if (dependencyCache.remove(projectPath) != null) { + if (dependencyCache.remove(projectUri) != null) { JdtlsExtActivator.logInfo("Cache invalidated for project: " + project.getName()); } } @@ -214,7 +212,6 @@ private static long calculateClasspathHash(IJavaProject javaProject) { private static final String KEY_MODULE_NAME = "moduleName"; private static final String KEY_TOTAL_LIBRARIES = "totalLibraries"; private static final String KEY_TOTAL_PROJECT_REFS = "totalProjectReferences"; - private static final String KEY_JRE_CONTAINER_PATH = "jreContainerPath"; private static final String KEY_JRE_CONTAINER = "jreContainer"; public static class DependencyInfo { @@ -242,12 +239,16 @@ public static List resolveProjectDependencies(String fileUri, IP List result = new ArrayList<>(); try { - IPath fileIPath = ResourceUtils.canonicalFilePathFromURI(fileUri); + // Use JDTUtils to convert URI and find the resource + java.net.URI uri = JDTUtils.toURI(fileUri); + IResource resource = JDTUtils.findResource(uri, + ResourcesPlugin.getWorkspace().getRoot()::findFilesForLocationURI); - // Find the project - IWorkspaceRoot root = ResourcesPlugin.getWorkspace().getRoot(); - IProject project = findProjectByPath(root, fileIPath); + if (resource == null) { + return result; + } + IProject project = resource.getProject(); if (project == null || !project.isAccessible()) { return result; } @@ -258,8 +259,8 @@ public static List resolveProjectDependencies(String fileUri, IP return result; } - // Generate cache key based on project location - String cacheKey = project.getLocation().toOSString(); + // Generate cache key based on project URI + String cacheKey = JDTUtils.getFileURI(project); // Calculate current classpath hash for validation long currentClasspathHash = calculateClasspathHash(javaProject); @@ -290,44 +291,13 @@ public static List resolveProjectDependencies(String fileUri, IP return result; } - /** - * Find project by path from all projects in workspace. - * The path can be either a project root path or a file/folder path within a project. - * This method will find the project that contains the given path. - * - * @param root The workspace root - * @param filePath The path to search for (can be project root or file within project) - * @return The project that contains the path, or null if not found - */ - private static IProject findProjectByPath(IWorkspaceRoot root, IPath filePath) { - IProject[] allProjects = root.getProjects(); - - // First pass: check for exact project location match (most efficient) - for (IProject p : allProjects) { - if (p.getLocation() != null && p.getLocation().equals(filePath)) { - return p; - } - } - - // Second pass: check if the file path is within any project directory - // This handles cases where filePath points to a file or folder inside a project - for (IProject p : allProjects) { - if (p.getLocation() != null && p.getLocation().isPrefixOf(filePath)) { - return p; - } - } - - return null; - } - /** * Add basic project information including name, location, and Java version settings. */ private static void addBasicProjectInfo(List result, IProject project, IJavaProject javaProject) { result.add(new DependencyInfo(KEY_PROJECT_NAME, project.getName())); - addIfNotNull(result, KEY_PROJECT_LOCATION, - project.getLocation() != null ? project.getLocation().toOSString() : null); + addIfNotNull(result, KEY_PROJECT_LOCATION, JDTUtils.getFileURI(project)); addIfNotNull(result, KEY_JAVA_VERSION, javaProject.getOption(JavaCore.COMPILER_COMPLIANCE, true));