IDEA-29246 Debug with alternative JRE - JDK source is incorrect
authorEgor.Ushakov <egor.ushakov@jetbrains.com>
Wed, 24 Aug 2016 09:10:15 +0000 (12:10 +0300)
committerEgor.Ushakov <egor.ushakov@jetbrains.com>
Wed, 24 Aug 2016 09:23:31 +0000 (12:23 +0300)
java/debugger/impl/src/com/intellij/debugger/DebugEnvironment.java
java/debugger/impl/src/com/intellij/debugger/DefaultDebugEnvironment.java
java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java
java/debugger/impl/src/com/intellij/debugger/impl/AlternativeJreIndexHelper.java [new file with mode: 0644]
java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerRunner.java
java/execution/impl/src/com/intellij/execution/application/ApplicationConfiguration.java
java/execution/openapi/src/com/intellij/execution/configurations/ConfigurationWithAlternativeJre.java [new file with mode: 0644]
resources/src/META-INF/IdeaPlugin.xml

index 85f452fcec1a603b4734eadf6c35dd950a4761f1..d6cd833154385acabc7608a103a3f525294afc36 100644 (file)
@@ -18,6 +18,7 @@ package com.intellij.debugger;
 import com.intellij.execution.ExecutionException;
 import com.intellij.execution.ExecutionResult;
 import com.intellij.execution.configurations.RemoteConnection;
+import com.intellij.openapi.projectRoots.Sdk;
 import com.intellij.psi.search.GlobalSearchScope;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
@@ -36,6 +37,11 @@ public interface DebugEnvironment {
   @NotNull
   GlobalSearchScope getSearchScope();
 
+  @Nullable
+  default Sdk getAlternativeJre() {
+    return null;
+  }
+
   boolean isRemote();
 
   RemoteConnection getRemoteConnection();
index 5cfee964e7d6f936753daa5bbdbbe896899ea4b7..e4d6499f6e42d4d28a0abe434cc0526e96a6b2bb 100644 (file)
  */
 package com.intellij.debugger;
 
+import com.intellij.debugger.impl.AlternativeJreIndexHelper;
 import com.intellij.debugger.impl.DebuggerManagerImpl;
 import com.intellij.debugger.settings.DebuggerSettings;
 import com.intellij.execution.ExecutionException;
 import com.intellij.execution.ExecutionResult;
 import com.intellij.execution.configurations.*;
 import com.intellij.execution.runners.ExecutionEnvironment;
+import com.intellij.openapi.projectRoots.Sdk;
 import com.intellij.psi.search.GlobalSearchScope;
 import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
 
 public class DefaultDebugEnvironment implements DebugEnvironment {
   private final GlobalSearchScope mySearchScope;
@@ -87,4 +90,10 @@ public class DefaultDebugEnvironment implements DebugEnvironment {
   public String getSessionName() {
     return environment.getRunProfile().getName();
   }
+
+  @Nullable
+  @Override
+  public Sdk getAlternativeJre() {
+    return AlternativeJreIndexHelper.getAlternativeJre(environment.getRunProfile());
+  }
 }
index 6c1e55e3db4b5b23286a37daf8805830f5f322f8..25188dd36f7d94a477d8cc8ce7e54de2656ff00a 100644 (file)
@@ -20,13 +20,16 @@ import com.intellij.debugger.NoDataException;
 import com.intellij.debugger.PositionManager;
 import com.intellij.debugger.SourcePosition;
 import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.impl.AlternativeJreIndexHelper;
 import com.intellij.debugger.impl.DebuggerUtilsEx;
 import com.intellij.debugger.jdi.VirtualMachineProxyImpl;
 import com.intellij.debugger.requests.ClassPrepareRequestor;
 import com.intellij.openapi.application.ApplicationManager;
 import com.intellij.openapi.diagnostic.Logger;
 import com.intellij.openapi.editor.Document;
+import com.intellij.openapi.project.IndexNotReadyException;
 import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.Sdk;
 import com.intellij.openapi.util.Computable;
 import com.intellij.openapi.util.NullableComputable;
 import com.intellij.openapi.util.Ref;
@@ -35,8 +38,11 @@ import com.intellij.openapi.util.text.StringUtil;
 import com.intellij.openapi.vfs.VirtualFile;
 import com.intellij.openapi.vfs.VirtualFileManager;
 import com.intellij.psi.*;
+import com.intellij.psi.impl.compiled.ClsClassImpl;
+import com.intellij.psi.impl.java.stubs.index.JavaStubIndexKeys;
 import com.intellij.psi.search.FilenameIndex;
 import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.stubs.StubIndex;
 import com.intellij.psi.util.PsiTreeUtil;
 import com.intellij.util.DocumentUtil;
 import com.intellij.util.containers.ContainerUtil;
@@ -351,13 +357,39 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio
     //}
 
     final String originalQName = refType.name();
-    final GlobalSearchScope searchScope = myDebugProcess.getSearchScope();
-    PsiClass psiClass = DebuggerUtils.findClass(originalQName, project, searchScope); // try to lookup original name first
+
+    PsiClass psiClass = null;
+
+    // first check alternative jre if any
+    Sdk alternativeJre = myDebugProcess.getSession().getAlternativeJre();
+    if (alternativeJre != null) {
+      try {
+        psiClass = ContainerUtil.getFirstItem(StubIndex.getElements(JavaStubIndexKeys.CLASS_FQN,
+                                                                    originalQName.hashCode(),
+                                                                    project,
+                                                                    AlternativeJreIndexHelper.getSearchScope(alternativeJre),
+                                                                    PsiClass.class));
+
+        if (psiClass instanceof ClsClassImpl) { //try to find sources
+          PsiFile psiSource = findSourceFile((ClsClassImpl)psiClass, alternativeJre);
+          if (psiSource != null) {
+            return psiSource;
+          }
+        }
+      }
+      catch (IndexNotReadyException ignored) {
+      }
+    }
+
     if (psiClass == null) {
-      int dollar = originalQName.indexOf('$');
-      if (dollar > 0) {
-        final String qName = originalQName.substring(0, dollar);
-        psiClass = DebuggerUtils.findClass(qName, project, searchScope);
+      GlobalSearchScope searchScope = myDebugProcess.getSearchScope();
+      psiClass = DebuggerUtils.findClass(originalQName, project, searchScope); // try to lookup original name first
+      if (psiClass == null) {
+        int dollar = originalQName.indexOf('$');
+        if (dollar > 0) {
+          final String qName = originalQName.substring(0, dollar);
+          psiClass = DebuggerUtils.findClass(qName, project, searchScope);
+        }
       }
     }
 
@@ -393,6 +425,24 @@ public class PositionManagerImpl implements PositionManager, MultiRequestPositio
     return null;
   }
 
+  @Nullable
+  private static PsiFile findSourceFile(ClsClassImpl psiClass, Sdk alternativeJre) {
+    String sourceFileName = psiClass.getSourceFileName();
+    String packageName = ((PsiClassOwner)psiClass.getContainingFile()).getPackageName();
+    String relativePath = packageName.isEmpty() ? sourceFileName : packageName.replace('.', '/') + '/' + sourceFileName;
+
+    for (VirtualFile file : AlternativeJreIndexHelper.getSourceRoots(alternativeJre)) {
+      VirtualFile source = file.findFileByRelativePath(relativePath);
+      if (source != null && source.isValid()) {
+        PsiFile psiSource = psiClass.getManager().findFile(source);
+        if (psiSource instanceof PsiClassOwner) {
+          return psiSource;
+        }
+      }
+    }
+    return null;
+  }
+
   @NotNull
   public List<ReferenceType> getAllClasses(@NotNull final SourcePosition position) throws NoDataException {
     return ApplicationManager.getApplication().runReadAction(new Computable<List<ReferenceType>>() {
diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/AlternativeJreIndexHelper.java b/java/debugger/impl/src/com/intellij/debugger/impl/AlternativeJreIndexHelper.java
new file mode 100644 (file)
index 0000000..8428225
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.debugger.impl;
+
+import com.intellij.execution.RunManager;
+import com.intellij.execution.configurations.ConfigurationWithAlternativeJre;
+import com.intellij.execution.configurations.RunConfiguration;
+import com.intellij.execution.configurations.RunProfile;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.projectRoots.ProjectJdkTable;
+import com.intellij.openapi.projectRoots.Sdk;
+import com.intellij.openapi.roots.OrderRootType;
+import com.intellij.openapi.vfs.VirtualFile;
+import com.intellij.psi.search.GlobalSearchScope;
+import com.intellij.psi.search.NonClasspathDirectoriesScope;
+import com.intellij.util.containers.SmartHashSet;
+import com.intellij.util.indexing.IndexableSetContributor;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+
+/**
+ * @author egor
+ */
+public class AlternativeJreIndexHelper extends IndexableSetContributor {
+  @NotNull
+  @Override
+  public Set<VirtualFile> getAdditionalRootsToIndex() {
+    return Collections.emptySet();
+  }
+
+  @NotNull
+  @Override
+  public Set<VirtualFile> getAdditionalProjectRootsToIndex(@NotNull Project project) {
+    SmartHashSet<VirtualFile> res = new SmartHashSet<>();
+    for (RunConfiguration configuration : RunManager.getInstance(project).getAllConfigurationsList()) {
+      Sdk jre = getAlternativeJre(configuration);
+      if (jre != null) {
+        res.addAll(getClassRoots(jre));
+      }
+    }
+    return res;
+  }
+
+  @Nullable
+  public static Sdk getAlternativeJre(RunProfile profile) {
+    if (profile instanceof ConfigurationWithAlternativeJre) {
+      ConfigurationWithAlternativeJre appConfig = (ConfigurationWithAlternativeJre)profile;
+      if (appConfig.isAlternativeJrePathEnabled()) {
+        return ProjectJdkTable.getInstance().findJdk(appConfig.getAlternativeJrePath());
+      }
+    }
+    return null;
+  }
+
+  @Nullable
+  private static Collection<VirtualFile> getClassRoots(@NotNull Sdk jre) {
+    return Arrays.asList(jre.getRootProvider().getFiles(OrderRootType.CLASSES));
+  }
+
+  @NotNull
+  public static Collection<VirtualFile> getSourceRoots(@NotNull Sdk jre) {
+    return Arrays.asList(jre.getRootProvider().getFiles(OrderRootType.SOURCES));
+  }
+
+  @Nullable
+  public static GlobalSearchScope getSearchScope(@NotNull Sdk jre) {
+    return new NonClasspathDirectoriesScope(getClassRoots(jre));
+  }
+}
index e30b4a18a5634a1902bda2e77312a83ed7fb5d31..3570bdeb3ce3c09c3c466e2ffd0609af78917dff 100644 (file)
@@ -33,7 +33,9 @@ import com.intellij.execution.runners.JavaPatchableProgramRunner;
 import com.intellij.execution.ui.RunContentDescriptor;
 import com.intellij.openapi.fileEditor.FileDocumentManager;
 import com.intellij.openapi.options.SettingsEditor;
+import com.intellij.openapi.project.DumbService;
 import com.intellij.openapi.util.text.StringUtil;
+import com.intellij.util.indexing.UnindexedFilesUpdater;
 import com.intellij.xdebugger.XDebugProcess;
 import com.intellij.xdebugger.XDebugProcessStarter;
 import com.intellij.xdebugger.XDebugSession;
@@ -117,6 +119,11 @@ public class GenericDebuggerRunner extends JavaPatchableProgramRunner<GenericDeb
 
     final DebugProcessImpl debugProcess = debuggerSession.getProcess();
 
+    // index alternative jdk if needed
+    if (AlternativeJreIndexHelper.getAlternativeJre(env.getRunProfile()) != null) {
+      DumbService.getInstance(debuggerSession.getProject()).queueTask(new UnindexedFilesUpdater(debuggerSession.getProject(), false));
+    }
+
     return XDebuggerManager.getInstance(env.getProject()).startSession(env, new XDebugProcessStarter() {
       @Override
       @NotNull
index fa4de4318d94088d5bfd51b784ed3d11df2ad95e..9df298fabeb0dad81610efccf4e968f9b9ddcc71 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2000-2015 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.
@@ -45,7 +45,7 @@ import java.util.LinkedHashMap;
 import java.util.Map;
 
 public class ApplicationConfiguration extends ModuleBasedConfiguration<JavaRunConfigurationModule>
-  implements CommonJavaRunConfigurationParameters, SingleClassConfiguration, RefactoringListenerProvider {
+  implements CommonJavaRunConfigurationParameters, SingleClassConfiguration, RefactoringListenerProvider, ConfigurationWithAlternativeJre {
 
   public String MAIN_CLASS_NAME;
   public String VM_PARAMETERS;
diff --git a/java/execution/openapi/src/com/intellij/execution/configurations/ConfigurationWithAlternativeJre.java b/java/execution/openapi/src/com/intellij/execution/configurations/ConfigurationWithAlternativeJre.java
new file mode 100644 (file)
index 0000000..6c857cd
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.execution.configurations;
+
+import org.jetbrains.annotations.Nullable;
+
+/**
+ * @author egor
+ */
+public interface ConfigurationWithAlternativeJre {
+  boolean isAlternativeJrePathEnabled();
+
+  @Nullable
+  String getAlternativeJrePath();
+}
index b44a794c4cefeb6ee83421006290e91a65e98f89..9e7af4061bb6522454921e41a39760a3af319c70 100644 (file)
     <debugger.syntheticProvider implementation="com.intellij.debugger.engine.DefaultSyntheticProvider"/>
     <debugger.sourcePositionProvider implementation="com.intellij.debugger.engine.DefaultSourcePositionProvider" order="last"/>
     <debugger.sourcePositionHighlighter implementation="com.intellij.debugger.engine.JavaSourcePositionHighlighter"/>
+    <indexedRootsProvider implementation="com.intellij.debugger.impl.AlternativeJreIndexHelper"/>
 
     <debugger.nodeRenderer implementation="com.intellij.debugger.ui.tree.render.ColorObjectRenderer"/>
     <debugger.nodeRenderer implementation="com.intellij.debugger.ui.tree.render.ImageObjectRenderer"/>