IDEA-113062 (using file naming convention to tell top-level classes from inner)

Allows to correctly identify and parse classes with "$" abuse.
This commit is contained in:
Roman Shevchenko
2013-11-16 19:01:13 +01:00
parent 1483356656
commit 4645f02b2b
16 changed files with 82 additions and 18 deletions
@@ -20,7 +20,6 @@ import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.roots.FileIndexFacade;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.impl.PsiManagerImpl;
import com.intellij.psi.impl.compiled.ClsFileImpl;
import org.jetbrains.annotations.NotNull;
@@ -38,20 +37,22 @@ public class ClassFileViewProvider extends SingleRootFileViewProvider {
@Override
protected PsiFile createFile(@NotNull final Project project, @NotNull final VirtualFile vFile, @NotNull final FileType fileType) {
final FileIndexFacade fileIndex = ServiceManager.getService(project, FileIndexFacade.class);
if (fileIndex.isInLibraryClasses(vFile) || !fileIndex.isInSource(vFile)) {
String name = vFile.getName();
FileIndexFacade fileIndex = ServiceManager.getService(project, FileIndexFacade.class);
if (!fileIndex.isInLibraryClasses(vFile) && fileIndex.isInSource(vFile)) {
return null;
}
// skip inners & anonymous (todo: read actual class name from file)
int dotIndex = name.lastIndexOf('.');
if (dotIndex < 0) dotIndex = name.length();
int index = name.lastIndexOf('$', dotIndex);
if (index <= 0 || index == dotIndex - 1) {
return new ClsFileImpl((PsiManagerImpl)PsiManager.getInstance(project), this);
// skip inners & anonymous
String name = vFile.getNameWithoutExtension();
int index = name.lastIndexOf('$', name.length());
if (index > 0 && index < name.length() - 1) {
String supposedParentName = name.substring(0, index) + ".class";
if (vFile.getParent().findChild(supposedParentName) != null) {
return null;
}
}
return null;
return new ClsFileImpl(PsiManager.getInstance(project), this);
}
@NotNull
@@ -31,7 +31,8 @@ import com.intellij.util.indexing.FileContent;
*/
public class ClassFileStubBuilder implements BinaryFileStubBuilder {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.compiled.ClassFileStubBuilder");
public static final int STUB_VERSION = JavaFileElementType.STUB_VERSION + 6;
public static final int STUB_VERSION = JavaFileElementType.STUB_VERSION + 7;
@Override
public boolean acceptsFile(final VirtualFile file) {
@@ -41,7 +41,7 @@ public class DefaultClsStubBuilderFactory extends ClsStubBuilderFactory {
try {
final ClassReader reader = new ClassReader(bytes);
final StubBuildingVisitor<VirtualFile> classVisitor =
new StubBuildingVisitor<VirtualFile>(vFile, VirtualFileInnerClassStrategy.INSTANCE, file, 0, null);
new StubBuildingVisitor<VirtualFile>(vFile, VirtualFileInnerClassStrategy.INSTANCE, file, 0, vFile.getNameWithoutExtension());
try {
reader.accept(classVisitor, ClassReader.SKIP_FRAMES);
}
@@ -17,7 +17,8 @@ package com.intellij.psi.impl.compiled;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.PsiNameHelper;
import com.intellij.psi.PsiReferenceList;
import com.intellij.psi.impl.cache.ModifierFlags;
import com.intellij.psi.impl.cache.TypeInfo;
import com.intellij.psi.impl.java.stubs.*;
@@ -82,8 +83,16 @@ public class StubBuildingVisitor<T> extends ClassVisitor {
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
String fqn = getClassName(name);
String shortName = myShortName != null ? myShortName : PsiNameHelper.getShortClassName(fqn);
String fqn, shortName;
if (myShortName != null && name.endsWith(myShortName)) {
shortName = myShortName;
fqn = name.length() == shortName.length()
? shortName : getClassName(name.substring(0, name.length() - shortName.length() - 1)) + "." + shortName;
}
else {
fqn = getClassName(name);
shortName = PsiNameHelper.getShortClassName(fqn);
}
int flags = myAccess == 0 ? access : myAccess;
boolean isDeprecated = (flags & Opcodes.ACC_DEPRECATED) != 0;
@@ -307,8 +316,6 @@ public class StubBuildingVisitor<T> extends ClassVisitor {
}
}
if (!getClassName(outerName).equals(myResult.getQualifiedName())) return;
final T innerSource = myInnersStrategy.findInnerClass(innerName, mySource);
if (innerSource == null) return;
@@ -0,0 +1,7 @@
// IntelliJ API Decompiler stub source generated from a class file
// Implementation of methods is not available
public class DefaultPackage {
public DefaultPackage() { /* compiled code */ }
}
@@ -0,0 +1,11 @@
// IntelliJ API Decompiler stub source generated from a class file
// Implementation of methods is not available
package pkg;
public class LocalClass {
public LocalClass() { /* compiled code */ }
public java.lang.Runnable runnable() { /* compiled code */ }
}
@@ -0,0 +1,13 @@
// IntelliJ API Decompiler stub source generated from a class file
// Implementation of methods is not available
package pkg;
public class Middle$Buck {
public Middle$Buck() { /* compiled code */ }
private static class Inner$Buck {
private Inner$Buck() { /* compiled code */ }
}
}
@@ -0,0 +1,2 @@
public class DefaultPackage {
}
@@ -0,0 +1,13 @@
package pkg;
public class LocalClass {
public Runnable runnable() {
class MyRunnable implements Runnable {
public void run() {
System.out.println(this);
}
}
return new MyRunnable();
}
}
@@ -0,0 +1,6 @@
package pkg;
public class Middle$Buck {
private static class Inner$Buck {
}
}
@@ -44,6 +44,9 @@ public class ClsMirrorBuildingTest extends LightIdeaTestCase {
public void testClassRefs() { doTest(); }
public void testEA46236() { doTest("ValuedEnum"); }
public void testKotlinFunList() { doTest(); }
public void testMiddle$Buck() { doTest(); }
public void testDefaultPackage() { doTest(); }
public void testLocalClass() { doTest(); }
private void doTest() {
doTest(getTestName(false));