caf0e41c07c38024cf1654ef229a7a58bcd852de
[idea/community.git] / java / debugger / impl / src / com / intellij / debugger / engine / evaluation / expression / LocalVariableEvaluator.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
17 /*
18  * Class LocalVariableEvaluator
19  * @author Jeka
20  */
21 package com.intellij.debugger.engine.evaluation.expression;
22
23 import com.intellij.debugger.DebuggerBundle;
24 import com.intellij.debugger.engine.evaluation.EvaluateException;
25 import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil;
26 import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
27 import com.intellij.debugger.jdi.LocalVariableProxyImpl;
28 import com.intellij.debugger.jdi.StackFrameProxyImpl;
29 import com.intellij.debugger.jdi.ThreadReferenceProxyImpl;
30 import com.intellij.debugger.ui.impl.watch.LocalVariableDescriptorImpl;
31 import com.intellij.debugger.ui.impl.watch.NodeDescriptorImpl;
32 import com.intellij.openapi.diagnostic.Logger;
33 import com.intellij.openapi.project.Project;
34 import com.sun.jdi.*;
35
36 import java.util.List;
37
38 class LocalVariableEvaluator implements Evaluator {
39   private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.evaluation.expression.LocalVariableEvaluator");
40
41   private final String myLocalVariableName;
42   private EvaluationContextImpl myContext;
43   private LocalVariableProxyImpl myEvaluatedVariable;
44   private final boolean myIsJspSpecial;
45   private int myParameterIndex = -1;
46
47   public LocalVariableEvaluator(String localVariableName, boolean isJspSpecial) {
48     myLocalVariableName = localVariableName;
49     myIsJspSpecial = isJspSpecial;
50   }
51
52   public void setParameterIndex(int parameterIndex) {
53     myParameterIndex = parameterIndex;
54   }
55
56   @Override
57   public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
58     StackFrameProxyImpl frameProxy = context.getFrameProxy();
59     if (frameProxy == null) {
60       throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.no.stackframe"));
61     }
62
63     try {
64       ThreadReferenceProxyImpl threadProxy = null;
65       int lastFrameIndex = -1;
66
67       while (true) {
68         try {
69           LocalVariableProxyImpl local = frameProxy.visibleVariableByName(myLocalVariableName);
70           if (local != null) {
71             myEvaluatedVariable = local;
72             myContext = context;
73             return frameProxy.getValue(local);
74           }
75         }
76         catch (EvaluateException e) {
77           if (!(e.getCause() instanceof AbsentInformationException)) {
78             throw e;
79           }
80           if (myParameterIndex < 0) {
81             throw e;
82           }
83           final List<Value> values = frameProxy.getArgumentValues();
84           if (values.isEmpty() || myParameterIndex >= values.size()) {
85             throw e;
86           }
87           return values.get(myParameterIndex);
88         }
89
90         if (myIsJspSpecial) {
91           if (threadProxy == null /* initialize it lazily */) {
92             threadProxy = frameProxy.threadProxy();
93             lastFrameIndex = threadProxy.frameCount() - 1;
94           }
95           final int currentFrameIndex = frameProxy.getFrameIndex();
96           if (currentFrameIndex < lastFrameIndex) {
97             frameProxy = threadProxy.frame(currentFrameIndex + 1);
98             continue;
99           }
100         }
101
102         break;
103       }
104       throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.local.variable.missing", myLocalVariableName));
105     }
106     catch (EvaluateException e) {
107       myEvaluatedVariable = null;
108       myContext = null;
109       throw e;
110     }
111   }
112
113   @Override
114   public Modifier getModifier() {
115     Modifier modifier = null;
116     if (myEvaluatedVariable != null && myContext != null) {
117       modifier = new Modifier() {
118         @Override
119         public boolean canInspect() {
120           return true;
121         }
122
123         @Override
124         public boolean canSetValue() {
125           return true;
126         }
127
128         @Override
129         public void setValue(Value value) throws ClassNotLoadedException, InvalidTypeException {
130           StackFrameProxyImpl frameProxy = myContext.getFrameProxy();
131           try {
132             assert frameProxy != null;
133             frameProxy.setValue(myEvaluatedVariable, value);
134           }
135           catch (EvaluateException e) {
136             LOG.error(e);
137           }
138         }
139
140         @Override
141         public Type getExpectedType() throws ClassNotLoadedException {
142           try {
143             return myEvaluatedVariable.getType();
144           }
145           catch (EvaluateException e) {
146             LOG.error(e);
147             return null;
148           }
149         }
150
151         @Override
152         public NodeDescriptorImpl getInspectItem(Project project) {
153           return new LocalVariableDescriptorImpl(project, myEvaluatedVariable);
154         }
155       };
156     }
157     return modifier;
158   }
159
160   @Override
161   public String toString() {
162     return myLocalVariableName;
163   }
164 }