mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
[java] optimizes file content reading for .class stub building
This commit is contained in:
@@ -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<PsiClassHolderFileStub>
|
||||
PsiJavaFileStub stub = stubBuilder.fun(packageName);
|
||||
|
||||
try {
|
||||
StubBuildingVisitor<VirtualFile> visitor = new StubBuildingVisitor<VirtualFile>(file, STRATEGY, stub, 0, className);
|
||||
FileContentPair source = new FileContentPair(file, bytes);
|
||||
StubBuildingVisitor<FileContentPair> visitor = new StubBuildingVisitor<FileContentPair>(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<PsiClassHolderFileStub>
|
||||
return p > 0 ? internalName.substring(0, p).replace('/', '.') : "";
|
||||
}
|
||||
|
||||
private static final InnerClassSourceStrategy<VirtualFile> STRATEGY = new InnerClassSourceStrategy<VirtualFile>() {
|
||||
@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<VirtualFile, byte[]> {
|
||||
public FileContentPair(VirtualFile file, byte[] content) {
|
||||
super(file, content);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void accept(VirtualFile innerClass, StubBuildingVisitor<VirtualFile> 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<FileContentPair> STRATEGY = new InnerClassSourceStrategy<FileContentPair>() {
|
||||
@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<FileContentPair> visitor) {
|
||||
new ClassReader(innerClass.second).accept(visitor, EMPTY_ATTRIBUTES, ClassReader.SKIP_FRAMES);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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<T> {
|
||||
@Nullable
|
||||
T findInnerClass(String name, T outerClass);
|
||||
T findInnerClass(String innerName, T outerClass);
|
||||
|
||||
void accept(T innerClass, StubBuildingVisitor<T> visitor);
|
||||
}
|
||||
}
|
||||
@@ -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<T> extends ClassVisitor {
|
||||
}
|
||||
|
||||
private static Function<String, String> createMapping(Object classSource) {
|
||||
if (classSource instanceof VirtualFile) {
|
||||
final Map<String, Pair<String, String>> mapping = ContainerUtil.newHashMap();
|
||||
Function<String, String> 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<String, String>() {
|
||||
@Override
|
||||
public String fun(String internalName) {
|
||||
String className = internalName;
|
||||
|
||||
if (className.indexOf('$') >= 0) {
|
||||
Pair<String, String> 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<String, String> createMapping(byte[] classBytes) {
|
||||
final Map<String, Pair<String, String>> 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<String, String>() {
|
||||
@Override
|
||||
public String fun(String internalName) {
|
||||
String className = internalName;
|
||||
|
||||
if (className.indexOf('$') >= 0) {
|
||||
Pair<String, String> 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<String, String> GUESSING_MAPPER = new Function<String, String>() {
|
||||
|
||||
Reference in New Issue
Block a user