diff --git a/java/java-psi-impl/src/com/intellij/core/CoreJavaFileManager.java b/java/java-psi-impl/src/com/intellij/core/CoreJavaFileManager.java index 1df60969e17e..dd3904097351 100644 --- a/java/java-psi-impl/src/com/intellij/core/CoreJavaFileManager.java +++ b/java/java-psi-impl/src/com/intellij/core/CoreJavaFileManager.java @@ -26,10 +26,7 @@ import com.intellij.psi.search.GlobalSearchScope; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; +import java.util.*; /** * @author yole @@ -138,36 +135,48 @@ public class CoreJavaFileManager implements JavaFileManager { if (classes.length == 1) { PsiClass curClass = classes[0]; - if (bucks > 0) { - int newComponentStart = 0; - int lookupStart = 0; + if (bucks > 0) { + Stack currentPath = new Stack(); + currentPath.add(new ClassAndOffsets(curClass, 0, 0)); + currentPath.add(currentPath.peek()); - while (lookupStart <= className.length()) { - int b = className.indexOf("$", lookupStart); - b = b < 0 ? className.length(): b; + while (currentPath.size() > 1) { + ClassAndOffsets classAndOffset = currentPath.pop(); + int newComponentStart = classAndOffset.componentStart; + int lookupStart = classAndOffset.lookupStart; + curClass = currentPath.peek().clazz; //owner class - String component = className.substring(newComponentStart, b); - PsiClass inner = curClass.findInnerClassByName(component, false); + while (lookupStart <= className.length()) { + int bucksIndex = className.indexOf("$", lookupStart); + bucksIndex = bucksIndex < 0 ? className.length(): bucksIndex; - lookupStart = b + 1; - if (inner == null) { - continue; + String component = className.substring(newComponentStart, bucksIndex); + PsiClass inner = curClass.findInnerClassByName(component, false); + + lookupStart = bucksIndex + 1; + if (inner == null) { + continue; + } + + currentPath.add(new ClassAndOffsets(inner, newComponentStart, lookupStart)); + + newComponentStart = lookupStart; + curClass = inner; + } + + if (lookupStart == newComponentStart) { + return curClass; + } } - newComponentStart = lookupStart; - curClass = inner; - } - - if (lookupStart != newComponentStart) { return null; + + } else { + return curClass; } } - - - return curClass; } } - } return null; } @@ -196,4 +205,17 @@ public class CoreJavaFileManager implements JavaFileManager { public void addToClasspath(VirtualFile root) { myClasspath.add(root); } + + private static class ClassAndOffsets { + + final PsiClass clazz; + final int componentStart; + final int lookupStart; + + ClassAndOffsets(PsiClass clazz, int componentStart, int lookupStart) { + this.clazz = clazz; + this.componentStart = componentStart; + this.lookupStart = lookupStart; + } + } } diff --git a/java/java-tests/testSrc/com/intellij/psi/CoreJavaFileManagerTest.java b/java/java-tests/testSrc/com/intellij/psi/CoreJavaFileManagerTest.java index 1cd630ccc2db..01365c2d1b5a 100644 --- a/java/java-tests/testSrc/com/intellij/psi/CoreJavaFileManagerTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/CoreJavaFileManagerTest.java @@ -22,26 +22,36 @@ import com.intellij.psi.search.GlobalSearchScope; import com.intellij.testFramework.PsiTestCase; import com.intellij.testFramework.PsiTestUtil; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Stack; + public class CoreJavaFileManagerTest extends PsiTestCase { - public void testNotNullInnerClass() throws Exception { + private VirtualFile prepareClasses(String clazzName, String clazzData) throws Exception { VirtualFile root = PsiTestUtil.createTestProjectStructure(myProject, myModule, myFilesToDelete); VirtualFile pkg = root.createChildDirectory(this, "foo"); PsiDirectory dir = myPsiManager.findDirectory(pkg); assertNotNull(dir); + PsiElement created = dir.add(PsiFileFactory.getInstance(getProject()).createFileFromText(clazzName + ".java", JavaFileType.INSTANCE, clazzData)); + return root; + } + + public void testNotNullInnerClass() throws Exception { String text = "package foo;\n\n" + "public class Nested {\n" + "public class InnerGeneral {}\n" + - "public class Inner$ {}\n" + + "public class Inner$ {" + + "}\n" + "\n" + "public Inner$ inner() {\n" + " return new Inner$();\n" + "}\n" + "\n" + "}"; - PsiElement created = dir.add(PsiFileFactory.getInstance(getProject()).createFileFromText("Nested.java", JavaFileType.INSTANCE, text)); + VirtualFile root = prepareClasses("Nested", text); GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); CoreJavaFileManager manager = new CoreJavaFileManager(myPsiManager); manager.addToClasspath(root); @@ -65,4 +75,90 @@ public class CoreJavaFileManagerTest extends PsiTestCase { assertNull(clazzInner$Wrong3); } + + public void testNotNullInnerClass2() throws Exception { + String text = "package foo;\n\n" + + "public class Nested {\n" + + + "public class Inner {" + + " public class XInner{}" + + " public class XInner${}" + + "}\n" + + "public class Inner$ {" + + " public class XInner{}" + + " public class XInner${}" + + "}\n" + + "\n" + + "}"; + + VirtualFile root = prepareClasses("Nested", text); + GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); + CoreJavaFileManager manager = new CoreJavaFileManager(myPsiManager); + manager.addToClasspath(root); + + PsiClass clazzInner = manager.findClass("foo.Nested.Inner", scope); + assertNotNull(clazzInner); + + PsiClass clazzXInner = manager.findClass("foo.Nested.Inner.XInner", scope); + assertNotNull(clazzXInner); + + PsiClass clazzXInner$ = manager.findClass("foo.Nested.Inner.XInner$", scope); + assertNotNull(clazzXInner$); + + PsiClass clazz$XInner = manager.findClass("foo.Nested.Inner$.XInner", scope); + assertNotNull(clazz$XInner); + + PsiClass clazz$XInner$ = manager.findClass("foo.Nested.Inner$.XInner$", scope); + assertNotNull(clazz$XInner$); + } + + + public void testNotNullInnerClass3() throws Exception { + String text = "package foo;\n\n" + + "public class NestedX {\n" + + + "public class XX {" + + " public class XXX{" + + " public class XXXX{ }" + + " public class XXXX${ }" + + " }" + + " public class XXX${" + + " public class XXXX{ }" + + " public class XXXX${ }" + + " }" + + "}\n" + + "public class XX$ {" + + " public class XXX{" + + " public class XXXX{ }" + + " public class XXXX${ }" + + " }" + + " public class XXX${" + + " public class XXXX{ }" + + " public class XXXX${ }" + + " }" + + "}\n" + + "\n" + + "}"; + + VirtualFile root = prepareClasses("NestedX", text); + GlobalSearchScope scope = GlobalSearchScope.allScope(getProject()); + CoreJavaFileManager manager = new CoreJavaFileManager(myPsiManager); + manager.addToClasspath(root); + + Queue queue = new LinkedList(); + queue.add("foo.NestedX"); + + while(!queue.isEmpty()) { + String head = queue.remove(); + PsiClass clazzInner = manager.findClass(head, scope); + assertNotNull(head, clazzInner); + String lastSegment = head.substring(head.lastIndexOf('.')); + String xs = lastSegment.substring(lastSegment.indexOf("X")).replace("$", ""); + if (xs.length() < 4) { + queue.add(head + "." + xs + "X"); + queue.add(head + "." + xs + "X$"); + } + } + } + }