diff --git a/java/debugger/impl/src/com/intellij/debugger/DebugEnvironment.java b/java/debugger/impl/src/com/intellij/debugger/DebugEnvironment.java index 85f452fcec1a..d6cd83315438 100644 --- a/java/debugger/impl/src/com/intellij/debugger/DebugEnvironment.java +++ b/java/debugger/impl/src/com/intellij/debugger/DebugEnvironment.java @@ -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(); diff --git a/java/debugger/impl/src/com/intellij/debugger/DefaultDebugEnvironment.java b/java/debugger/impl/src/com/intellij/debugger/DefaultDebugEnvironment.java index 5cfee964e7d6..e4d6499f6e42 100644 --- a/java/debugger/impl/src/com/intellij/debugger/DefaultDebugEnvironment.java +++ b/java/debugger/impl/src/com/intellij/debugger/DefaultDebugEnvironment.java @@ -15,14 +15,17 @@ */ 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()); + } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java index 6c1e55e3db4b..25188dd36f7d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/PositionManagerImpl.java @@ -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 getAllClasses(@NotNull final SourcePosition position) throws NoDataException { return ApplicationManager.getApplication().runReadAction(new Computable>() { 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 index 000000000000..8428225ac9fc --- /dev/null +++ b/java/debugger/impl/src/com/intellij/debugger/impl/AlternativeJreIndexHelper.java @@ -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 getAdditionalRootsToIndex() { + return Collections.emptySet(); + } + + @NotNull + @Override + public Set getAdditionalProjectRootsToIndex(@NotNull Project project) { + SmartHashSet 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 getClassRoots(@NotNull Sdk jre) { + return Arrays.asList(jre.getRootProvider().getFiles(OrderRootType.CLASSES)); + } + + @NotNull + public static Collection 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)); + } +} diff --git a/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerRunner.java b/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerRunner.java index e30b4a18a563..3570bdeb3ce3 100644 --- a/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerRunner.java +++ b/java/debugger/impl/src/com/intellij/debugger/impl/GenericDebuggerRunner.java @@ -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 - 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 index 000000000000..6c857cd9a184 --- /dev/null +++ b/java/execution/openapi/src/com/intellij/execution/configurations/ConfigurationWithAlternativeJre.java @@ -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(); +} diff --git a/resources/src/META-INF/IdeaPlugin.xml b/resources/src/META-INF/IdeaPlugin.xml index b44a794c4cef..9e7af4061bb6 100644 --- a/resources/src/META-INF/IdeaPlugin.xml +++ b/resources/src/META-INF/IdeaPlugin.xml @@ -1627,6 +1627,7 @@ +