blob: 41e436ba6c8ed6ac00de89214007e7a9b2784643 [file] [log] [blame]
/*
* Copyright 2000-2014 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.engine;
import com.intellij.debugger.SourcePosition;
import com.intellij.debugger.impl.DebuggerContextImpl;
import com.intellij.debugger.impl.DebuggerContextUtil;
import com.intellij.debugger.impl.DebuggerSession;
import com.intellij.debugger.impl.PositionUtil;
import com.intellij.debugger.jdi.StackFrameProxyImpl;
import com.intellij.debugger.ui.impl.watch.FieldDescriptorImpl;
import com.intellij.debugger.ui.tree.FieldDescriptor;
import com.intellij.debugger.ui.tree.LocalVariableDescriptor;
import com.intellij.debugger.ui.tree.NodeDescriptor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.sun.jdi.*;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.List;
public class DefaultSourcePositionProvider extends SourcePositionProvider {
@Nullable
@Override
protected SourcePosition computeSourcePosition(@NotNull NodeDescriptor descriptor,
@NotNull Project project,
@NotNull DebuggerContextImpl context,
boolean nearest) {
StackFrameProxyImpl frame = context.getFrameProxy();
if (frame == null) {
return null;
}
if (descriptor instanceof FieldDescriptor) {
return getSourcePositionForField((FieldDescriptor)descriptor, project, context, nearest);
}
else if (descriptor instanceof LocalVariableDescriptor) {
return getSourcePositionForLocalVariable((LocalVariableDescriptor)descriptor, project, context, nearest);
}
return null;
}
@Nullable
protected SourcePosition getSourcePositionForField(@NotNull FieldDescriptor descriptor,
@NotNull Project project,
@NotNull DebuggerContextImpl context,
boolean nearest) {
final ReferenceType type = descriptor.getField().declaringType();
final JavaPsiFacade facade = JavaPsiFacade.getInstance(project);
final String fieldName = descriptor.getField().name();
if (fieldName.startsWith(FieldDescriptorImpl.OUTER_LOCAL_VAR_FIELD_PREFIX)) {
// this field actually mirrors a local variable in the outer class
String varName = fieldName.substring(fieldName.lastIndexOf('$') + 1);
PsiElement element = PositionUtil.getContextElement(context);
if (element == null) {
return null;
}
PsiClass aClass = PsiTreeUtil.getParentOfType(element, PsiClass.class, false);
if (aClass == null) {
return null;
}
PsiElement navigationElement = aClass.getNavigationElement();
if (!(navigationElement instanceof PsiClass)) {
return null;
}
aClass = (PsiClass)navigationElement;
PsiVariable psiVariable = facade.getResolveHelper().resolveReferencedVariable(varName, aClass);
if (psiVariable == null) {
return null;
}
if (nearest) {
return DebuggerContextUtil.findNearest(context, psiVariable, aClass.getContainingFile());
}
return SourcePosition.createFromOffset(psiVariable.getContainingFile(), psiVariable.getTextOffset());
}
else {
final DebuggerSession session = context.getDebuggerSession();
final GlobalSearchScope scope = session != null? session.getSearchScope() : GlobalSearchScope.allScope(project);
PsiClass aClass = facade.findClass(type.name().replace('$', '.'), scope);
if (aClass == null) {
// trying to search, assuming declaring class is an anonymous class
final DebugProcessImpl debugProcess = context.getDebugProcess();
if (debugProcess != null) {
try {
final List<Location> locations = type.allLineLocations();
if (!locations.isEmpty()) {
// important: use the last location to be sure the position will be within the anonymous class
final Location lastLocation = locations.get(locations.size() - 1);
final SourcePosition position = debugProcess.getPositionManager().getSourcePosition(lastLocation);
aClass = JVMNameUtil.getClassAt(position);
}
}
catch (AbsentInformationException ignored) {
}
catch (ClassNotPreparedException ignored) {
}
}
}
if (aClass != null) {
PsiField field = aClass.findFieldByName(fieldName, false);
if (field != null) {
PsiElement element = field.getNavigationElement();
if (nearest) {
return DebuggerContextUtil.findNearest(context, element, aClass.getContainingFile());
}
return SourcePosition.createFromOffset(element.getContainingFile(), element.getTextOffset());
}
}
return null;
}
}
@Nullable
protected SourcePosition getSourcePositionForLocalVariable(@NotNull LocalVariableDescriptor descriptor,
@NotNull Project project,
@NotNull DebuggerContextImpl context,
boolean nearest) {
PsiElement place = PositionUtil.getContextElement(context);
if (place == null) {
return null;
}
PsiVariable psiVariable = JavaPsiFacade.getInstance(project).getResolveHelper().resolveReferencedVariable(descriptor.getName(), place);
if (psiVariable == null) {
return null;
}
PsiFile containingFile = psiVariable.getContainingFile();
if(containingFile == null) return null;
if (nearest) {
return DebuggerContextUtil.findNearest(context, psiVariable, containingFile);
}
return SourcePosition.createFromOffset(containingFile, psiVariable.getTextOffset());
}
}