blob: 7b402a1b17f9f8fabb2731f2775c5eef361a1ca6 [file] [log] [blame]
/*
* Copyright 2000-2009 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.actions;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.engine.DebugProcessImpl;
import com.intellij.debugger.engine.JVMNameUtil;
import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.ui.impl.watch.DebuggerTreeNodeImpl;
import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
import com.intellij.debugger.ui.tree.ValueDescriptor;
import com.intellij.openapi.actionSystem.AnActionEvent;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Computable;
import com.intellij.psi.PsiClass;
import com.sun.jdi.*;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class JumpToObjectAction extends DebuggerAction{
private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.actions.JumpToObjectAction");
@Override
public void actionPerformed(AnActionEvent e) {
DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
if(selectedNode == null) {
return;
}
final NodeDescriptorImpl descriptor = selectedNode.getDescriptor();
if(!(descriptor instanceof ValueDescriptor)) {
return;
}
DebuggerContextImpl debuggerContext = getDebuggerContext(e.getDataContext());
final DebugProcessImpl debugProcess = debuggerContext.getDebugProcess();
if(debugProcess == null) {
return;
}
debugProcess.getManagerThread().schedule(new NavigateCommand(debuggerContext, (ValueDescriptor)descriptor, debugProcess, e));
}
@Override
public void update(final AnActionEvent e) {
if(!isFirstStart(e)) {
return;
}
final DebuggerContextImpl debuggerContext = getDebuggerContext(e.getDataContext());
final DebugProcessImpl debugProcess = debuggerContext.getDebugProcess();
if(debugProcess == null) {
e.getPresentation().setVisible(false);
return;
}
DebuggerTreeNodeImpl selectedNode = getSelectedNode(e.getDataContext());
if(selectedNode == null) {
e.getPresentation().setVisible(false);
return;
}
final NodeDescriptorImpl descriptor = selectedNode.getDescriptor();
if (descriptor instanceof ValueDescriptor) {
debugProcess.getManagerThread().schedule(new EnableCommand(debuggerContext, (ValueDescriptor)descriptor, debugProcess, e));
}
else {
e.getPresentation().setVisible(false);
}
}
private static SourcePosition calcPosition(final ValueDescriptor descriptor, final DebugProcessImpl debugProcess) throws ClassNotLoadedException {
final Value value = descriptor.getValue();
if(value == null) {
return null;
}
Type type = value.type();
if(type == null) {
return null;
}
try {
if(type instanceof ArrayType) {
type = ((ArrayType)type).componentType();
}
if(type instanceof ClassType) {
final ClassType clsType = (ClassType)type;
final List<Location> locations = clsType.allLineLocations();
if(locations.size() > 0) {
final Location location = locations.get(0);
return ApplicationManager.getApplication().runReadAction(new Computable<SourcePosition>() {
@Override
public SourcePosition compute() {
SourcePosition position = debugProcess.getPositionManager().getSourcePosition(location);
// adjust position for non-anonymous classes
if (clsType.name().indexOf('$') < 0) {
final PsiClass classAt = JVMNameUtil.getClassAt(position);
if (classAt != null) {
final SourcePosition classPosition = SourcePosition.createFromElement(classAt);
if (classPosition != null) {
position = classPosition;
}
}
}
return position;
}
});
}
}
}
catch (ClassNotPreparedException e) {
LOG.debug(e);
}
catch (AbsentInformationException e) {
LOG.debug(e);
}
return null;
}
public static class NavigateCommand extends SourcePositionCommand {
public NavigateCommand(final DebuggerContextImpl debuggerContext, final ValueDescriptor descriptor, final DebugProcessImpl debugProcess, final AnActionEvent e) {
super(debuggerContext, descriptor, debugProcess, e);
}
@Override
protected NavigateCommand createRetryCommand() {
return new NavigateCommand(myDebuggerContext, myDescriptor, myDebugProcess, myActionEvent);
}
@Override
protected void doAction(final SourcePosition sourcePosition) {
if (sourcePosition != null) {
sourcePosition.navigate(true);
}
}
}
private static class EnableCommand extends SourcePositionCommand {
public EnableCommand(final DebuggerContextImpl debuggerContext, final ValueDescriptor descriptor, final DebugProcessImpl debugProcess, final AnActionEvent e) {
super(debuggerContext, descriptor, debugProcess, e);
}
@Override
protected EnableCommand createRetryCommand() {
return new EnableCommand(myDebuggerContext, myDescriptor, myDebugProcess, myActionEvent);
}
@Override
protected void doAction(final SourcePosition sourcePosition) {
enableAction(myActionEvent, sourcePosition != null);
}
}
public abstract static class SourcePositionCommand extends SuspendContextCommandImpl {
protected final DebuggerContextImpl myDebuggerContext;
protected final ValueDescriptor myDescriptor;
protected final DebugProcessImpl myDebugProcess;
protected final AnActionEvent myActionEvent;
public SourcePositionCommand(final DebuggerContextImpl debuggerContext,
final ValueDescriptor descriptor,
final DebugProcessImpl debugProcess,
final AnActionEvent actionEvent) {
super(debuggerContext.getSuspendContext());
myDebuggerContext = debuggerContext;
myDescriptor = descriptor;
myDebugProcess = debugProcess;
myActionEvent = actionEvent;
}
@Override
public final void contextAction() throws Exception {
try {
doAction(calcPosition(myDescriptor, myDebugProcess));
}
catch (ClassNotLoadedException ex) {
final String className = ex.className();
if (loadClass(className) != null) {
myDebugProcess.getManagerThread().schedule(createRetryCommand());
}
}
}
protected abstract SourcePositionCommand createRetryCommand();
protected abstract void doAction(@Nullable SourcePosition sourcePosition);
private ReferenceType loadClass(final String className) {
final EvaluationContextImpl eContext = myDebuggerContext.createEvaluationContext();
try {
return myDebugProcess.loadClass(eContext, className, eContext.getClassLoader());
}
catch(Throwable ignored) {
}
return null;
}
}
}