Merge branch 'master' into nodeDescriptor_names_ext
[idea/community.git] / java / debugger / impl / src / com / intellij / debugger / ui / impl / watch / FieldDescriptorImpl.java
1 /*
2  * Copyright 2000-2015 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.debugger.ui.impl.watch;
17
18 import com.intellij.debugger.DebuggerBundle;
19 import com.intellij.debugger.DebuggerContext;
20 import com.intellij.debugger.engine.DebuggerManagerThreadImpl;
21 import com.intellij.debugger.engine.DebuggerUtils;
22 import com.intellij.debugger.engine.evaluation.EvaluateException;
23 import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
24 import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
25 import com.intellij.debugger.impl.PositionUtil;
26 import com.intellij.debugger.settings.NodeRendererSettings;
27 import com.intellij.debugger.ui.tree.FieldDescriptor;
28 import com.intellij.debugger.ui.tree.NodeDescriptor;
29 import com.intellij.debugger.ui.tree.NodeDescriptorNameAdjuster;
30 import com.intellij.openapi.project.Project;
31 import com.intellij.openapi.util.text.StringUtil;
32 import com.intellij.psi.JavaPsiFacade;
33 import com.intellij.psi.PsiElementFactory;
34 import com.intellij.psi.PsiExpression;
35 import com.intellij.util.IncorrectOperationException;
36 import com.sun.jdi.Field;
37 import com.sun.jdi.ObjectCollectedException;
38 import com.sun.jdi.ObjectReference;
39 import com.sun.jdi.Value;
40 import org.jetbrains.annotations.NotNull;
41 import org.jetbrains.annotations.Nullable;
42
43 public class FieldDescriptorImpl extends ValueDescriptorImpl implements FieldDescriptor{
44   public static final String OUTER_LOCAL_VAR_FIELD_PREFIX = "val$";
45   private final Field myField;
46   private final ObjectReference myObject;
47   private Boolean myIsPrimitive = null;
48   private final boolean myIsStatic;
49
50   public FieldDescriptorImpl(Project project, ObjectReference objRef, @NotNull Field field) {
51     super(project);
52     myObject = objRef;
53     myField = field;
54     myIsStatic = field.isStatic();
55     setLvalue(!field.isFinal());
56   }
57
58   @Override
59   public Field getField() {
60     return myField;
61   }
62
63   @Override
64   public ObjectReference getObject() {
65     return myObject;
66   }
67
68   @Override
69   public void setAncestor(NodeDescriptor oldDescriptor) {
70     super.setAncestor(oldDescriptor);
71     final Boolean isPrimitive = ((FieldDescriptorImpl)oldDescriptor).myIsPrimitive;
72     if (isPrimitive != null) { // was cached
73       // do not loose cached info
74       myIsPrimitive = isPrimitive;
75     }
76   }
77
78
79   @Override
80   public boolean isPrimitive() {
81     if (myIsPrimitive == null) {
82       final Value value = getValue();
83       if (value != null) {
84         myIsPrimitive = super.isPrimitive();
85       }
86       else {
87         myIsPrimitive = DebuggerUtils.isPrimitiveType(myField.typeName());
88       }
89     }
90     return myIsPrimitive.booleanValue();
91   }
92
93   @Override
94   public Value calcValue(EvaluationContextImpl evaluationContext) throws EvaluateException {
95     DebuggerManagerThreadImpl.assertIsManagerThread();
96     try {
97       return (myObject != null) ? myObject.getValue(myField) : myField.declaringType().getValue(myField);
98     }
99     catch (ObjectCollectedException ignored) {
100       throw EvaluateExceptionUtil.OBJECT_WAS_COLLECTED;
101     }
102   }
103
104   public boolean isStatic() {
105     return myIsStatic;
106   }
107
108   @Override
109   public String getName() {
110     final String fieldName = myField.name();
111     NodeDescriptorNameAdjuster nameAdjuster = NodeDescriptorNameAdjuster.findFor(this);
112     if (nameAdjuster != null) {
113       return nameAdjuster.fixName(fieldName, this);
114     }
115     return fieldName;
116   }
117
118   public boolean isOuterLocalVariableValue() {
119     try {
120       return DebuggerUtils.isSynthetic(myField) && myField.name().startsWith(OUTER_LOCAL_VAR_FIELD_PREFIX);
121     }
122     catch (UnsupportedOperationException ignored) {
123       return false;
124     }
125   }
126
127   @Nullable
128   @Override
129   public String getDeclaredType() {
130     return myField.typeName();
131   }
132
133   @Override
134   public PsiExpression getDescriptorEvaluation(DebuggerContext context) throws EvaluateException {
135     PsiElementFactory elementFactory = JavaPsiFacade.getInstance(context.getProject()).getElementFactory();
136     String fieldName;
137     if(isStatic()) {
138       String typeName = myField.declaringType().name().replace('$', '.');
139       typeName = DebuggerTreeNodeExpression.normalize(typeName, PositionUtil.getContextElement(context), context.getProject());
140       fieldName = typeName + "." + getName();
141     }
142     else {
143       //noinspection HardCodedStringLiteral
144       fieldName = isOuterLocalVariableValue()? StringUtil.trimStart(getName(), OUTER_LOCAL_VAR_FIELD_PREFIX) : "this." + getName();
145     }
146     try {
147       return elementFactory.createExpressionFromText(fieldName, null);
148     }
149     catch (IncorrectOperationException e) {
150       throw new EvaluateException(DebuggerBundle.message("error.invalid.field.name", getName()), e);
151     }
152   }
153 }