diff --git a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JDTUtils.java b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JDTUtils.java index a1b2baafa5..1bd6a6b2a8 100644 --- a/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JDTUtils.java +++ b/org.eclipse.jdt.ls.core/src/org/eclipse/jdt/ls/core/internal/JDTUtils.java @@ -27,6 +27,7 @@ import java.nio.file.InvalidPathException; import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -54,7 +55,6 @@ import org.eclipse.core.runtime.jobs.ISchedulingRule; import org.eclipse.jdt.core.CompletionProposal; import org.eclipse.jdt.core.Flags; - import org.eclipse.jdt.core.IAnnotatable; import org.eclipse.jdt.core.IAnnotation; import org.eclipse.jdt.core.IBuffer; @@ -70,6 +70,7 @@ import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IOpenable; import org.eclipse.jdt.core.IPackageFragment; +import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.ISourceRange; import org.eclipse.jdt.core.ISourceReference; import org.eclipse.jdt.core.IType; @@ -106,7 +107,6 @@ import org.eclipse.jdt.core.dom.SingleVariableDeclaration; import org.eclipse.jdt.core.dom.SuperConstructorInvocation; import org.eclipse.jdt.core.dom.Type; - import org.eclipse.jdt.core.dom.VariableDeclarationFragment; import org.eclipse.jdt.core.manipulation.CoreASTProvider; import org.eclipse.jdt.core.manipulation.SharedASTProviderCore; @@ -117,6 +117,7 @@ import org.eclipse.jdt.internal.compiler.lookup.Binding; import org.eclipse.jdt.internal.compiler.lookup.MethodBinding; import org.eclipse.jdt.internal.core.NamedMember; +import org.eclipse.jdt.internal.core.PackageFragmentRoot; import org.eclipse.jdt.internal.core.manipulation.JavaElementLabelComposerCore; import org.eclipse.jdt.internal.core.manipulation.JavaElementLabelsCore; import org.eclipse.jdt.internal.core.manipulation.search.IOccurrencesFinder.OccurrenceLocation; @@ -1142,7 +1143,7 @@ public static IResource findResource(URI uri, Function resourc if (uri == null || !"file".equals(uri.getScheme())) { return null; } - IResource[] resources = resourceFinder.apply(uri); + IResource[] resources = resourceFinder.apply(uri); if (resources.length == 0) { //On Mac, Linked resources are referenced via the "real" URI, i.e file://USERS/username/... //instead of file://Users/username/..., so we check against that real URI. @@ -1165,7 +1166,7 @@ public static IResource findResource(URI uri, Function resourc } resources = resourceFinder.apply(uri); } - } + } switch(resources.length) { case 0: return null; @@ -1173,7 +1174,7 @@ public static IResource findResource(URI uri, Function resourc return resources[0]; default://several candidates if a linked resource was created before the real project was configured IResource resource = null; - for (IResource f : resources) { + for (IResource f : resources) { //delete linked resource if (JavaLanguageServerPlugin.getProjectsManager().getDefaultProject().equals(f.getProject())) { try { @@ -1182,15 +1183,38 @@ public static IResource findResource(URI uri, Function resourc JavaLanguageServerPlugin.logException(e.getMessage(), e); } } + //find closest project containing that file, in case of nested projects - if (resource == null || f.getProjectRelativePath().segmentCount() < resource.getProjectRelativePath().segmentCount()) { - resource = f; + //ignore files outside a source folder (https://github.com/eclipse-jdtls/eclipse.jdt.ls/issues/3447) + if (hasPackageFragmentRoot(f) + && (resource == null || f.getProjectRelativePath().segmentCount() < resource.getProjectRelativePath().segmentCount())) { + resource = f; } } return resource; } } + private static boolean hasPackageFragmentRoot(IResource resource) { + ICompilationUnit unit = resolveCompilationUnit((IFile)resource); + if (unit == null || unit.getJavaProject() == null) { + return false; + } + try {; + IPath path = unit.getPath(); + + IPackageFragmentRoot[] packageFragmentRoots = unit.getJavaProject().getPackageFragmentRoots(); + boolean containsPackageFragmentRoot = Arrays.stream(packageFragmentRoots) + .anyMatch(root -> root.getClass().equals(PackageFragmentRoot.class) + && packageFragmentRoots[0].getPath().isPrefixOf(path)); + + return containsPackageFragmentRoot; + } catch (JavaModelException e) { + JavaLanguageServerPlugin.log(e); + return false; + } + } + public static URI toURI(String uriString) { if (uriString == null || uriString.isEmpty()) { return null; diff --git a/org.eclipse.jdt.ls.tests/projects/maven/nested-project/.classpath b/org.eclipse.jdt.ls.tests/projects/maven/nested-project/.classpath new file mode 100644 index 0000000000..a599464fba --- /dev/null +++ b/org.eclipse.jdt.ls.tests/projects/maven/nested-project/.classpath @@ -0,0 +1,5 @@ + + + + + diff --git a/org.eclipse.jdt.ls.tests/projects/maven/nested-project/.eclipse/projects/mypackage_mytarget/.classpath b/org.eclipse.jdt.ls.tests/projects/maven/nested-project/.eclipse/projects/mypackage_mytarget/.classpath new file mode 100644 index 0000000000..f27a6fd36d --- /dev/null +++ b/org.eclipse.jdt.ls.tests/projects/maven/nested-project/.eclipse/projects/mypackage_mytarget/.classpath @@ -0,0 +1,6 @@ + + + + + + diff --git a/org.eclipse.jdt.ls.tests/projects/maven/nested-project/.eclipse/projects/mypackage_mytarget/.project b/org.eclipse.jdt.ls.tests/projects/maven/nested-project/.eclipse/projects/mypackage_mytarget/.project new file mode 100644 index 0000000000..807d951ffe --- /dev/null +++ b/org.eclipse.jdt.ls.tests/projects/maven/nested-project/.eclipse/projects/mypackage_mytarget/.project @@ -0,0 +1,41 @@ + + + mypackage_mytarget + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + org.eclipse.jdt.core.javanature + + + + linked-srcs/com/packages/foo/File.java + 1 + PARENT-3-PROJECT_LOC/com/packages/foo/File.java + + + + + 1748456351890 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + + diff --git a/org.eclipse.jdt.ls.tests/projects/maven/nested-project/.eclipse/projects/mypackage_mytarget/eclipse-bin/com/packages/foo/File.class b/org.eclipse.jdt.ls.tests/projects/maven/nested-project/.eclipse/projects/mypackage_mytarget/eclipse-bin/com/packages/foo/File.class new file mode 100644 index 0000000000..7740a6eff0 Binary files /dev/null and b/org.eclipse.jdt.ls.tests/projects/maven/nested-project/.eclipse/projects/mypackage_mytarget/eclipse-bin/com/packages/foo/File.class differ diff --git a/org.eclipse.jdt.ls.tests/projects/maven/nested-project/.project b/org.eclipse.jdt.ls.tests/projects/maven/nested-project/.project new file mode 100644 index 0000000000..a657f9636b --- /dev/null +++ b/org.eclipse.jdt.ls.tests/projects/maven/nested-project/.project @@ -0,0 +1,34 @@ + + + workspace_root + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + org.eclipse.jdt.core.javanature + + + + 1748456351890 + + 30 + + org.eclipse.core.resources.regexFilterMatcher + node_modules|\.git|__CREATED_BY_JAVA_LANGUAGE_SERVER__ + + + + diff --git a/org.eclipse.jdt.ls.tests/projects/maven/nested-project/com/packages/foo/File.java b/org.eclipse.jdt.ls.tests/projects/maven/nested-project/com/packages/foo/File.java new file mode 100644 index 0000000000..93aaa238cd --- /dev/null +++ b/org.eclipse.jdt.ls.tests/projects/maven/nested-project/com/packages/foo/File.java @@ -0,0 +1,9 @@ +package com.packages.foo; + +public class File +{ + public static void main(String[] args) + { + System.out.println("Hello, World"); + } +} \ No newline at end of file