From e856733aab823f31f374d20a04c7385077b0fd4b Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Wed, 6 Apr 2011 20:53:50 +0200 Subject: [PATCH] IDEA-67596 (class stub builder: decode only relevant access modifiers) --- .../impl/compiled/ClassFileStubBuilder.java | 14 ++- .../impl/compiled/ClsModifierListImpl.java | 59 +++++----- .../psi/impl/compiled/ClsStubBuilder.java | 101 +++++++++++------- .../stubBuilder/AnnotatedEnumConstructor.txt | 2 +- .../psi/cls/stubBuilder/Modifiers.txt | 27 +++++ .../psi/cls/stubBuilder/UtilCollections.txt | 2 +- .../repositoryUse/cls/pack/Modifiers.class | Bin 0 -> 443 bytes .../com/intellij/psi/ClsBuilderTest.java | 14 ++- .../intellij/psi/ClsRepositoryUseTest.java | 16 +++ 9 files changed, 152 insertions(+), 83 deletions(-) create mode 100644 java/java-tests/testData/psi/cls/stubBuilder/Modifiers.txt create mode 100644 java/java-tests/testData/psi/repositoryUse/cls/pack/Modifiers.class diff --git a/java/java-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java b/java/java-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java index bba38dd08fd2..4bde80b3d036 100644 --- a/java/java-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java +++ b/java/java-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * @author max - */ package com.intellij.psi.impl.compiled; import com.intellij.openapi.vfs.VirtualFile; @@ -26,6 +22,9 @@ import com.intellij.psi.stubs.BinaryFileStubBuilder; import com.intellij.psi.stubs.StubElement; import com.intellij.util.cls.ClsFormatException; +/** + * @author max + */ public class ClassFileStubBuilder implements BinaryFileStubBuilder { public boolean acceptsFile(final VirtualFile file) { return !isInner(file.getNameWithoutExtension(), new ParentDirectory(file)); @@ -37,8 +36,7 @@ public class ClassFileStubBuilder implements BinaryFileStubBuilder { private static boolean isInner(final String name, final int from, final Directory directory) { final int index = name.indexOf('$', from); - return index == -1 ? false - : containsPart(directory, name, index) ? true : isInner(name, index + 1, directory); + return index != -1 && (containsPart(directory, name, index) || isInner(name, index + 1, directory)); } private static boolean containsPart(Directory directory, String name, int endIndex) { @@ -55,7 +53,7 @@ public class ClassFileStubBuilder implements BinaryFileStubBuilder { } public int getStubVersion() { - return JavaFileElementType.STUB_VERSION; + return JavaFileElementType.STUB_VERSION + 1; } @@ -74,7 +72,7 @@ public class ClassFileStubBuilder implements BinaryFileStubBuilder { public boolean contains(final String name) { final String fullName = myExtension == null ? name : name + "." + myExtension; - return myDirectory == null ? false : myDirectory.findChild(fullName) != null; + return myDirectory != null && myDirectory.findChild(fullName) != null; } } } \ No newline at end of file diff --git a/java/java-impl/src/com/intellij/psi/impl/compiled/ClsModifierListImpl.java b/java/java-impl/src/com/intellij/psi/impl/compiled/ClsModifierListImpl.java index 77939afac236..0f0d2cd194ba 100644 --- a/java/java-impl/src/com/intellij/psi/impl/compiled/ClsModifierListImpl.java +++ b/java/java-impl/src/com/intellij/psi/impl/compiled/ClsModifierListImpl.java @@ -85,29 +85,32 @@ public class ClsModifierListImpl extends ClsRepositoryPsiElementtreeToPsiNotNull(element).getAnnotations(); PsiAnnotation[] annotations = getAnnotations(); LOG.assertTrue(annotations.length == mirrorAnnotations.length); for (int i = 0; i < annotations.length; i++) { - ((ClsElementImpl)annotations[i]).setMirror((TreeElement)SourceTreeToPsiMap.psiElementToTree(mirrorAnnotations[i])); + ((ClsElementImpl)annotations[i]).setMirror(SourceTreeToPsiMap.psiToTreeNotNull(mirrorAnnotations[i])); } } diff --git a/java/java-impl/src/com/intellij/psi/impl/compiled/ClsStubBuilder.java b/java/java-impl/src/com/intellij/psi/impl/compiled/ClsStubBuilder.java index ec6a920a7087..aee30f6493ac 100644 --- a/java/java-impl/src/com/intellij/psi/impl/compiled/ClsStubBuilder.java +++ b/java/java-impl/src/com/intellij/psi/impl/compiled/ClsStubBuilder.java @@ -13,10 +13,6 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - -/* - * @author max - */ package com.intellij.psi.impl.compiled; import com.intellij.lexer.JavaLexer; @@ -25,6 +21,7 @@ import com.intellij.openapi.util.Comparing; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; +import com.intellij.psi.CommonClassNames; import com.intellij.psi.JavaTokenType; import com.intellij.psi.PsiNameHelper; import com.intellij.psi.PsiReferenceList; @@ -51,12 +48,14 @@ import java.util.Collections; import java.util.List; import java.util.regex.Pattern; +/** + * @author max + */ @SuppressWarnings({"HardCodedStringLiteral"}) public class ClsStubBuilder { private static final Pattern REGEX_PATTERN = Pattern.compile("(?<=[^\\$])\\${1}(?=[^\\$])"); - private ClsStubBuilder() { - } + private ClsStubBuilder() { } @Nullable public static PsiFileStub build(final VirtualFile vFile, byte[] bytes) throws ClsFormatException { @@ -102,7 +101,7 @@ public class ClsStubBuilder { private final StubElement myParent; private final int myAccess; private final VirtualFile myVFile; - private PsiModifierListStub myModlist; + private PsiModifierListStub myModList; private PsiClassStub myResult; @NonNls private static final String SYNTHETIC_CLINIT_METHOD = ""; @NonNls private static final String SYNTHETIC_INIT_METHOD = ""; @@ -143,7 +142,7 @@ public class ClsStubBuilder { myLexer = new JavaLexer(languageLevel); ((PsiClassStubImpl)myResult).setLanguageLevel(languageLevel); - myModlist = new PsiModifierListStubImpl(myResult, packModlistFlags(flags)); + myModList = new PsiModifierListStubImpl(myResult, packClassFlags(flags)); CharacterIterator signatureIterator = signature != null ? new StringCharacterIterator(signature) : null; if (signatureIterator != null) { @@ -177,7 +176,7 @@ public class ClsStubBuilder { new PsiClassReferenceListStubImpl(JavaStubElementTypes.IMPLEMENTS_LIST, myResult, ArrayUtil.EMPTY_STRING_ARRAY, PsiReferenceList.Role.IMPLEMENTS_LIST); } else { - if (convertedSuper != null && !"java.lang.Object".equals(convertedSuper)) { + if (convertedSuper != null && !CommonClassNames.JAVA_LANG_OBJECT.equals(convertedSuper)) { new PsiClassReferenceListStubImpl(JavaStubElementTypes.EXTENDS_LIST, myResult, new String[]{convertedSuper}, PsiReferenceList.Role.EXTENDS_LIST); } else { @@ -226,36 +225,66 @@ public class ClsStubBuilder { return LanguageLevel.HIGHEST; } - private static int packModlistFlags(final int access) { + private static int packCommonFlags(final int access) { int flags = 0; if ((access & Opcodes.ACC_PRIVATE) != 0) { flags |= ModifierFlags.PRIVATE_MASK; - } else if ((access & Opcodes.ACC_PROTECTED) != 0) { + } + else if ((access & Opcodes.ACC_PROTECTED) != 0) { flags |= ModifierFlags.PROTECTED_MASK; - } else if ((access & Opcodes.ACC_PUBLIC) != 0) { + } + else if ((access & Opcodes.ACC_PUBLIC) != 0) { flags |= ModifierFlags.PUBLIC_MASK; - } else { + } + else { flags |= ModifierFlags.PACKAGE_LOCAL_MASK; } - if ((access & Opcodes.ACC_ABSTRACT) != 0) { - flags |= ModifierFlags.ABSTRACT_MASK; + if ((access & Opcodes.ACC_STATIC) != 0) { + flags |= ModifierFlags.STATIC_MASK; } if ((access & Opcodes.ACC_FINAL) != 0) { flags |= ModifierFlags.FINAL_MASK; } - if ((access & Opcodes.ACC_NATIVE) != 0) { - flags |= ModifierFlags.NATIVE_MASK; + + return flags; + } + + private static int packClassFlags(final int access) { + int flags = packCommonFlags(access); + + if ((access & Opcodes.ACC_ABSTRACT) != 0) { + flags |= ModifierFlags.ABSTRACT_MASK; } - if ((access & Opcodes.ACC_STATIC) != 0) { - flags |= ModifierFlags.STATIC_MASK; + + return flags; + } + + private static int packFieldFlags(final int access) { + int flags = packCommonFlags(access); + + if ((access & Opcodes.ACC_VOLATILE) != 0) { + flags |= ModifierFlags.VOLATILE_MASK; } if ((access & Opcodes.ACC_TRANSIENT) != 0) { flags |= ModifierFlags.TRANSIENT_MASK; } - if ((access & Opcodes.ACC_VOLATILE) != 0) { - flags |= ModifierFlags.VOLATILE_MASK; + + return flags; + } + + private static int packMethodFlags(final int access) { + int flags = packCommonFlags(access); + + if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { + flags |= ModifierFlags.SYNCHRONIZED_MASK; + } + if ((access & Opcodes.ACC_NATIVE) != 0) { + flags |= ModifierFlags.NATIVE_MASK; + } + if ((access & Opcodes.ACC_ABSTRACT) != 0) { + flags |= ModifierFlags.ABSTRACT_MASK; } if ((access & Opcodes.ACC_STRICT) != 0) { flags |= ModifierFlags.STRICTFP_MASK; @@ -274,7 +303,7 @@ public class ClsStubBuilder { public AnnotationVisitor visitAnnotation(final String desc, final boolean visible) { return new AnnotationTextCollector(desc, new AnnotationResultCallback() { public void callback(final String text) { - new PsiAnnotationStubImpl(myModlist, text); + new PsiAnnotationStubImpl(myModList, text); } }); } @@ -287,11 +316,11 @@ public class ClsStubBuilder { if (!isCorrectName(innerName)) return; if (innerName != null && outerName != null && getClassName(outerName).equals(myResult.getQualifiedName())) { - final String basename = myVFile.getNameWithoutExtension(); + final String baseName = myVFile.getNameWithoutExtension(); final VirtualFile dir = myVFile.getParent(); assert dir != null; - final VirtualFile innerFile = dir.findChild(basename + "$" + innerName + ".class"); + final VirtualFile innerFile = dir.findChild(baseName + "$" + innerName + ".class"); if (innerFile != null) { try { buildClass(innerFile, innerFile.contentsToByteArray(), myResult, access); @@ -318,8 +347,8 @@ public class ClsStubBuilder { final byte flags = PsiFieldStubImpl.packFlags((access & Opcodes.ACC_ENUM) != 0, (access & Opcodes.ACC_DEPRECATED) != 0, false); PsiFieldStub stub = new PsiFieldStubImpl(myResult, name, fieldType(desc, signature), constToString(value), flags); - final PsiModifierListStub modlist = new PsiModifierListStubImpl(stub, packModlistFlags(access)); - return new AnnotationCollectingVisitor(stub, modlist); + final PsiModifierListStub modList = new PsiModifierListStubImpl(stub, packFieldFlags(access)); + return new AnnotationCollectingVisitor(stub, modList); } @NotNull @@ -346,7 +375,6 @@ public class ClsStubBuilder { return new TypeInfo(StringRef.fromString(getTypeText(type)), (byte)dim, false, Collections.emptyList()); //todo read annos from .class file } - @Nullable public MethodVisitor visitMethod(final int access, final String name, @@ -372,7 +400,7 @@ public class ClsStubBuilder { PsiMethodStubImpl stub = new PsiMethodStubImpl(myResult, StringRef.fromString(canonicalMethodName), flags, null); - final PsiModifierListStub modlist = new PsiModifierListStubImpl(stub, packMethodFlags(access)); + final PsiModifierListStub modList = new PsiModifierListStubImpl(stub, packMethodFlags(access)); boolean parsedViaGenericSignature = false; String returnType; if (signature == null) { @@ -392,7 +420,7 @@ public class ClsStubBuilder { final boolean isNonStaticInnerClassConstructor = - isConstructor && !(myParent instanceof PsiFileStub) && (myModlist.getModifiersMask() & Opcodes.ACC_STATIC) == 0; + isConstructor && !(myParent instanceof PsiFileStub) && (myModList.getModifiersMask() & Opcodes.ACC_STATIC) == 0; final boolean shouldSkipFirstParamForNonStaticInnerClassConstructor = !parsedViaGenericSignature && isNonStaticInnerClassConstructor; final PsiParameterListStubImpl parameterList = new PsiParameterListStubImpl(stub); @@ -420,7 +448,7 @@ public class ClsStubBuilder { localVarIgnoreCount += 2; } final int paramIgnoreCount = isEnumConstructor? 2 : isNonStaticInnerClassConstructor ? 1 : 0; - return new AnnotationParamCollectingVisitor(stub, modlist, localVarIgnoreCount, paramIgnoreCount, paramCount, paramStubs); + return new AnnotationParamCollectingVisitor(stub, modList, localVarIgnoreCount, paramIgnoreCount, paramCount, paramStubs); } private static String[] buildThrowsList(String[] exceptions, List throwables, boolean parsedViaGenericSignature) { @@ -445,15 +473,6 @@ public class ClsStubBuilder { } } - private static int packMethodFlags(final int access) { - int commonFlags = packModlistFlags(access); - if ((access & Opcodes.ACC_SYNCHRONIZED) != 0) { - commonFlags |= ModifierFlags.SYNCHRONIZED_MASK; - } - - return commonFlags; - } - private static String parseMethodViaDescription(final String desc, final PsiMethodStubImpl stub, final List args) { final String returnType = getTypeText(Type.getReturnType(desc)); final Type[] argTypes = Type.getArgumentTypes(desc); @@ -691,10 +710,10 @@ public class ClsStubBuilder { private static String getTypeText(final Type type) { final String raw = type.getClassName(); - // As the '$' char is a valid java identifier and is actively used by bytecode genarators, the problem is + // As the '$' char is a valid java identifier and is actively used by byte code generators, the problem is // which occurrences of this char should be replaced and which should not. // Heuristic: replace only those $ occurrences that are surrounded non-"$" chars - // (most likely generated by javac to separate inner or anonymoys class name) + // (most likely generated by javac to separate inner or anonymous class name) // Leading and trailing $ chars should be left unchanged. return raw.contains("$")? REGEX_PATTERN.matcher(raw).replaceAll("\\.") : raw; } diff --git a/java/java-tests/testData/psi/cls/stubBuilder/AnnotatedEnumConstructor.txt b/java/java-tests/testData/psi/cls/stubBuilder/AnnotatedEnumConstructor.txt index 28f66661e8a3..d8df903180e9 100644 --- a/java/java-tests/testData/psi/cls/stubBuilder/AnnotatedEnumConstructor.txt +++ b/java/java-tests/testData/psi/cls/stubBuilder/AnnotatedEnumConstructor.txt @@ -23,7 +23,7 @@ PsiJavaFileStub [] PsiModifierListStub[mask=0] PsiRefListStub[THROWS_LIST:] PsiMethodStub[cons varargs AnnotatedEnumConstructor:void] - PsiModifierListStub[mask=130] + PsiModifierListStub[mask=2] PsiTypeParameterListStub PsiParameterListStub PsiParameterStub[names:java.lang.String...] diff --git a/java/java-tests/testData/psi/cls/stubBuilder/Modifiers.txt b/java/java-tests/testData/psi/cls/stubBuilder/Modifiers.txt new file mode 100644 index 000000000000..a608ee7ea7e9 --- /dev/null +++ b/java/java-tests/testData/psi/cls/stubBuilder/Modifiers.txt @@ -0,0 +1,27 @@ +PsiJavaFileStub [pack] + PsiClassStub[name=Modifiers fqn=pack.Modifiers] + PsiModifierListStub[mask=1] + PsiTypeParameterListStub + PsiRefListStub[EXTENDS_LIST:] + PsiRefListStub[IMPLEMENTS_LIST:] + PsiFieldStub[f1:int] + PsiModifierListStub[mask=130] + PsiFieldStub[f2:int] + PsiModifierListStub[mask=66] + PsiMethodStub[cons Modifiers:void] + PsiModifierListStub[mask=1] + PsiTypeParameterListStub + PsiParameterListStub + PsiRefListStub[THROWS_LIST:] + PsiMethodStub[varargs m1:void] + PsiModifierListStub[mask=2] + PsiTypeParameterListStub + PsiParameterListStub + PsiParameterStub[i:int...] + PsiModifierListStub[mask=0] + PsiRefListStub[THROWS_LIST:] + PsiMethodStub[m2:void] + PsiModifierListStub[mask=34] + PsiTypeParameterListStub + PsiParameterListStub + PsiRefListStub[THROWS_LIST:] diff --git a/java/java-tests/testData/psi/cls/stubBuilder/UtilCollections.txt b/java/java-tests/testData/psi/cls/stubBuilder/UtilCollections.txt index d294d868a3e9..d58e2e68de90 100644 --- a/java/java-tests/testData/psi/cls/stubBuilder/UtilCollections.txt +++ b/java/java-tests/testData/psi/cls/stubBuilder/UtilCollections.txt @@ -2289,7 +2289,7 @@ PsiJavaFileStub [java.util] PsiModifierListStub[mask=0] PsiRefListStub[THROWS_LIST:] PsiMethodStub[varargs addAll:boolean] - PsiModifierListStub[mask=137] + PsiModifierListStub[mask=9] PsiTypeParameterListStub PsiTypeParameter[T] PsiRefListStub[EXTENDS_BOUNDS_LIST:] diff --git a/java/java-tests/testData/psi/repositoryUse/cls/pack/Modifiers.class b/java/java-tests/testData/psi/repositoryUse/cls/pack/Modifiers.class new file mode 100644 index 0000000000000000000000000000000000000000..0ea879469d285ddf094e98dee60f9298fa00254e GIT binary patch literal 443 zcmZusyH3ME5S;ZBOh`h2Knqm>DHf5aKolS$MKVx;(xf^&7r5XDavVM&e?)~u!3XeB zh&{)OKv3N5?(EKt?(^&Y13(YE9!zYzXuH@U7~^9C^>x!DIA!N(OTvoY59K^?vHG$EC`!r;?_5f2|geI literal 0 HcmV?d00001 diff --git a/java/java-tests/testSrc/com/intellij/psi/ClsBuilderTest.java b/java/java-tests/testSrc/com/intellij/psi/ClsBuilderTest.java index 142fee97dbae..2ecad41d87f7 100644 --- a/java/java-tests/testSrc/com/intellij/psi/ClsBuilderTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/ClsBuilderTest.java @@ -61,15 +61,23 @@ public class ClsBuilderTest extends LightIdeaTestCase { doTestFromTestData(); } + public void testModifiers() throws Exception { + final String clsFilePath = JavaTestUtil.getJavaTestDataPath() + "/psi/repositoryUse/cls/pack/" + getTestName(false) + ".class"; + final VirtualFile clsFile = LocalFileSystem.getInstance().findFileByPath(clsFilePath); + assert clsFile != null : clsFilePath; + doTest(clsFile, getTestName(false) + ".txt"); + } + private void doTestFromTestData() throws ClsFormatException, IOException { final String clsFilePath = JavaTestUtil.getJavaTestDataPath() + "/psi/cls/stubBuilder/" + getTestName(false) + ".class"; - VirtualFile clsFile = LocalFileSystem.getInstance().findFileByPath(clsFilePath); + final VirtualFile clsFile = LocalFileSystem.getInstance().findFileByPath(clsFilePath); + assert clsFile != null : clsFilePath; doTest(clsFile, getTestName(false) + ".txt"); } private void doTest(final String className) throws IOException, ClsFormatException { - VirtualFile vFile = findFile(className); - doTest(vFile, getTestName(false)+".txt"); + final VirtualFile clsFile = findFile(className); + doTest(clsFile, getTestName(false) + ".txt"); } private static void doTest(VirtualFile vFile, String goldFile) throws ClsFormatException, IOException { diff --git a/java/java-tests/testSrc/com/intellij/psi/ClsRepositoryUseTest.java b/java/java-tests/testSrc/com/intellij/psi/ClsRepositoryUseTest.java index 2eba4f944073..73e361f29f84 100644 --- a/java/java-tests/testSrc/com/intellij/psi/ClsRepositoryUseTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/ClsRepositoryUseTest.java @@ -752,4 +752,20 @@ public class ClsRepositoryUseTest extends PsiTestCase{ assertTrue(substitution instanceof PsiWildcardType); assertEquals(PsiWildcardType.createUnbounded(myPsiManager), substitution); } + + public void testModifiers() throws Exception { + final PsiClass psiClass = myJavaFacade.findClass("pack.Modifiers", RESOLVE_SCOPE); + assertNotNull(psiClass); + assertEquals("public class Modifiers {\n" + + " private transient int f1;\n" + + " private volatile int f2;\n" + + " \n" + + " public Modifiers() { /* compiled code */ }\n" + + " \n" + + " private void m1(int... i) { /* compiled code */ }\n" + + " \n" + + " private synchronized void m2() { /* compiled code */ }\n" + + "}", + psiClass.getText().trim()); + } }