From b23de45f7354f7fc465e6bdbf84f80852ee2f3f9 Mon Sep 17 00:00:00 2001 From: "Alexander.Podkhalyuzin" Date: Thu, 24 Nov 2011 11:25:50 +0400 Subject: [PATCH] Extensible checking of is inner class file --- .../impl/compiled/ClassFileStubBuilder.java | 49 +++------- .../impl/compiled/ClsStubBuilderFactory.java | 19 +++- ...java => DefaultClsStubBuilderFactory.java} | 98 ++++++++++++------- .../com/intellij/psi/ClsBuilderTest.java | 4 +- .../compiled/ClassFileStubBuilderTest.java | 4 +- resources/src/META-INF/IdeaPlugin.xml | 2 + 6 files changed, 99 insertions(+), 77 deletions(-) rename java/java-psi-impl/src/com/intellij/psi/impl/compiled/{ClsStubBuilder.java => DefaultClsStubBuilderFactory.java} (65%) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java index 887b13b8d747..61d645b7f931 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java @@ -15,6 +15,7 @@ */ package com.intellij.psi.impl.compiled; +import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.project.Project; import com.intellij.psi.impl.source.JavaFileElementType; @@ -28,26 +29,23 @@ import com.intellij.util.cls.ClsFormatException; public class ClassFileStubBuilder implements BinaryFileStubBuilder { @Override public boolean acceptsFile(final VirtualFile file) { - return !isInner(file.getNameWithoutExtension(), new ParentDirectory(file)); - } - - static boolean isInner(final String name, final Directory directory) { - return isInner(name, 0, directory); - } - - private static boolean isInner(final String name, final int from, final Directory directory) { - final int index = name.indexOf('$', from); - return index != -1 && (containsPart(directory, name, index) || isInner(name, index + 1, directory)); - } - - private static boolean containsPart(Directory directory, String name, int endIndex) { - return endIndex > 0 && directory.contains(name.substring(0, endIndex)); + final ClsStubBuilderFactory[] factories = Extensions.getExtensions(ClsStubBuilderFactory.EP_NAME); + for (ClsStubBuilderFactory factory : factories) { + if (!factory.isInnerClass(file)) return true; + } + return false; } @Override public StubElement buildStubTree(final VirtualFile file, final byte[] content, final Project project) { try { - return ClsStubBuilder.build(file, content); + final ClsStubBuilderFactory[] factories = Extensions.getExtensions(ClsStubBuilderFactory.EP_NAME); + for (ClsStubBuilderFactory factory : factories) { + if (!factory.isInnerClass(file) && factory.canBeProcessed(file, content)) { + return factory.buildFileStub(file, content); + } + } + return null; } catch (ClsFormatException e) { return null; @@ -58,25 +56,4 @@ public class ClassFileStubBuilder implements BinaryFileStubBuilder { public int getStubVersion() { return JavaFileElementType.STUB_VERSION + 3; } - - - interface Directory { - boolean contains(String name); - } - - private static class ParentDirectory implements Directory { - private final VirtualFile myDirectory; - private final String myExtension; - - private ParentDirectory(final VirtualFile file) { - myDirectory = file.getParent(); - myExtension = file.getExtension(); - } - - @Override - public boolean contains(final String name) { - final String fullName = myExtension == null ? name : name + "." + myExtension; - return myDirectory != null && myDirectory.findChild(fullName) != null; - } - } } \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsStubBuilderFactory.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsStubBuilderFactory.java index 1b29a54e6b17..8da85a67644d 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsStubBuilderFactory.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsStubBuilderFactory.java @@ -19,15 +19,26 @@ import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiFile; import com.intellij.psi.stubs.PsiFileStub; +import com.intellij.util.cls.ClsFormatException; +import org.jetbrains.annotations.Nullable; /** * @author ilyas */ -public interface ClsStubBuilderFactory { +public abstract class ClsStubBuilderFactory { - ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.clsStubBuilderFactory"); + public static final ExtensionPointName EP_NAME = ExtensionPointName.create("com.intellij.clsStubBuilderFactory"); - PsiFileStub buildFileStub(final VirtualFile file, byte[] bytes); + @Nullable + public abstract PsiFileStub buildFileStub(final VirtualFile file, byte[] bytes) throws ClsFormatException; - boolean canBeProcessed(final VirtualFile file, byte[] bytes); + public abstract boolean canBeProcessed(final VirtualFile file, byte[] bytes); + + /** + * Should be fast, because of processing file only according to the name. + * It can be inconsistent with 'canBeProcessed' method. + * @param file classFile + * @return false in case if it's not inner class + */ + public abstract boolean isInnerClass(final VirtualFile file); } diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsStubBuilder.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/DefaultClsStubBuilderFactory.java similarity index 65% rename from java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsStubBuilder.java rename to java/java-psi-impl/src/com/intellij/psi/impl/compiled/DefaultClsStubBuilderFactory.java index edf317267ed8..08d391c8aa11 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsStubBuilder.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/DefaultClsStubBuilderFactory.java @@ -15,7 +15,6 @@ */ package com.intellij.psi.impl.compiled; -import com.intellij.openapi.extensions.Extensions; import com.intellij.openapi.util.Comparing; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.PsiClass; @@ -32,8 +31,71 @@ import java.io.IOException; * @author max */ @SuppressWarnings({"HardCodedStringLiteral"}) -public class ClsStubBuilder { - private ClsStubBuilder() { } +public class DefaultClsStubBuilderFactory extends ClsStubBuilderFactory { + @Override + public PsiFileStub buildFileStub(VirtualFile vFile, byte[] bytes) throws ClsFormatException { + final PsiJavaFileStubImpl file = new PsiJavaFileStubImpl("do.not.know.yet", true); + try { + ClassReader reader = new ClassReader(bytes); + + final StubBuildingVisitor + classVisitor = new StubBuildingVisitor(vFile, VirtualFileInnerClassStrategy.INSTANCE, file, 0); + reader.accept(classVisitor, 0); + + final PsiClassStub result = classVisitor.getResult(); + if (result == null) return null; + + //noinspection unchecked + file.setPackageName(getPackageName(result)); + } + catch (Exception e) { + throw new ClsFormatException(); + } + return file; + } + + @Override + public boolean canBeProcessed(VirtualFile file, byte[] bytes) { + return true; + } + + @Override + public boolean isInnerClass(VirtualFile file) { + return isInner(file.getNameWithoutExtension(), new ParentDirectory(file)); + } + + static boolean isInner(final String name, final Directory directory) { + return isInner(name, 0, directory); + } + + private static boolean isInner(final String name, final int from, final Directory directory) { + final int index = name.indexOf('$', from); + return index != -1 && (containsPart(directory, name, index) || isInner(name, index + 1, directory)); + } + + private static boolean containsPart(Directory directory, String name, int endIndex) { + return endIndex > 0 && directory.contains(name.substring(0, endIndex)); + } + + interface Directory { + boolean contains(String name); + } + + private static class ParentDirectory implements Directory { + private final VirtualFile myDirectory; + private final String myExtension; + + private ParentDirectory(final VirtualFile file) { + myDirectory = file.getParent(); + myExtension = file.getExtension(); + } + + @Override + public boolean contains(final String name) { + final String fullName = myExtension == null ? name : name + "." + myExtension; + return myDirectory != null && myDirectory.findChild(fullName) != null; + } + } private static class VirtualFileInnerClassStrategy implements InnerClassSourceStrategy { public static VirtualFileInnerClassStrategy INSTANCE = new VirtualFileInnerClassStrategy(); @@ -60,35 +122,6 @@ public class ClsStubBuilder { } } - @Nullable - public static PsiFileStub build(final VirtualFile vFile, byte[] bytes) throws ClsFormatException { - final ClsStubBuilderFactory[] factories = Extensions.getExtensions(ClsStubBuilderFactory.EP_NAME); - for (ClsStubBuilderFactory factory : factories) { - if (factory.canBeProcessed(vFile, bytes)) { - return factory.buildFileStub(vFile, bytes); - } - } - - final PsiJavaFileStubImpl file = new PsiJavaFileStubImpl("do.not.know.yet", true); - try { - ClassReader reader = new ClassReader(bytes); - - final StubBuildingVisitor - classVisitor = new StubBuildingVisitor(vFile, VirtualFileInnerClassStrategy.INSTANCE, file, 0); - reader.accept(classVisitor, 0); - - final PsiClassStub result = classVisitor.getResult(); - if (result == null) return null; - - //noinspection unchecked - file.setPackageName(getPackageName(result)); - } - catch (Exception e) { - throw new ClsFormatException(); - } - return file; - } - private static String getPackageName(final PsiClassStub result) { final String fqn = result.getQualifiedName(); final String shortName = result.getName(); @@ -98,5 +131,4 @@ public class ClsStubBuilder { return fqn.substring(0, fqn.lastIndexOf('.')); } - } diff --git a/java/java-tests/testSrc/com/intellij/psi/ClsBuilderTest.java b/java/java-tests/testSrc/com/intellij/psi/ClsBuilderTest.java index 2ecad41d87f7..51c816e01d24 100644 --- a/java/java-tests/testSrc/com/intellij/psi/ClsBuilderTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/ClsBuilderTest.java @@ -6,7 +6,7 @@ import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; -import com.intellij.psi.impl.compiled.ClsStubBuilder; +import com.intellij.psi.impl.compiled.DefaultClsStubBuilderFactory; import com.intellij.psi.stubs.PsiFileStub; import com.intellij.psi.stubs.StubBase; import com.intellij.testFramework.LightIdeaTestCase; @@ -81,7 +81,7 @@ public class ClsBuilderTest extends LightIdeaTestCase { } private static void doTest(VirtualFile vFile, String goldFile) throws ClsFormatException, IOException { - final PsiFileStub stub = ClsStubBuilder.build(vFile, vFile.contentsToByteArray()); + final PsiFileStub stub = (new DefaultClsStubBuilderFactory()).buildFileStub(vFile, vFile.contentsToByteArray()); assert stub != null : vFile; final String butWas = ((StubBase)stub).printTree(); diff --git a/java/java-tests/testSrc/com/intellij/psi/impl/compiled/ClassFileStubBuilderTest.java b/java/java-tests/testSrc/com/intellij/psi/impl/compiled/ClassFileStubBuilderTest.java index 31f06355eb7d..71e7d950fcc6 100644 --- a/java/java-tests/testSrc/com/intellij/psi/impl/compiled/ClassFileStubBuilderTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/impl/compiled/ClassFileStubBuilderTest.java @@ -127,11 +127,11 @@ public class ClassFileStubBuilderTest extends TestCase { Set all = new HashSet(); ContainerUtil.addAll(all, files); all.add(name); - return ClassFileStubBuilder.isInner(name, new DirectoryMock(all)); + return DefaultClsStubBuilderFactory.isInner(name, new DirectoryMock(all)); } - private static class DirectoryMock implements ClassFileStubBuilder.Directory { + private static class DirectoryMock implements DefaultClsStubBuilderFactory.Directory { private Set myFiles; private DirectoryMock(Set files) { diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index 453e54c19a68..9853b3fe4eb9 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1095,6 +1095,8 @@ + +