rewrite class file stub builder as full decompiler
authorDmitry Batkovich <dmitry.batkovich@jetbrains.com>
Wed, 12 Aug 2020 07:05:41 +0000 (10:05 +0300)
committerintellij-monorepo-bot <intellij-monorepo-bot-no-reply@jetbrains.com>
Wed, 12 Aug 2020 11:40:33 +0000 (11:40 +0000)
GitOrigin-RevId: ca86f254c7f61fd25919afeb2b5bd3d89bb67a9f

java/java-psi-api/src/com/intellij/psi/compiled/ClassFileDecompilers.java
java/java-psi-impl/src/META-INF/JavaPsiPlugin.xml
java/java-psi-impl/src/com/intellij/psi/ClassFileViewProviderFactory.java
java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileDecompiler.java
java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClassFileStubBuilder.java
java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsDecompilerImpl.java [new file with mode: 0644]
java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java
plugins/java-decompiler/plugin/src/META-INF/plugin.xml
plugins/java-decompiler/plugin/src/org/jetbrains/java/decompiler/IdeaDecompiler.kt

index 7b75f87858ee0a141497b4974e409447010b6581..316d948be63a7f65dfa070e47da2196ad76de6e4 100644 (file)
@@ -10,7 +10,6 @@ import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.FileViewProvider;
 import com.intellij.psi.PsiManager;
 import org.jetbrains.annotations.NotNull;
-import org.jetbrains.annotations.Nullable;
 
 /**
  * An API to extend default IDEA .class file decompiler and handle files compiled from sources other than Java.
@@ -90,7 +89,8 @@ public final class ClassFileDecompilers {
     }
   }
 
-  public @Nullable Decompiler find(@NotNull VirtualFile file) {
-    return EP_NAME.findFirstSafe(decompiler -> (decompiler instanceof Light || decompiler instanceof Full) && decompiler.accepts(file));
+  @SuppressWarnings("unchecked")
+  public <D extends Decompiler> D find(@NotNull VirtualFile file, @NotNull Class<D> decompilerClass) {
+    return (D)EP_NAME.findFirstSafe(d -> decompilerClass.isInstance(d) && d.accepts(file));
   }
 }
\ No newline at end of file
index 77e0e12d618c2d9967a2700dd6c301fdbf419a09..cdd8a3a84d6fa246ccd280c5118aa4bbe51bb92e 100644 (file)
     <codeInsight.containerProvider implementation="com.intellij.codeInsight.JavaContainerProvider" id="JAVA"/>
     <constantExpressionEvaluator language="JAVA" implementationClass="com.intellij.psi.impl.PsiExpressionEvaluator" />
     <lang.psiAugmentProvider implementation="com.intellij.psi.impl.RecordAugmentProvider"/>
+    <psi.classFileDecompiler id="clsStubBuilder" implementation="com.intellij.psi.impl.compiled.ClsDecompilerImpl" order="last"/>
   </extensions>
 
   <extensions defaultExtensionNs="org.jetbrains.uast">
index 58622824cda8d8b6495587825500d38accaae125..bfb4c15290e91bd41a4b27c9ca1946bc71f2644f 100644 (file)
@@ -14,11 +14,7 @@ public class ClassFileViewProviderFactory implements FileViewProviderFactory {
                                                           Language language,
                                                           @NotNull PsiManager manager,
                                                           boolean eventSystemEnabled) {
-    ClassFileDecompilers.Decompiler decompiler = ClassFileDecompilers.getInstance().find(file);
-    if (decompiler instanceof Full) {
-      return ((Full)decompiler).createFileViewProvider(file, manager, eventSystemEnabled);
-    }
-
-    return new ClassFileViewProvider(manager, file, eventSystemEnabled);
+    Full decompiler = ClassFileDecompilers.getInstance().find(file, Full.class);
+    return decompiler.createFileViewProvider(file, manager, eventSystemEnabled);
   }
 }
\ No newline at end of file
index d61c1a93f07e70f530dbe50ee7ce6cd541f54c91..1faf4f811133d14047c1a79787b322a2d0f26f12 100644 (file)
@@ -14,7 +14,7 @@ public class ClassFileDecompiler implements BinaryFileDecompiler {
 
   @Override
   public @NotNull CharSequence decompile(@NotNull VirtualFile file) {
-    ClassFileDecompilers.Decompiler decompiler = ClassFileDecompilers.getInstance().find(file);
+    ClassFileDecompilers.Decompiler decompiler = ClassFileDecompilers.getInstance().find(file, ClassFileDecompilers.Decompiler.class);
     if (decompiler instanceof ClassFileDecompilers.Full) {
       PsiManager manager = PsiManager.getInstance(DefaultProjectFactory.getInstance().getDefaultProject());
       return ((ClassFileDecompilers.Full)decompiler).createFileViewProvider(file, manager, true).getContents();
@@ -29,6 +29,10 @@ public class ClassFileDecompiler implements BinaryFileDecompiler {
       }
     }
 
-    return ClsFileImpl.decompile(file);
+    throw new IllegalStateException(decompiler.getClass().getName() +
+                                    " should be on of " +
+                                    ClassFileDecompilers.Full.class.getName() +
+                                    " or " +
+                                    ClassFileDecompilers.Light.class.getName());
   }
 }
\ No newline at end of file
index f4d78b6850c3971e1a8ca81cf020e8ba98073cd2..5d1963722419264d0cfbb419dc70ebd8bfc6e93c 100644 (file)
@@ -4,9 +4,7 @@ package com.intellij.psi.impl.compiled;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.psi.compiled.ClassFileDecompilers;
-import com.intellij.psi.impl.source.JavaFileElementType;
 import com.intellij.psi.stubs.BinaryFileStubBuilder;
-import com.intellij.psi.stubs.PsiFileStub;
 import com.intellij.psi.stubs.Stub;
 import com.intellij.util.cls.ClsFormatException;
 import com.intellij.util.indexing.FileContent;
@@ -17,10 +15,10 @@ import java.util.stream.Stream;
 
 import static com.intellij.psi.compiled.ClassFileDecompilers.Full;
 
-public class ClassFileStubBuilder implements BinaryFileStubBuilder.CompositeBinaryFileStubBuilder<ClassFileDecompilers.Decompiler> {
+public class ClassFileStubBuilder implements BinaryFileStubBuilder.CompositeBinaryFileStubBuilder<Full> {
   private static final Logger LOG = Logger.getInstance(ClassFileStubBuilder.class);
 
-  public static final int STUB_VERSION = 25 + JavaFileElementType.STUB_VERSION;
+  public static final int STUB_VERSION = 26;
 
   @Override
   public boolean acceptsFile(@NotNull VirtualFile file) {
@@ -28,49 +26,35 @@ public class ClassFileStubBuilder implements BinaryFileStubBuilder.CompositeBina
   }
 
   @Override
-  public @NotNull Stream<ClassFileDecompilers.Decompiler> getAllSubBuilders() {
-    return ClassFileDecompilers.getInstance().EP_NAME.extensions().filter(decompiler -> decompiler instanceof Full);
+  public @NotNull Stream<Full> getAllSubBuilders() {
+    return ClassFileDecompilers.getInstance().EP_NAME.extensions().filter(d -> d instanceof Full).map(d -> (Full) d);
   }
 
   @Override
-  public @Nullable ClassFileDecompilers.Decompiler getSubBuilder(@NotNull FileContent fileContent) {
+  public @Nullable Full getSubBuilder(@NotNull FileContent fileContent) {
     return fileContent.getFile()
-      .computeWithPreloadedContentHint(fileContent.getContent(), () -> ClassFileDecompilers.getInstance().find(fileContent.getFile()));
+      .computeWithPreloadedContentHint(fileContent.getContent(), () -> ClassFileDecompilers.getInstance().find(fileContent.getFile(), Full.class));
   }
 
   @Override
-  public @NotNull String getSubBuilderVersion(@Nullable ClassFileDecompilers.Decompiler decompiler) {
+  public @NotNull String getSubBuilderVersion(@Nullable Full decompiler) {
     if (decompiler == null) return "default";
-    int version = decompiler instanceof Full ? ((Full)decompiler).getStubBuilder().getStubVersion() : 0;
+    int version = decompiler.getStubBuilder().getStubVersion();
     return decompiler.getClass().getName() + ":" + version;
   }
 
   @Override
-  public @Nullable Stub buildStubTree(@NotNull FileContent fileContent, @Nullable ClassFileDecompilers.Decompiler decompiler) {
+  public @Nullable Stub buildStubTree(@NotNull FileContent fileContent, @Nullable Full decompiler) {
+    if (decompiler == null) return null;
     return fileContent.getFile().computeWithPreloadedContentHint(fileContent.getContent(), () -> {
       VirtualFile file = fileContent.getFile();
       try {
-        if (decompiler instanceof Full) {
-          return ((Full)decompiler).getStubBuilder().buildFileStub(fileContent);
-        }
+        return decompiler.getStubBuilder().buildFileStub(fileContent);
       }
       catch (ClsFormatException e) {
         if (LOG.isDebugEnabled()) LOG.debug(file.getPath(), e);
         else LOG.info(file.getPath() + ": " + e.getMessage());
       }
-
-      try {
-        PsiFileStub<?> stub = ClsFileImpl.buildFileStub(file, fileContent.getContent());
-        if (stub == null && fileContent.getFileName().indexOf('$') < 0) {
-          LOG.info("No stub built for the file " + fileContent);
-        }
-        return stub;
-      }
-      catch (ClsFormatException e) {
-        if (LOG.isDebugEnabled()) LOG.debug(file.getPath(), e);
-        else LOG.info(file.getPath() + ": " + e.getMessage());
-      }
-
       return null;
     });
   }
diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsDecompilerImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsDecompilerImpl.java
new file mode 100644 (file)
index 0000000..b5058a0
--- /dev/null
@@ -0,0 +1,52 @@
+// Copyright 2000-2020 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
+package com.intellij.psi.impl.compiled;
+
+import com.intellij.openapi.diagnostic.Logger;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.ClassFileViewProvider;
+import com.intellij.psi.FileViewProvider;
+import com.intellij.psi.PsiManager;
+import com.intellij.psi.compiled.ClassFileDecompilers;
+import com.intellij.psi.compiled.ClsStubBuilder;
+import com.intellij.psi.impl.source.JavaFileElementType;
+import com.intellij.psi.stubs.PsiFileStub;
+import com.intellij.util.cls.ClsFormatException;
+import com.intellij.util.indexing.FileContent;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+public class ClsDecompilerImpl extends ClassFileDecompilers.Full {
+  private static final Logger LOG = Logger.getInstance(ClsDecompilerImpl.class);
+  private final ClsStubBuilder myStubBuilder = new MyClsStubBuilder();
+
+  @Override
+  public boolean accepts(@NotNull VirtualFile file) {
+    return true;
+  }
+
+  @Override
+  public @NotNull ClsStubBuilder getStubBuilder() {
+    return myStubBuilder;
+  }
+
+  @Override
+  public @NotNull FileViewProvider createFileViewProvider(@NotNull VirtualFile file, @NotNull PsiManager manager, boolean physical) {
+    return new ClassFileViewProvider(manager, file, physical);
+  }
+
+  private static class MyClsStubBuilder extends ClsStubBuilder {
+    @Override
+    public int getStubVersion() {
+      return JavaFileElementType.STUB_VERSION;
+    }
+
+    @Override
+    public @Nullable PsiFileStub<?> buildFileStub(@NotNull FileContent fileContent) throws ClsFormatException {
+      PsiFileStub<?> stub = ClsFileImpl.buildFileStub(fileContent.getFile(), fileContent.getContent());
+      if (stub == null && fileContent.getFileName().indexOf('$') < 0) {
+        LOG.info("No stub built for the file " + fileContent);
+      }
+      return stub;
+    }
+  }
+}
index 4eb528776397880b407373dcbd5bd2f370f226ef..ff8bcd30fe68b598ef44ddd79ad80328dddb822b 100644 (file)
@@ -382,8 +382,8 @@ public class ClsFileImpl extends PsiBinaryFileImpl
   }
 
   private static Exception wrapException(InvalidMirrorException e, VirtualFile file) {
-    ClassFileDecompilers.Decompiler decompiler = ClassFileDecompilers.getInstance().find(file);
-    if (decompiler instanceof ClassFileDecompilers.Light) {
+    ClassFileDecompilers.Decompiler decompiler = ClassFileDecompilers.getInstance().find(file, ClassFileDecompilers.Light.class);
+    if (decompiler != null) {
       PluginId pluginId = PluginManagerCore.getPluginByClassName(decompiler.getClass().getName());
       if (pluginId != null) {
         return new PluginException(e, pluginId);
index 1747de72ba083791ccc4e6783e131e9f6f147a0d..34e67efe0a35bf5979b852f3e5d8506608ce3c7d 100644 (file)
@@ -12,7 +12,7 @@
   <resource-bundle>messages.Decompiler</resource-bundle>
 
   <extensions defaultExtensionNs="com.intellij">
-    <psi.classFileDecompiler implementation="org.jetbrains.java.decompiler.IdeaDecompiler" order="last"/>
+    <psi.classFileDecompiler implementation="org.jetbrains.java.decompiler.IdeaDecompiler" order="last, before clsStubBuilder"/>
   </extensions>
 
   <applicationListeners>
index 140ba4e7d09538b7168debe007600566c65a3629..25855b654345f3464b8228bc20e995be0f4802ae 100644 (file)
@@ -79,7 +79,7 @@ class IdeaDecompiler : ClassFileDecompilers.Light() {
 
     override fun beforeFileOpened(source: FileEditorManager, file: VirtualFile) {
       if (myShowNotice && file.fileType === JavaClassFileType.INSTANCE) {
-        val decompiler = ClassFileDecompilers.getInstance().find(file)
+        val decompiler = ClassFileDecompilers.getInstance().find(file, ClassFileDecompilers.Light::class.java)
         if (decompiler is IdeaDecompiler) {
           TASK_KEY.set(file, ApplicationManager.getApplication().executeOnPooledThread(Callable { decompiler.decompile(file) }))