Restructure JetDecompiledData
JetDecompiledData now stores file text and uses descriptors serialized to String to find declarations
This commit is contained in:
@@ -16,74 +16,64 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.plugin.libraries;
|
package org.jetbrains.jet.plugin.libraries;
|
||||||
|
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.util.TextRange;
|
import com.intellij.openapi.util.TextRange;
|
||||||
import com.intellij.psi.PsiClass;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiManager;
|
||||||
import com.intellij.psi.PsiField;
|
|
||||||
import com.intellij.psi.impl.compiled.ClsElementImpl;
|
|
||||||
import com.intellij.psi.impl.compiled.ClsFileImpl;
|
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.jet.di.InjectorForJavaDescriptorResolver;
|
import org.jetbrains.jet.di.InjectorForJavaDescriptorResolver;
|
||||||
import org.jetbrains.jet.lang.descriptors.*;
|
import org.jetbrains.jet.lang.descriptors.*;
|
||||||
import org.jetbrains.jet.lang.psi.JetDeclaration;
|
|
||||||
import org.jetbrains.jet.lang.psi.JetFile;
|
import org.jetbrains.jet.lang.psi.JetFile;
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContext;
|
|
||||||
import org.jetbrains.jet.lang.resolve.BindingContextUtils;
|
|
||||||
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
|
import org.jetbrains.jet.lang.resolve.BindingTraceContext;
|
||||||
import org.jetbrains.jet.lang.resolve.MemberComparator;
|
import org.jetbrains.jet.lang.resolve.MemberComparator;
|
||||||
import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils;
|
|
||||||
import org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule;
|
import org.jetbrains.jet.lang.resolve.java.DescriptorSearchRule;
|
||||||
import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
|
import org.jetbrains.jet.lang.resolve.java.JavaDescriptorResolver;
|
||||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
import org.jetbrains.jet.lang.resolve.java.resolver.KotlinClassFileHeader;
|
||||||
import org.jetbrains.jet.lang.resolve.name.FqName;
|
import org.jetbrains.jet.lang.resolve.name.FqName;
|
||||||
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
import org.jetbrains.jet.renderer.DescriptorRenderer;
|
||||||
import org.jetbrains.jet.renderer.DescriptorRendererBuilder;
|
import org.jetbrains.jet.renderer.DescriptorRendererBuilder;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
public class DecompiledDataFactory {
|
import static org.jetbrains.jet.plugin.libraries.JetDecompiledData.descriptorToKey;
|
||||||
|
|
||||||
|
public final class DecompiledDataFactory {
|
||||||
private static final String DECOMPILED_COMMENT = "/* compiled code */";
|
private static final String DECOMPILED_COMMENT = "/* compiled code */";
|
||||||
private static final DescriptorRenderer DESCRIPTOR_RENDERER =
|
public static final DescriptorRenderer DESCRIPTOR_RENDERER =
|
||||||
new DescriptorRendererBuilder().setWithDefinedIn(false).setClassWithPrimaryConstructor(true).build();
|
new DescriptorRendererBuilder().setWithDefinedIn(false).setClassWithPrimaryConstructor(true).build();
|
||||||
|
@NotNull
|
||||||
private final StringBuilder builder = new StringBuilder();
|
private final StringBuilder builder = new StringBuilder();
|
||||||
private final ClsFileImpl clsFile;
|
@NotNull
|
||||||
private final BindingContext bindingContext;
|
private final Map<String, TextRange> renderedDescriptorsToRange = new HashMap<String, TextRange>();
|
||||||
private final Map<PsiElement, TextRange> clsMembersToRanges = new HashMap<PsiElement, TextRange>();
|
@NotNull
|
||||||
|
|
||||||
private final Map<ClsElementImpl, JetDeclaration> clsElementsToJetElements = new HashMap<ClsElementImpl, JetDeclaration>();
|
|
||||||
private final JavaDescriptorResolver javaDescriptorResolver;
|
private final JavaDescriptorResolver javaDescriptorResolver;
|
||||||
|
@NotNull
|
||||||
|
private final KotlinClassFileHeader kotlinClassFileHeader;
|
||||||
|
@NotNull
|
||||||
|
private final VirtualFile classFile;
|
||||||
|
@NotNull
|
||||||
|
private final Project project;
|
||||||
|
|
||||||
private DecompiledDataFactory(ClsFileImpl clsFile) {
|
private DecompiledDataFactory(@NotNull VirtualFile classFile, @NotNull Project project) {
|
||||||
this.clsFile = clsFile;
|
this.classFile = classFile;
|
||||||
|
this.project = project;
|
||||||
BindingTraceContext trace = new BindingTraceContext();
|
InjectorForJavaDescriptorResolver injector =
|
||||||
this.bindingContext = trace.getBindingContext();
|
new InjectorForJavaDescriptorResolver(project, new BindingTraceContext());
|
||||||
InjectorForJavaDescriptorResolver injector = new InjectorForJavaDescriptorResolver(clsFile.getProject(), trace);
|
|
||||||
this.javaDescriptorResolver = injector.getJavaDescriptorResolver();
|
this.javaDescriptorResolver = injector.getJavaDescriptorResolver();
|
||||||
|
this.kotlinClassFileHeader = KotlinClassFileHeader.readKotlinHeaderFromClassFile(classFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
static JetDecompiledData createDecompiledData(@NotNull ClsFileImpl clsFile) {
|
static JetDecompiledData createDecompiledData(@NotNull VirtualFile virtualFile, @NotNull Project project) {
|
||||||
return new DecompiledDataFactory(clsFile).build();
|
return new DecompiledDataFactory(virtualFile, project).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private JetDecompiledData build() {
|
private JetDecompiledData build() {
|
||||||
builder.append("// IntelliJ API Decompiler stub source generated from a class file\n" +
|
FqName packageFqName = kotlinClassFileHeader.getJvmClassName().getFqName().parent();
|
||||||
"// Implementation of methods is not available");
|
appendDecompiledTextAndPackageName(packageFqName);
|
||||||
builder.append("\n\n");
|
KotlinClassFileHeader.HeaderType type = kotlinClassFileHeader.getType();
|
||||||
|
if (type == KotlinClassFileHeader.HeaderType.PACKAGE) {
|
||||||
String packageName = clsFile.getPackageName();
|
NamespaceDescriptor nd = javaDescriptorResolver.resolveNamespace(packageFqName, DescriptorSearchRule.INCLUDE_KOTLIN);
|
||||||
if (packageName.length() > 0) {
|
|
||||||
builder.append("package ").append(packageName).append("\n\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
PsiClass psiClass = clsFile.getClasses()[0];
|
|
||||||
|
|
||||||
if (DescriptorResolverUtils.isCompiledKotlinPackageClass(psiClass)) {
|
|
||||||
NamespaceDescriptor nd = javaDescriptorResolver.resolveNamespace(new FqName(packageName), DescriptorSearchRule.INCLUDE_KOTLIN);
|
|
||||||
|
|
||||||
if (nd != null) {
|
if (nd != null) {
|
||||||
for (DeclarationDescriptor member : sortDeclarations(nd.getMemberScope().getAllDescriptors())) {
|
for (DeclarationDescriptor member : sortDeclarations(nd.getMemberScope().getAllDescriptors())) {
|
||||||
if (member instanceof ClassDescriptor || member instanceof NamespaceDescriptor
|
if (member instanceof ClassDescriptor || member instanceof NamespaceDescriptor
|
||||||
@@ -96,29 +86,28 @@ public class DecompiledDataFactory {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ClassDescriptor cd = javaDescriptorResolver.resolveClass(new FqName(psiClass.getQualifiedName()), DescriptorSearchRule.INCLUDE_KOTLIN);
|
assert type == KotlinClassFileHeader.HeaderType.CLASS;
|
||||||
|
ClassDescriptor cd = javaDescriptorResolver.resolveClass(kotlinClassFileHeader.getJvmClassName().getFqName(),
|
||||||
|
DescriptorSearchRule.INCLUDE_KOTLIN);
|
||||||
if (cd != null) {
|
if (cd != null) {
|
||||||
appendDescriptor(cd, "");
|
appendDescriptor(cd, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JetFile jetFile = JetDummyClassFileViewProvider.createJetFile(clsFile.getManager(), clsFile.getVirtualFile(), builder.toString());
|
JetFile jetFile = JetDummyClassFileViewProvider.createJetFile(PsiManager.getInstance(project), classFile, builder.toString());
|
||||||
for (Map.Entry<PsiElement, TextRange> clsMemberToRange : clsMembersToRanges.entrySet()) {
|
return new JetDecompiledData(jetFile, renderedDescriptorsToRange);
|
||||||
PsiElement clsMember = clsMemberToRange.getKey();
|
|
||||||
assert clsMember instanceof ClsElementImpl;
|
|
||||||
|
|
||||||
TextRange range = clsMemberToRange.getValue();
|
|
||||||
JetDeclaration jetDeclaration = PsiTreeUtil.findElementOfClassAtRange(jetFile, range.getStartOffset(), range.getEndOffset(),
|
|
||||||
JetDeclaration.class);
|
|
||||||
assert jetDeclaration != null : "Can't find declaration at " + range + ": "
|
|
||||||
+ jetFile.getText().substring(range.getStartOffset(), range.getEndOffset());
|
|
||||||
clsElementsToJetElements.put((ClsElementImpl) clsMember, jetDeclaration);
|
|
||||||
}
|
|
||||||
|
|
||||||
return new JetDecompiledData(jetFile, clsElementsToJetElements);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static List<DeclarationDescriptor> sortDeclarations(Collection<DeclarationDescriptor> input) {
|
private void appendDecompiledTextAndPackageName(@NotNull FqName packageName) {
|
||||||
|
builder.append("// IntelliJ API Decompiler stub source generated from a class file\n" +
|
||||||
|
"// Implementation of methods is not available");
|
||||||
|
builder.append("\n\n");
|
||||||
|
if (!packageName.isRoot()) {
|
||||||
|
builder.append("package ").append(packageName).append("\n\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<DeclarationDescriptor> sortDeclarations(@NotNull Collection<DeclarationDescriptor> input) {
|
||||||
ArrayList<DeclarationDescriptor> r = new ArrayList<DeclarationDescriptor>(input);
|
ArrayList<DeclarationDescriptor> r = new ArrayList<DeclarationDescriptor>(input);
|
||||||
Collections.sort(r, MemberComparator.INSTANCE);
|
Collections.sort(r, MemberComparator.INSTANCE);
|
||||||
return r;
|
return r;
|
||||||
@@ -150,10 +139,11 @@ public class DecompiledDataFactory {
|
|||||||
ClassDescriptor classDescriptor = (ClassDescriptor) descriptor;
|
ClassDescriptor classDescriptor = (ClassDescriptor) descriptor;
|
||||||
boolean firstPassed = false;
|
boolean firstPassed = false;
|
||||||
String subindent = indent + " ";
|
String subindent = indent + " ";
|
||||||
if (classDescriptor.getClassObjectDescriptor() != null) {
|
ClassDescriptor classObjectDescriptor = classDescriptor.getClassObjectDescriptor();
|
||||||
|
if (classObjectDescriptor != null) {
|
||||||
firstPassed = true;
|
firstPassed = true;
|
||||||
builder.append(subindent);
|
builder.append(subindent);
|
||||||
appendDescriptor(classDescriptor.getClassObjectDescriptor(), subindent);
|
appendDescriptor(classObjectDescriptor, subindent);
|
||||||
}
|
}
|
||||||
for (DeclarationDescriptor member : sortDeclarations(classDescriptor.getDefaultType().getMemberScope().getAllDescriptors())) {
|
for (DeclarationDescriptor member : sortDeclarations(classDescriptor.getDefaultType().getMemberScope().getAllDescriptors())) {
|
||||||
if (member.getContainingDeclaration() != descriptor) {
|
if (member.getContainingDeclaration() != descriptor) {
|
||||||
@@ -180,28 +170,18 @@ public class DecompiledDataFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
builder.append("\n");
|
builder.append("\n");
|
||||||
saveClsMemberToRange(descriptor, startOffset, endOffset);
|
saveDescriptorToRange(descriptor, startOffset, endOffset);
|
||||||
|
|
||||||
if (descriptor instanceof ClassDescriptor) {
|
if (descriptor instanceof ClassDescriptor) {
|
||||||
ConstructorDescriptor primaryConstructor = ((ClassDescriptor) descriptor).getUnsubstitutedPrimaryConstructor();
|
ConstructorDescriptor primaryConstructor = ((ClassDescriptor) descriptor).getUnsubstitutedPrimaryConstructor();
|
||||||
if (primaryConstructor != null) {
|
if (primaryConstructor != null) {
|
||||||
saveClsMemberToRange(primaryConstructor, startOffset, endOffset);
|
saveDescriptorToRange(primaryConstructor, startOffset, endOffset);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveClsMemberToRange(DeclarationDescriptor descriptor, int startOffset, int endOffset) {
|
private void saveDescriptorToRange(DeclarationDescriptor descriptor, int startOffset, int endOffset) {
|
||||||
PsiElement clsMember = BindingContextUtils.descriptorToDeclaration(bindingContext, descriptor);
|
renderedDescriptorsToRange.put(descriptorToKey(descriptor), new TextRange(startOffset, endOffset));
|
||||||
if (clsMember != null) {
|
|
||||||
clsMembersToRanges.put(clsMember, new TextRange(startOffset, endOffset));
|
|
||||||
|
|
||||||
if (descriptor instanceof ClassDescriptor && ((ClassDescriptor) descriptor).getKind() == ClassKind.OBJECT) {
|
|
||||||
assert clsMember instanceof PsiClass;
|
|
||||||
PsiField instanceField = ((PsiClass) clsMember).findFieldByName(JvmAbi.INSTANCE_FIELD, false);
|
|
||||||
assert instanceField != null;
|
|
||||||
clsMembersToRanges.put(instanceField, new TextRange(startOffset, endOffset));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean isNamedObjectProperty(@NotNull DeclarationDescriptor descriptor) {
|
private static boolean isNamedObjectProperty(@NotNull DeclarationDescriptor descriptor) {
|
||||||
|
|||||||
@@ -23,12 +23,11 @@ import com.intellij.openapi.fileTypes.SyntaxHighlighter;
|
|||||||
import com.intellij.openapi.project.DumbService;
|
import com.intellij.openapi.project.DumbService;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.psi.impl.compiled.ClsFileImpl;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.jet.plugin.highlighter.JetHighlighter;
|
import org.jetbrains.jet.plugin.highlighter.JetHighlighter;
|
||||||
|
|
||||||
public class JetContentBasedFileSubstitutor implements ContentBasedClassFileProcessor {
|
public final class JetContentBasedFileSubstitutor implements ContentBasedClassFileProcessor {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isApplicable(@Nullable Project project, @NotNull final VirtualFile file) {
|
public boolean isApplicable(@Nullable Project project, @NotNull final VirtualFile file) {
|
||||||
@@ -48,16 +47,14 @@ public class JetContentBasedFileSubstitutor implements ContentBasedClassFileProc
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return JetDecompiledData.isKotlinFile(project, file);
|
return DecompiledUtils.isKotlinCompiledFile(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@Override
|
@Override
|
||||||
public String obtainFileText(Project project, VirtualFile file) {
|
public String obtainFileText(Project project, VirtualFile file) {
|
||||||
if (JetDecompiledData.isKotlinFile(project, file)) {
|
if (DecompiledUtils.isKotlinCompiledFile(file)) {
|
||||||
ClsFileImpl clsFile = JetDecompiledData.getClsFile(project, file);
|
return JetDecompiledData.getDecompiledData(file, project).getFileText();
|
||||||
assert clsFile != null;
|
|
||||||
return JetDecompiledData.getDecompiledData(clsFile).getJetFile().getText();
|
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,85 +16,77 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.plugin.libraries;
|
package org.jetbrains.jet.plugin.libraries;
|
||||||
|
|
||||||
import com.intellij.ide.highlighter.JavaClassFileType;
|
|
||||||
import com.intellij.openapi.fileTypes.FileTypeManager;
|
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.util.Key;
|
import com.intellij.openapi.util.Key;
|
||||||
|
import com.intellij.openapi.util.TextRange;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
import com.intellij.psi.PsiManager;
|
|
||||||
import com.intellij.psi.impl.compiled.ClsElementImpl;
|
|
||||||
import com.intellij.psi.impl.compiled.ClsFileImpl;
|
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
import org.jetbrains.annotations.TestOnly;
|
import org.jetbrains.annotations.TestOnly;
|
||||||
|
import org.jetbrains.jet.lang.descriptors.DeclarationDescriptor;
|
||||||
import org.jetbrains.jet.lang.psi.JetDeclaration;
|
import org.jetbrains.jet.lang.psi.JetDeclaration;
|
||||||
import org.jetbrains.jet.lang.psi.JetFile;
|
import org.jetbrains.jet.lang.psi.JetFile;
|
||||||
import org.jetbrains.jet.lang.resolve.java.DescriptorResolverUtils;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized")
|
@SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized")
|
||||||
public class JetDecompiledData {
|
public class JetDecompiledData {
|
||||||
private final JetFile jetFile;
|
|
||||||
private final Map<ClsElementImpl, JetDeclaration> clsElementsToJetElements;
|
|
||||||
|
|
||||||
private static final Object LOCK = new String("decompiled data lock");
|
|
||||||
private static final Key<JetDecompiledData> USER_DATA_KEY = new Key<JetDecompiledData>("USER_DATA_KEY");
|
private static final Key<JetDecompiledData> USER_DATA_KEY = new Key<JetDecompiledData>("USER_DATA_KEY");
|
||||||
|
private static final Object LOCK = new String("decompiled data lock");
|
||||||
|
|
||||||
JetDecompiledData(JetFile jetFile, Map<ClsElementImpl, JetDeclaration> clsElementJetDeclarationMap) {
|
@NotNull
|
||||||
this.jetFile = jetFile;
|
private final JetFile file;
|
||||||
clsElementsToJetElements = clsElementJetDeclarationMap;
|
@NotNull
|
||||||
|
private final Map<String, TextRange> renderedDescriptorsToRanges;
|
||||||
|
|
||||||
|
JetDecompiledData(@NotNull JetFile file, @NotNull Map<String,TextRange> renderedDescriptorsToRanges) {
|
||||||
|
this.file = file;
|
||||||
|
this.renderedDescriptorsToRanges = renderedDescriptorsToRanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public JetFile getJetFile() {
|
public String getFileText() {
|
||||||
return jetFile;
|
return file.getText();
|
||||||
}
|
|
||||||
|
|
||||||
public JetDeclaration getJetDeclarationByClsElement(ClsElementImpl clsElement) {
|
|
||||||
return clsElementsToJetElements.get(clsElement);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Nullable
|
|
||||||
public static ClsFileImpl getClsFile(@NotNull Project project, @NotNull VirtualFile vFile) {
|
|
||||||
if (!FileTypeManager.getInstance().isFileOfType(vFile, JavaClassFileType.INSTANCE)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
PsiFile psiFile = PsiManager.getInstance(project).findFile(vFile);
|
|
||||||
if (!(psiFile instanceof ClsFileImpl)) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
ClsFileImpl clsFile = (ClsFileImpl) psiFile;
|
|
||||||
if (clsFile.getClasses().length != 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
return clsFile;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isKotlinFile(@NotNull Project project, @NotNull VirtualFile vFile) {
|
|
||||||
ClsFileImpl clsFile = getClsFile(project, vFile);
|
|
||||||
return clsFile != null && isKotlinFile(clsFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isKotlinFile(@NotNull ClsFileImpl clsFile) {
|
|
||||||
return DescriptorResolverUtils.isCompiledKotlinClassOrPackageClass(clsFile.getClasses()[0]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JetDecompiledData getDecompiledData(@NotNull ClsFileImpl clsFile) {
|
public static JetDecompiledData getDecompiledData(@NotNull VirtualFile virtualFile, @NotNull Project project) {
|
||||||
synchronized (LOCK) {
|
synchronized (LOCK) {
|
||||||
if (clsFile.getUserData(USER_DATA_KEY) == null) {
|
if (virtualFile.getUserData(USER_DATA_KEY) == null) {
|
||||||
clsFile.putUserData(USER_DATA_KEY, DecompiledDataFactory.createDecompiledData(clsFile));
|
virtualFile.putUserData(USER_DATA_KEY, DecompiledDataFactory.createDecompiledData(virtualFile, project));
|
||||||
}
|
}
|
||||||
JetDecompiledData decompiledData = clsFile.getUserData(USER_DATA_KEY);
|
JetDecompiledData decompiledData = virtualFile.getUserData(USER_DATA_KEY);
|
||||||
assert decompiledData != null;
|
assert decompiledData != null;
|
||||||
return decompiledData;
|
return decompiledData;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestOnly
|
@TestOnly
|
||||||
Map<ClsElementImpl, JetDeclaration> getClsElementsToJetElements() {
|
@NotNull
|
||||||
return clsElementsToJetElements;
|
public Map<String, TextRange> getRenderedDescriptorsToRanges() {
|
||||||
|
return renderedDescriptorsToRanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public JetDeclaration getDeclarationForDescriptor(@NotNull DeclarationDescriptor descriptor) {
|
||||||
|
String key = descriptorToKey(descriptor);
|
||||||
|
TextRange range = renderedDescriptorsToRanges.get(key);
|
||||||
|
if (range == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return PsiTreeUtil.findElementOfClassAtRange(file, range.getStartOffset(), range.getEndOffset(), JetDeclaration.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: should use more accurate way to identify descriptors
|
||||||
|
@NotNull
|
||||||
|
static String descriptorToKey(@NotNull DeclarationDescriptor descriptor) {
|
||||||
|
return DecompiledDataFactory.DESCRIPTOR_RENDERER.render(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
public JetFile getFile() {
|
||||||
|
return file;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,17 +4,17 @@
|
|||||||
package testData.libraries
|
package testData.libraries
|
||||||
|
|
||||||
[[public final enum class Color(rgb: jet.Int) : jet.Enum<testData.libraries.Color> {
|
[[public final enum class Color(rgb: jet.Int) : jet.Enum<testData.libraries.Color> {
|
||||||
public class object {
|
[[public class object {
|
||||||
[public final val BLUE: testData.libraries.Color] /* compiled code */
|
[public final val BLUE: testData.libraries.Color] /* compiled code */
|
||||||
|
|
||||||
[public final val GREEN: testData.libraries.Color] /* compiled code */
|
[public final val GREEN: testData.libraries.Color] /* compiled code */
|
||||||
|
|
||||||
[public final val RED: testData.libraries.Color] /* compiled code */
|
[public final val RED: testData.libraries.Color] /* compiled code */
|
||||||
|
|
||||||
public final fun valueOf(value: jet.String): testData.libraries.Color { /* compiled code */ }
|
[public final fun valueOf(value: jet.String): testData.libraries.Color { /* compiled code */ }]
|
||||||
|
|
||||||
public final fun values(): jet.Array<testData.libraries.Color> { /* compiled code */ }
|
[public final fun values(): jet.Array<testData.libraries.Color> { /* compiled code */ }]
|
||||||
}
|
}]]
|
||||||
|
|
||||||
[internal final val rgb: jet.Int] /* compiled code */
|
[internal final val rgb: jet.Int] /* compiled code */
|
||||||
}]]
|
}]]
|
||||||
@@ -4,9 +4,9 @@
|
|||||||
package testData.libraries
|
package testData.libraries
|
||||||
|
|
||||||
[[public final class WithInnerAndObject() {
|
[[public final class WithInnerAndObject() {
|
||||||
public class object {
|
[[public class object {
|
||||||
[internal final fun foo(): jet.Unit { /* compiled code */ }]
|
[internal final fun foo(): jet.Unit { /* compiled code */ }]
|
||||||
}
|
}]]
|
||||||
|
|
||||||
[[internal final class MyInner() {
|
[[internal final class MyInner() {
|
||||||
[internal trait MyInnerInner {
|
[internal trait MyInnerInner {
|
||||||
|
|||||||
@@ -4,6 +4,6 @@
|
|||||||
package testData.libraries
|
package testData.libraries
|
||||||
|
|
||||||
[[public final class WithTraitClassObject() {
|
[[public final class WithTraitClassObject() {
|
||||||
public class object : testData.libraries.SimpleTrait {
|
[[public class object : testData.libraries.SimpleTrait {
|
||||||
}
|
}]]
|
||||||
}]]
|
}]]
|
||||||
|
|||||||
+27
-22
@@ -16,18 +16,21 @@
|
|||||||
|
|
||||||
package org.jetbrains.jet.plugin.libraries;
|
package org.jetbrains.jet.plugin.libraries;
|
||||||
|
|
||||||
|
import com.beust.jcommander.internal.Maps;
|
||||||
import com.intellij.openapi.editor.Document;
|
import com.intellij.openapi.editor.Document;
|
||||||
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||||
import com.intellij.openapi.util.TextRange;
|
import com.intellij.openapi.util.TextRange;
|
||||||
import com.intellij.openapi.util.text.StringUtil;
|
import com.intellij.openapi.util.text.StringUtil;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
import com.intellij.psi.impl.compiled.ClsElementImpl;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import com.intellij.psi.impl.compiled.ClsFileImpl;
|
|
||||||
import org.jetbrains.jet.lang.psi.JetDeclaration;
|
import org.jetbrains.jet.lang.psi.JetDeclaration;
|
||||||
|
import org.jetbrains.jet.lang.psi.JetFile;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.jetbrains.jet.plugin.libraries.JetDecompiledData.getDecompiledData;
|
||||||
|
|
||||||
public class NavigateToDecompiledLibraryTest extends AbstractNavigateToLibraryTest {
|
public class NavigateToDecompiledLibraryTest extends AbstractNavigateToLibraryTest {
|
||||||
private VirtualFile classFile;
|
private VirtualFile classFile;
|
||||||
|
|
||||||
@@ -77,15 +80,15 @@ public class NavigateToDecompiledLibraryTest extends AbstractNavigateToLibraryTe
|
|||||||
|
|
||||||
private void doTest() {
|
private void doTest() {
|
||||||
classFile = getClassFile();
|
classFile = getClassFile();
|
||||||
|
JetDecompiledData decompiledData = JetDecompiledData.getDecompiledData(classFile, getProject());
|
||||||
Map<ClsElementImpl, JetDeclaration> map = getDecompiledData(classFile).getClsElementsToJetElements();
|
Map<String, JetDeclaration> map = getRenderedDescriptorToKotlinPsiMap(decompiledData.getFile(),
|
||||||
checkNavigationElements(map);
|
getDecompiledData(classFile, getProject()) .getRenderedDescriptorsToRanges());
|
||||||
String decompiledTextWithMarks = getDecompiledTextWithMarks(map);
|
String decompiledTextWithMarks = getDecompiledTextWithMarks(map);
|
||||||
|
|
||||||
assertSameLinesWithFile(TEST_DATA_PATH + "/decompiled/" + getTestName(false) + ".kt", decompiledTextWithMarks);
|
assertSameLinesWithFile(TEST_DATA_PATH + "/decompiled/" + getTestName(false) + ".kt", decompiledTextWithMarks);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getDecompiledTextWithMarks(Map<ClsElementImpl, JetDeclaration> map) {
|
private String getDecompiledTextWithMarks(Map<String, JetDeclaration> map) {
|
||||||
String decompiledText = getDecompiledText();
|
String decompiledText = getDecompiledText();
|
||||||
|
|
||||||
int[] openings = new int[decompiledText.length() + 1];
|
int[] openings = new int[decompiledText.length() + 1];
|
||||||
@@ -113,21 +116,6 @@ public class NavigateToDecompiledLibraryTest extends AbstractNavigateToLibraryTe
|
|||||||
return document.getText();
|
return document.getText();
|
||||||
}
|
}
|
||||||
|
|
||||||
private JetDecompiledData getDecompiledData(VirtualFile classFile) {
|
|
||||||
PsiFile classPsiFile = getPsiManager().findFile(classFile);
|
|
||||||
assertInstanceOf(classPsiFile, ClsFileImpl.class);
|
|
||||||
ClsFileImpl clsFile = (ClsFileImpl) classPsiFile;
|
|
||||||
return JetDecompiledData.getDecompiledData(clsFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void checkNavigationElements(Map<ClsElementImpl, JetDeclaration> map) {
|
|
||||||
PsiFile classPsiFile = getPsiManager().findFile(classFile);
|
|
||||||
for (Map.Entry<ClsElementImpl, JetDeclaration> clsToJet : map.entrySet()) {
|
|
||||||
assertSame(classPsiFile, clsToJet.getKey().getContainingFile());
|
|
||||||
assertSame(clsToJet.getValue(), clsToJet.getKey().getNavigationElement());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private VirtualFile getClassFile() {
|
private VirtualFile getClassFile() {
|
||||||
VirtualFile packageDir = libraryDir.findFileByRelativePath(PACKAGE.replace(".", "/"));
|
VirtualFile packageDir = libraryDir.findFileByRelativePath(PACKAGE.replace(".", "/"));
|
||||||
assertNotNull(packageDir);
|
assertNotNull(packageDir);
|
||||||
@@ -140,4 +128,21 @@ public class NavigateToDecompiledLibraryTest extends AbstractNavigateToLibraryTe
|
|||||||
protected boolean isWithSources() {
|
protected boolean isWithSources() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
|
private static Map<String, JetDeclaration> getRenderedDescriptorToKotlinPsiMap(
|
||||||
|
@NotNull JetFile file, @NotNull Map<String, TextRange> renderedDescriptorsToRanges
|
||||||
|
) {
|
||||||
|
Map<String, JetDeclaration> renderedDescriptorsToJetDeclarations = Maps.newHashMap();
|
||||||
|
for (Map.Entry<String, TextRange> renderedDescriptorToRange : renderedDescriptorsToRanges.entrySet()) {
|
||||||
|
String renderedDescriptor = renderedDescriptorToRange.getKey();
|
||||||
|
TextRange range = renderedDescriptorToRange.getValue();
|
||||||
|
JetDeclaration jetDeclaration = PsiTreeUtil.findElementOfClassAtRange(file, range.getStartOffset(), range.getEndOffset(),
|
||||||
|
JetDeclaration.class);
|
||||||
|
assert jetDeclaration != null : "Can't find declaration at " + range + ": "
|
||||||
|
+ file.getText().substring(range.getStartOffset(), range.getEndOffset());
|
||||||
|
renderedDescriptorsToJetDeclarations.put(renderedDescriptor, jetDeclaration);
|
||||||
|
}
|
||||||
|
return renderedDescriptorsToJetDeclarations;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user