diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java index 3a6bfac42919..12d9fa439822 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java @@ -37,6 +37,7 @@ import com.intellij.openapi.ui.Queryable; import com.intellij.openapi.util.Computable; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.ModificationTracker; +import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.pom.java.LanguageLevel; @@ -612,7 +613,8 @@ public class ClsFileImpl extends ClsRepositoryPsiElement PsiJavaFileStub stub = stubBuilder.fun(packageName); try { - StubBuildingVisitor visitor = new StubBuildingVisitor(file, STRATEGY, stub, 0, className); + FileContentPair source = new FileContentPair(file, bytes); + StubBuildingVisitor visitor = new StubBuildingVisitor(source, STRATEGY, stub, 0, className); reader.accept(visitor, EMPTY_ATTRIBUTES, ClassReader.SKIP_FRAMES); PsiClassStub result = visitor.getResult(); if (result == null) return null; @@ -633,23 +635,38 @@ public class ClsFileImpl extends ClsRepositoryPsiElement return p > 0 ? internalName.substring(0, p).replace('/', '.') : ""; } - private static final InnerClassSourceStrategy STRATEGY = new InnerClassSourceStrategy() { - @Nullable - @Override - public VirtualFile findInnerClass(String innerName, VirtualFile outerClass) { - String baseName = outerClass.getNameWithoutExtension(); - VirtualFile dir = outerClass.getParent(); - assert dir != null : outerClass; - return dir.findChild(baseName + '$' + innerName + ".class"); + private static class FileContentPair extends Pair { + public FileContentPair(VirtualFile file, byte[] content) { + super(file, content); } @Override - public void accept(VirtualFile innerClass, StubBuildingVisitor visitor) { - try { - byte[] bytes = innerClass.contentsToByteArray(false); - new ClassReader(bytes).accept(visitor, EMPTY_ATTRIBUTES, ClassReader.SKIP_FRAMES); + public String toString() { + return first.toString(); + } + } + + private static final InnerClassSourceStrategy STRATEGY = new InnerClassSourceStrategy() { + @Nullable + @Override + public FileContentPair findInnerClass(String innerName, FileContentPair outerClass) { + String baseName = outerClass.first.getNameWithoutExtension(); + VirtualFile dir = outerClass.first.getParent(); + assert dir != null : outerClass; + VirtualFile innerClass = dir.findChild(baseName + '$' + innerName + ".class"); + if (innerClass != null) { + try { + byte[] bytes = innerClass.contentsToByteArray(false); + return new FileContentPair(innerClass, bytes); + } + catch (IOException ignored) { } } - catch (IOException ignored) { } + return null; + } + + @Override + public void accept(FileContentPair innerClass, StubBuildingVisitor visitor) { + new ClassReader(innerClass.second).accept(visitor, EMPTY_ATTRIBUTES, ClassReader.SKIP_FRAMES); } }; diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/InnerClassSourceStrategy.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/InnerClassSourceStrategy.java index a686088b7776..7a305f6ff538 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/InnerClassSourceStrategy.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/InnerClassSourceStrategy.java @@ -1,5 +1,5 @@ /* - * Copyright 2000-2014 JetBrains s.r.o. + * Copyright 2000-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -22,7 +22,7 @@ import org.jetbrains.annotations.Nullable; */ public interface InnerClassSourceStrategy { @Nullable - T findInnerClass(String name, T outerClass); + T findInnerClass(String innerName, T outerClass); void accept(T innerClass, StubBuildingVisitor visitor); -} +} \ No newline at end of file diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java index 4fbe6509047e..7b2f38baa8b3 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/StubBuildingVisitor.java @@ -39,6 +39,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.org.objectweb.asm.*; +import java.io.IOException; import java.lang.reflect.Array; import java.text.CharacterIterator; import java.text.StringCharacterIterator; @@ -787,47 +788,64 @@ public class StubBuildingVisitor extends ClassVisitor { } private static Function createMapping(Object classSource) { - if (classSource instanceof VirtualFile) { - final Map> mapping = ContainerUtil.newHashMap(); + Function mapping = null; - try { - byte[] bytes = ((VirtualFile)classSource).contentsToByteArray(false); - new ClassReader(bytes).accept(new ClassVisitor(ASM_API) { - @Override - public void visitInnerClass(String name, String outerName, String innerName, int access) { - if (outerName != null && innerName != null) { - mapping.put(name, pair(outerName, innerName)); - } - } - }, ClsFileImpl.EMPTY_ATTRIBUTES, ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES); - } - catch (Exception ignored) { } - - if (!mapping.isEmpty()) { - return new Function() { - @Override - public String fun(String internalName) { - String className = internalName; - - if (className.indexOf('$') >= 0) { - Pair p = mapping.get(className); - if (p == null) { - return GUESSING_MAPPER.fun(className); - } - className = p.first; - if (p.second != null) { - className = fun(p.first) + '.' + p.second; - mapping.put(className, pair(className, (String)null)); - } - } - - return className.replace('/', '.'); - } - }; + if (classSource instanceof Pair) { + Object second = ((Pair)classSource).second; + if (second instanceof byte[]) { + mapping = createMapping((byte[])second); } } + else if (classSource instanceof VirtualFile) { + try { + byte[] bytes = ((VirtualFile)classSource).contentsToByteArray(false); + mapping = createMapping(bytes); + } + catch (IOException ignored) { } + } - return GUESSING_MAPPER; + return mapping != null ? mapping : GUESSING_MAPPER; + } + + private static Function createMapping(byte[] classBytes) { + final Map> mapping = ContainerUtil.newHashMap(); + + try { + new ClassReader(classBytes).accept(new ClassVisitor(ASM_API) { + @Override + public void visitInnerClass(String name, String outerName, String innerName, int access) { + if (outerName != null && innerName != null) { + mapping.put(name, pair(outerName, innerName)); + } + } + }, ClsFileImpl.EMPTY_ATTRIBUTES, ClassReader.SKIP_DEBUG | ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES); + } + catch (Exception ignored) { } + + if (!mapping.isEmpty()) { + return new Function() { + @Override + public String fun(String internalName) { + String className = internalName; + + if (className.indexOf('$') >= 0) { + Pair p = mapping.get(className); + if (p == null) { + return GUESSING_MAPPER.fun(className); + } + className = p.first; + if (p.second != null) { + className = fun(p.first) + '.' + p.second; + mapping.put(className, pair(className, (String)null)); + } + } + + return className.replace('/', '.'); + } + }; + } + + return null; } public static final Function GUESSING_MAPPER = new Function() {