2 * Copyright 2000-2009 JetBrains s.r.o.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * Class EvaluatorBuilderImpl
21 package com
.intellij
.debugger
.engine
.evaluation
.expression
;
23 import com
.intellij
.codeInsight
.daemon
.JavaErrorMessages
;
24 import com
.intellij
.codeInsight
.daemon
.impl
.analysis
.HighlightUtil
;
25 import com
.intellij
.debugger
.DebuggerBundle
;
26 import com
.intellij
.debugger
.SourcePosition
;
27 import com
.intellij
.debugger
.engine
.ContextUtil
;
28 import com
.intellij
.debugger
.engine
.DebuggerUtils
;
29 import com
.intellij
.debugger
.engine
.JVMName
;
30 import com
.intellij
.debugger
.engine
.JVMNameUtil
;
31 import com
.intellij
.debugger
.engine
.evaluation
.*;
32 import com
.intellij
.openapi
.diagnostic
.Logger
;
33 import com
.intellij
.openapi
.project
.Project
;
34 import com
.intellij
.psi
.*;
35 import com
.intellij
.psi
.impl
.JavaConstantExpressionEvaluator
;
36 import com
.intellij
.psi
.search
.GlobalSearchScope
;
37 import com
.intellij
.psi
.tree
.IElementType
;
38 import com
.intellij
.psi
.util
.PsiTreeUtil
;
39 import com
.intellij
.psi
.util
.PsiTypesUtil
;
40 import com
.intellij
.psi
.util
.TypeConversionUtil
;
41 import com
.intellij
.util
.IncorrectOperationException
;
42 import org
.jetbrains
.annotations
.Nullable
;
44 import java
.util
.ArrayList
;
45 import java
.util
.HashSet
;
46 import java
.util
.List
;
49 public class EvaluatorBuilderImpl
implements EvaluatorBuilder
{
50 private static final EvaluatorBuilderImpl ourInstance
= new EvaluatorBuilderImpl();
52 private EvaluatorBuilderImpl() {
55 public static EvaluatorBuilder
getInstance() {
59 public ExpressionEvaluator
build(final TextWithImports text
, final PsiElement contextElement
, final SourcePosition position
) throws EvaluateException
{
60 if (contextElement
== null) {
61 throw EvaluateExceptionUtil
.CANNOT_FIND_SOURCE_CLASS
;
64 final Project project
= contextElement
.getProject();
66 PsiCodeFragment codeFragment
= DefaultCodeFragmentFactory
.getInstance().createCodeFragment(text
, contextElement
, project
);
67 if(codeFragment
== null) {
68 throw EvaluateExceptionUtil
.createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", text
.getText()));
70 codeFragment
.forceResolveScope(GlobalSearchScope
.allScope(project
));
71 DebuggerUtils
.checkSyntax(codeFragment
);
73 return build(codeFragment
, position
);
76 public ExpressionEvaluator
build(final PsiElement codeFragment
, final SourcePosition position
) throws EvaluateException
{
77 return new Builder(position
).buildElement(codeFragment
);
80 private static class Builder
extends JavaElementVisitor
{
81 private static final Logger LOG
= Logger
.getInstance("#com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl");
82 private Evaluator myResult
= null;
83 private PsiClass myContextPsiClass
;
84 private CodeFragmentEvaluator myCurrentFragmentEvaluator
;
85 private final Set
<JavaCodeFragment
> myVisitedFragments
= new HashSet
<JavaCodeFragment
>();
87 private final SourcePosition myPosition
;
89 private Builder(@Nullable SourcePosition position
) {
90 myPosition
= position
;
94 public void visitCodeFragment(JavaCodeFragment codeFragment
) {
95 myVisitedFragments
.add(codeFragment
);
96 ArrayList
<Evaluator
> evaluators
= new ArrayList
<Evaluator
>();
98 CodeFragmentEvaluator oldFragmentEvaluator
= myCurrentFragmentEvaluator
;
99 myCurrentFragmentEvaluator
= new CodeFragmentEvaluator(oldFragmentEvaluator
);
101 for (PsiElement child
= codeFragment
.getFirstChild(); child
!= null; child
= child
.getNextSibling()) {
103 if(myResult
!= null) {
104 evaluators
.add(myResult
);
109 myCurrentFragmentEvaluator
.setStatements(evaluators
.toArray(new Evaluator
[evaluators
.size()]));
110 myResult
= myCurrentFragmentEvaluator
;
112 myCurrentFragmentEvaluator
= oldFragmentEvaluator
;
116 public void visitErrorElement(PsiErrorElement element
) {
117 throw new EvaluateRuntimeException(EvaluateExceptionUtil
118 .createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", element
.getText())));
122 public void visitAssignmentExpression(PsiAssignmentExpression expression
) {
123 final PsiExpression rExpression
= expression
.getRExpression();
124 if(rExpression
== null) {
125 throw new EvaluateRuntimeException(
126 EvaluateExceptionUtil
.createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", expression
.getText()))
130 rExpression
.accept(this);
131 Evaluator rEvaluator
= myResult
;
133 if(expression
.getOperationSign().getTokenType() != JavaTokenType
.EQ
) {
134 throw new EvaluateRuntimeException(
135 EvaluateExceptionUtil
.createEvaluateException(DebuggerBundle
.message("evaluation.error.operation.not.supported", expression
.getOperationSign().getText()))
139 final PsiExpression lExpression
= expression
.getLExpression();
141 final PsiType lType
= lExpression
.getType();
143 throw new EvaluateRuntimeException(
144 EvaluateExceptionUtil
.createEvaluateException(DebuggerBundle
.message("evaluation.error.unknown.expression.type", lExpression
.getText()))
148 if(!TypeConversionUtil
.areTypesAssignmentCompatible(lType
, rExpression
)) {
149 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(DebuggerBundle
.message("evaluation.error.incompatible.types", expression
.getOperationSign().getText())));
151 lExpression
.accept(this);
152 Evaluator lEvaluator
= myResult
;
154 if (TypeConversionUtil
.boxingConversionApplicable(lType
, rExpression
.getType())) {
155 rEvaluator
= (lType
instanceof PsiPrimitiveType
)?
new UnBoxingEvaluator(rEvaluator
) : new BoxingEvaluator(rEvaluator
);
157 myResult
= new AssignmentEvaluator(lEvaluator
, rEvaluator
);
161 public void visitStatement(PsiStatement statement
) {
162 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(DebuggerBundle
.message("evaluation.error.statement.not.supported", statement
.getText())));
166 public void visitBlockStatement(PsiBlockStatement statement
) {
167 PsiStatement
[] statements
= statement
.getCodeBlock().getStatements();
168 Evaluator
[] evaluators
= new Evaluator
[statements
.length
];
169 for (int i
= 0; i
< statements
.length
; i
++) {
170 PsiStatement psiStatement
= statements
[i
];
171 psiStatement
.accept(this);
172 evaluators
[i
] = myResult
;
175 myResult
= new BlockStatementEvaluator(evaluators
);
179 public void visitWhileStatement(PsiWhileStatement statement
) {
180 PsiStatement body
= statement
.getBody();
181 if(body
== null) return;
183 Evaluator bodyEvaluator
= myResult
;
185 PsiExpression condition
= statement
.getCondition();
186 if(condition
== null) return;
187 condition
.accept(this);
189 if(statement
.getParent() instanceof PsiLabeledStatement
) {
190 label
= ((PsiLabeledStatement
)statement
.getParent()).getLabelIdentifier().getText();
192 myResult
= new WhileStatementEvaluator(myResult
, bodyEvaluator
, label
);
196 public void visitForStatement(PsiForStatement statement
) {
197 PsiStatement initializer
= statement
.getInitialization();
198 Evaluator initializerEvaluator
= null;
199 if(initializer
!= null){
200 initializer
.accept(this);
201 initializerEvaluator
= myResult
;
204 PsiExpression condition
= statement
.getCondition();
205 Evaluator conditionEvaluator
= null;
206 if(condition
!= null) {
207 condition
.accept(this);
208 conditionEvaluator
= myResult
;
211 PsiStatement update
= statement
.getUpdate();
212 Evaluator updateEvaluator
= null;
215 updateEvaluator
= myResult
;
218 PsiStatement body
= statement
.getBody();
219 if(body
== null) return;
221 Evaluator bodyEvaluator
= myResult
;
224 if(statement
.getParent() instanceof PsiLabeledStatement
) {
225 label
= ((PsiLabeledStatement
)statement
.getParent()).getLabelIdentifier().getText();
227 myResult
= new ForStatementEvaluator(initializerEvaluator
, conditionEvaluator
, updateEvaluator
, bodyEvaluator
, label
);
231 public void visitIfStatement(PsiIfStatement statement
) {
232 PsiStatement thenBranch
= statement
.getThenBranch();
233 if(thenBranch
== null) return;
234 thenBranch
.accept(this);
235 Evaluator thenEvaluator
= myResult
;
237 PsiStatement elseBranch
= statement
.getElseBranch();
238 Evaluator elseEvaluator
= null;
239 if(elseBranch
!= null){
240 elseBranch
.accept(this);
241 elseEvaluator
= myResult
;
244 PsiExpression condition
= statement
.getCondition();
245 if(condition
== null) return;
246 condition
.accept(this);
248 myResult
= new IfStatementEvaluator(myResult
, thenEvaluator
, elseEvaluator
);
252 public void visitBreakStatement(PsiBreakStatement statement
) {
253 PsiIdentifier labelIdentifier
= statement
.getLabelIdentifier();
254 myResult
= BreakContinueStatementEvaluator
.createBreakEvaluator(labelIdentifier
!= null ? labelIdentifier
.getText() : null);
258 public void visitContinueStatement(PsiContinueStatement statement
) {
259 PsiIdentifier labelIdentifier
= statement
.getLabelIdentifier();
260 myResult
= BreakContinueStatementEvaluator
.createContinueEvaluator(labelIdentifier
!= null ? labelIdentifier
.getText() : null);
264 public void visitExpressionStatement(PsiExpressionStatement statement
) {
265 statement
.getExpression().accept(this);
269 public void visitExpression(PsiExpression expression
) {
270 if (LOG
.isDebugEnabled()) {
271 LOG
.debug("visitExpression " + expression
);
276 public void visitBinaryExpression(PsiBinaryExpression expression
) {
277 if (LOG
.isDebugEnabled()) {
278 LOG
.debug("visitBinaryExpression " + expression
);
280 final PsiExpression lOperand
= expression
.getLOperand();
281 lOperand
.accept(this);
282 Evaluator lResult
= myResult
;
283 final PsiExpression rOperand
= expression
.getROperand();
284 if(rOperand
== null) {
285 throw new EvaluateRuntimeException(EvaluateExceptionUtil
286 .createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", expression
.getText())));
288 rOperand
.accept(this);
289 IElementType opType
= expression
.getOperationSign().getTokenType();
290 PsiType type
= expression
.getType();
292 throw new EvaluateRuntimeException(EvaluateExceptionUtil
293 .createEvaluateException(DebuggerBundle
.message("evaluation.error.unknown.expression.type", expression
.getText())));
295 // handle unboxing if neccesary
296 final PsiType lType
= lOperand
.getType();
297 final PsiType rType
= rOperand
.getType();
298 if (TypeConversionUtil
.boxingConversionApplicable(lType
, rType
)) {
299 if (lType
instanceof PsiPrimitiveType
) {
300 myResult
= new UnBoxingEvaluator(myResult
);
302 else if (rType
instanceof PsiPrimitiveType
) {
303 lResult
= new UnBoxingEvaluator(lResult
);
307 myResult
= new BinaryExpressionEvaluator(lResult
, myResult
, opType
, type
.getCanonicalText());
311 public void visitDeclarationStatement(PsiDeclarationStatement statement
) {
312 List
<Evaluator
> evaluators
= new ArrayList
<Evaluator
>();
314 PsiElement
[] declaredElements
= statement
.getDeclaredElements();
315 for (PsiElement declaredElement
: declaredElements
) {
316 if (declaredElement
instanceof PsiLocalVariable
) {
317 if (myCurrentFragmentEvaluator
!= null) {
318 final PsiLocalVariable localVariable
= ((PsiLocalVariable
)declaredElement
);
320 final PsiType lType
= localVariable
.getType();
322 PsiElementFactory elementFactory
= JavaPsiFacade
.getInstance(localVariable
.getProject()).getElementFactory();
324 PsiExpression initialValue
= elementFactory
.createExpressionFromText(PsiTypesUtil
.getDefaultValueOfType(lType
), null);
325 Object value
= JavaConstantExpressionEvaluator
.computeConstantExpression(initialValue
, true);
326 myCurrentFragmentEvaluator
.setInitialValue(localVariable
.getName(), value
);
328 catch (IncorrectOperationException e
) {
331 catch (EvaluateException e
) {
332 throw new EvaluateRuntimeException(e
);
335 PsiExpression initializer
= localVariable
.getInitializer();
336 if (initializer
!= null) {
338 if (!TypeConversionUtil
.areTypesAssignmentCompatible(localVariable
.getType(), initializer
)) {
339 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(
340 DebuggerBundle
.message("evaluation.error.incompatible.variable.initializer.type", localVariable
.getName())));
342 final PsiType rType
= initializer
.getType();
343 initializer
.accept(this);
344 Evaluator rEvaluator
= myResult
;
346 PsiExpression localVarReference
= elementFactory
.createExpressionFromText(localVariable
.getName(), initializer
);
348 localVarReference
.accept(this);
349 Evaluator lEvaluator
= myResult
;
351 Evaluator assignment
= new AssignmentEvaluator(lEvaluator
, rEvaluator
);
352 if (TypeConversionUtil
.boxingConversionApplicable(lType
, rType
)) {
353 if (lType
instanceof PsiPrimitiveType
) {
354 assignment
= new UnBoxingEvaluator(assignment
);
357 assignment
= new BoxingEvaluator(assignment
);
360 evaluators
.add(assignment
);
362 catch (IncorrectOperationException e
) {
368 throw new EvaluateRuntimeException(new EvaluateException(
369 DebuggerBundle
.message("evaluation.error.local.variable.declarations.not.supported"), null));
373 throw new EvaluateRuntimeException(new EvaluateException(
374 DebuggerBundle
.message("evaluation.error.unsupported.declaration", declaredElement
.getText()), null));
378 if(evaluators
.size() > 0) {
379 CodeFragmentEvaluator codeFragmentEvaluator
= new CodeFragmentEvaluator(myCurrentFragmentEvaluator
);
380 codeFragmentEvaluator
.setStatements(evaluators
.toArray(new Evaluator
[0]));
381 myResult
= codeFragmentEvaluator
;
388 public void visitConditionalExpression(PsiConditionalExpression expression
) {
389 if (LOG
.isDebugEnabled()) {
390 LOG
.debug("visitConditionalExpression " + expression
);
392 final PsiExpression thenExpression
= expression
.getThenExpression();
393 final PsiExpression elseExpression
= expression
.getElseExpression();
394 if (thenExpression
== null || elseExpression
== null){
395 throw new EvaluateRuntimeException(EvaluateExceptionUtil
396 .createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", expression
.getText())));
398 PsiExpression condition
= expression
.getCondition();
399 condition
.accept(this);
400 if (myResult
== null) {
401 throw new EvaluateRuntimeException(EvaluateExceptionUtil
402 .createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", condition
.getText())));
404 Evaluator conditionEvaluator
= myResult
;
405 thenExpression
.accept(this);
406 if (myResult
== null) {
407 throw new EvaluateRuntimeException(EvaluateExceptionUtil
408 .createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", thenExpression
.getText())));
410 Evaluator thenEvaluator
= myResult
;
411 elseExpression
.accept(this);
412 if (myResult
== null) {
413 throw new EvaluateRuntimeException(EvaluateExceptionUtil
414 .createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", elseExpression
.getText())));
416 Evaluator elseEvaluator
= myResult
;
417 myResult
= new ConditionalExpressionEvaluator(conditionEvaluator
, thenEvaluator
, elseEvaluator
);
421 public void visitReferenceExpression(PsiReferenceExpression expression
) {
422 if (LOG
.isDebugEnabled()) {
423 LOG
.debug("visitReferenceExpression " + expression
);
425 PsiExpression qualifier
= expression
.getQualifierExpression();
426 PsiElement element
= expression
.resolve();
428 if (element
instanceof PsiLocalVariable
|| element
instanceof PsiParameter
) {
430 final PsiFile containingFile
= element
.getContainingFile();
431 if(containingFile
instanceof PsiCodeFragment
&& myCurrentFragmentEvaluator
!= null && myVisitedFragments
.contains(((PsiCodeFragment
)containingFile
))) {
432 // psiVariable may live in PsiCodeFragment not only in debugger editors, for example Fabrique has such variables.
433 // So treat it as synthetic var only when this code fragment is located in DebuggerEditor,
434 // that's why we need to check that containing code fragment is the one we visited
435 myResult
= new SyntheticVariableEvaluator(myCurrentFragmentEvaluator
, ((PsiVariable
)element
).getName());
439 final PsiVariable psiVar
= (PsiVariable
)element
;
440 final String localName
= psiVar
.getName();
441 PsiClass variableClass
= getContainingClass(psiVar
);
442 if (getContextPsiClass() == null || getContextPsiClass().equals(variableClass
)) {
443 final LocalVariableEvaluator localVarEvaluator
= new LocalVariableEvaluator(localName
, ContextUtil
.isJspImplicit(element
));
444 if (psiVar
instanceof PsiParameter
) {
445 final PsiParameter param
= (PsiParameter
)psiVar
;
446 final PsiParameterList paramList
= PsiTreeUtil
.getParentOfType(param
, PsiParameterList
.class, true);
447 if (paramList
!= null) {
448 localVarEvaluator
.setParameterIndex(paramList
.getParameterIndex(param
));
451 myResult
= localVarEvaluator
;
454 // the expression references final var outside the context's class (in some of the outer classes)
455 int iterationCount
= 0;
456 PsiClass aClass
= getOuterClass(getContextPsiClass());
457 while (aClass
!= null && !aClass
.equals(variableClass
)) {
459 aClass
= getOuterClass(aClass
);
461 if (aClass
!= null) {
462 if(psiVar
.getInitializer() != null) {
463 Object value
= JavaPsiFacade
.getInstance(psiVar
.getProject()).getConstantEvaluationHelper().computeConstantExpression(psiVar
.getInitializer());
465 myResult
= new LiteralEvaluator(value
, psiVar
.getType().getCanonicalText());
469 Evaluator objectEvaluator
= new ThisEvaluator(iterationCount
);
470 //noinspection HardCodedStringLiteral
471 final PsiClass classAt
= myPosition
!= null? JVMNameUtil
.getClassAt(myPosition
) : null;
472 FieldEvaluator
.TargetClassFilter filter
= FieldEvaluator
.createClassFilter(classAt
!= null? classAt
: getContextPsiClass());
473 myResult
= new FieldEvaluator(objectEvaluator
, filter
, "val$" + localName
);
476 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(
477 DebuggerBundle
.message("evaluation.error.local.variable.missing.from.class.closure", localName
))
480 else if (element
instanceof PsiField
) {
481 final PsiField psiField
= (PsiField
)element
;
482 final PsiClass fieldClass
= psiField
.getContainingClass();
483 if(fieldClass
== null) {
484 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(
485 DebuggerBundle
.message("evaluation.error.cannot.resolve.field.class", psiField
.getName())));
487 Evaluator objectEvaluator
;
488 if (psiField
.hasModifierProperty(PsiModifier
.STATIC
)) {
489 objectEvaluator
= new TypeEvaluator(JVMNameUtil
.getContextClassJVMQualifiedName(SourcePosition
.createFromElement(psiField
)));
491 else if(qualifier
!= null) {
492 qualifier
.accept(this);
493 objectEvaluator
= myResult
;
495 else if (fieldClass
.equals(getContextPsiClass()) || getContextPsiClass().isInheritor(fieldClass
, true)) {
496 objectEvaluator
= new ThisEvaluator();
498 else { // myContextPsiClass != fieldClass && myContextPsiClass is not a subclass of fieldClass
499 int iterationCount
= 0;
500 PsiClass aClass
= getContextPsiClass();
501 while (aClass
!= null && !(aClass
.equals(fieldClass
) || aClass
.isInheritor(fieldClass
, true))) {
503 aClass
= getOuterClass(aClass
);
505 if (aClass
== null) {
506 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(
507 DebuggerBundle
.message("evaluation.error.cannot.sources.for.field.class", psiField
.getName())));
509 objectEvaluator
= new ThisEvaluator(iterationCount
);
511 myResult
= new FieldEvaluator(objectEvaluator
, FieldEvaluator
.createClassFilter(fieldClass
), psiField
.getName());
514 //let's guess what this could be
515 PsiElement nameElement
= expression
.getReferenceNameElement(); // get "b" part
517 if (nameElement
instanceof PsiIdentifier
) {
518 name
= nameElement
.getText();
521 //noinspection HardCodedStringLiteral
522 final String elementDisplayString
= (nameElement
!= null ? nameElement
.getText() : "(null)");
523 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(
524 DebuggerBundle
.message("evaluation.error.identifier.expected", elementDisplayString
)));
527 if(qualifier
!= null) {
528 final PsiElement qualifierTarget
= (qualifier
instanceof PsiReferenceExpression
) ?
((PsiReferenceExpression
)qualifier
).resolve() : null;
529 if (qualifierTarget
instanceof PsiClass
) {
530 // this is a call to a 'static' field
531 PsiClass psiClass
= (PsiClass
)qualifierTarget
;
532 final JVMName typeName
= JVMNameUtil
.getJVMQualifiedName(psiClass
);
533 myResult
= new FieldEvaluator(new TypeEvaluator(typeName
), FieldEvaluator
.createClassFilter(psiClass
), name
);
536 PsiType type
= qualifier
.getType();
538 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(
539 DebuggerBundle
.message("evaluation.error.qualifier.type.unknown", qualifier
.getText()))
543 qualifier
.accept(this);
544 if (myResult
== null) {
545 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(
546 DebuggerBundle
.message("evaluation.error.cannot.evaluate.qualifier", qualifier
.getText()))
550 myResult
= new FieldEvaluator(myResult
, FieldEvaluator
.createClassFilter(type
), name
);
554 myResult
= new LocalVariableEvaluator(name
, false);
560 public void visitSuperExpression(PsiSuperExpression expression
) {
561 if (LOG
.isDebugEnabled()) {
562 LOG
.debug("visitSuperExpression " + expression
);
564 final int iterationCount
= calcIterationCount(expression
.getQualifier());
565 myResult
= new SuperEvaluator(iterationCount
);
569 public void visitThisExpression(PsiThisExpression expression
) {
570 if (LOG
.isDebugEnabled()) {
571 LOG
.debug("visitThisExpression " + expression
);
573 final int iterationCount
= calcIterationCount(expression
.getQualifier());
574 myResult
= new ThisEvaluator(iterationCount
);
577 private int calcIterationCount(final PsiJavaCodeReferenceElement qualifier
) {
578 int iterationCount
= 0;
579 if (qualifier
!= null) {
580 PsiElement targetClass
= qualifier
.resolve();
581 if (targetClass
== null || getContextPsiClass() == null) {
582 throw new EvaluateRuntimeException(EvaluateExceptionUtil
583 .createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", qualifier
.getText())));
586 PsiClass aClass
= getContextPsiClass();
587 while (aClass
!= null && !aClass
.equals(targetClass
)) {
589 aClass
= getOuterClass(aClass
);
592 catch (Exception e
) {
593 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(e
));
596 return iterationCount
;
600 public void visitInstanceOfExpression(PsiInstanceOfExpression expression
) {
601 if (LOG
.isDebugEnabled()) {
602 LOG
.debug("visitInstanceOfExpression " + expression
);
604 PsiTypeElement checkType
= expression
.getCheckType();
605 if(checkType
== null) {
606 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", expression
.getText())));
608 PsiType type
= checkType
.getType();
609 expression
.getOperand().accept(this);
610 // ClassObjectEvaluator typeEvaluator = new ClassObjectEvaluator(type.getCanonicalText());
611 Evaluator operandEvaluator
= myResult
;
612 myResult
= new InstanceofEvaluator(operandEvaluator
, new TypeEvaluator(JVMNameUtil
.getJVMQualifiedName(type
)));
616 public void visitParenthesizedExpression(PsiParenthesizedExpression expression
) {
617 if (LOG
.isDebugEnabled()) {
618 LOG
.debug("visitParenthesizedExpression " + expression
);
620 PsiExpression expr
= expression
.getExpression();
627 public void visitPostfixExpression(PsiPostfixExpression expression
) {
628 expression
.getOperand().accept(this);
629 PsiType type
= expression
.getType();
631 throw new EvaluateRuntimeException(EvaluateExceptionUtil
632 .createEvaluateException(DebuggerBundle
.message("evaluation.error.unknown.expression.type", expression
.getText())));
634 myResult
= new PostfixOperationEvaluator(myResult
, expression
.getOperationSign().getTokenType(), type
.getCanonicalText());
638 public void visitPrefixExpression(final PsiPrefixExpression expression
) {
639 final PsiType expressionType
= expression
.getType();
640 if(expressionType
== null) {
641 throw new EvaluateRuntimeException(
642 EvaluateExceptionUtil
.createEvaluateException(DebuggerBundle
.message("evaluation.error.unknown.expression.type", expression
.getText()))
646 final PsiExpression operandExpression
= expression
.getOperand();
647 if (operandExpression
== null) {
648 throw new EvaluateRuntimeException(
649 EvaluateExceptionUtil
.createEvaluateException(DebuggerBundle
.message("evaluation.error.unknown.expression.operand", expression
.getText()))
653 final PsiType operandExpressionType
= operandExpression
.getType();
655 operandExpression
.accept(this);
656 final Evaluator operand
= myResult
;
658 final IElementType opType
= expression
.getOperationSign().getTokenType();
660 if(opType
== JavaTokenType
.PLUSPLUS
|| opType
== JavaTokenType
.MINUSMINUS
) {
661 final boolean isPlus
= opType
== JavaTokenType
.PLUSPLUS
;
664 PsiElementFactory elementFactory
= JavaPsiFacade
.getInstance(expression
.getProject()).getElementFactory();
665 PsiExpression one
= elementFactory
.createExpressionFromText("1", null);
667 // handle unboxing issues
668 Evaluator left
= operand
;
669 if (!(operandExpressionType
instanceof PsiPrimitiveType
)) {
670 left
= new UnBoxingEvaluator(left
);
673 PsiType expected
= expressionType
;
674 final PsiPrimitiveType unboxedExpectedType
= PsiPrimitiveType
.getUnboxedType(expected
);
675 if (unboxedExpectedType
!= null) {
676 expected
= unboxedExpectedType
;
678 final BinaryExpressionEvaluator rightEval
= new BinaryExpressionEvaluator(
679 left
, myResult
, isPlus ? JavaTokenType
.PLUS
: JavaTokenType
.MINUS
, expected
.getCanonicalText()
681 myResult
= new AssignmentEvaluator(
682 operand
, unboxedExpectedType
!= null?
new BoxingEvaluator(rightEval
) : rightEval
685 catch (IncorrectOperationException e
) {
690 PsiType expected
= expressionType
;
691 final PsiPrimitiveType unboxedExpectedType
= PsiPrimitiveType
.getUnboxedType(expected
);
692 if (unboxedExpectedType
!= null) {
693 expected
= unboxedExpectedType
;
695 final UnaryExpressionEvaluator unaryEvaluator
=
696 new UnaryExpressionEvaluator(opType
, expected
.getCanonicalText(), new UnBoxingEvaluator(operand
),
697 expression
.getOperationSign().getText());
698 myResult
= unboxedExpectedType
!= null?
new BoxingEvaluator(unaryEvaluator
) : unaryEvaluator
;
703 public void visitMethodCallExpression(PsiMethodCallExpression expression
) {
704 if (LOG
.isDebugEnabled()) {
705 LOG
.debug("visitMethodCallExpression " + expression
);
707 final PsiExpressionList argumentList
= expression
.getArgumentList();
708 final PsiExpression
[] argExpressions
= argumentList
.getExpressions();
709 List
<Evaluator
> argumentEvaluators
= new ArrayList
<Evaluator
>(argExpressions
.length
);
710 // evaluate arguments
711 for (PsiExpression psiExpression
: argExpressions
) {
712 psiExpression
.accept(this);
713 if (myResult
== null) {
714 // cannot build evaluator
715 throw new EvaluateRuntimeException(
716 EvaluateExceptionUtil
.createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", psiExpression
.getText()))
719 argumentEvaluators
.add(myResult
);
721 PsiReferenceExpression methodExpr
= expression
.getMethodExpression();
723 final JavaResolveResult resolveResult
= methodExpr
.advancedResolve(false);
724 final PsiMethod psiMethod
= (PsiMethod
)resolveResult
.getElement();
726 PsiExpression qualifier
= methodExpr
.getQualifierExpression();
727 Evaluator objectEvaluator
;
728 JVMName contextClass
= null;
730 if(psiMethod
!= null) {
731 PsiClass methodPsiClass
= psiMethod
.getContainingClass();
732 contextClass
= JVMNameUtil
.getJVMQualifiedName(methodPsiClass
);
733 if (psiMethod
.hasModifierProperty(PsiModifier
.STATIC
)) {
734 objectEvaluator
= new TypeEvaluator(contextClass
);
736 else if (qualifier
!= null ) {
737 qualifier
.accept(this);
738 objectEvaluator
= myResult
;
741 int iterationCount
= 0;
742 final PsiElement currentFileResolveScope
= resolveResult
.getCurrentFileResolveScope();
743 if (currentFileResolveScope
instanceof PsiClass
) {
744 PsiClass aClass
= getContextPsiClass();
745 while(aClass
!= null && !aClass
.equals(currentFileResolveScope
)) {
746 aClass
= getOuterClass(aClass
);
750 objectEvaluator
= new ThisEvaluator(iterationCount
);
755 if (qualifier
!= null) {
756 PsiType type
= qualifier
.getType();
759 contextClass
= JVMNameUtil
.getJVMQualifiedName(type
);
762 if (qualifier
instanceof PsiReferenceExpression
&& ((PsiReferenceExpression
)qualifier
).resolve() instanceof PsiClass
) {
763 // this is a call to a 'static' method
764 if (contextClass
== null && type
== null) {
765 throw new EvaluateRuntimeException(
766 EvaluateExceptionUtil
.createEvaluateException(DebuggerBundle
.message("evaluation.error.qualifier.type.unknown", qualifier
.getText()))
769 assert contextClass
!= null;
770 objectEvaluator
= new TypeEvaluator(contextClass
);
773 qualifier
.accept(this);
774 objectEvaluator
= myResult
;
778 objectEvaluator
= new ThisEvaluator();
779 contextClass
= JVMNameUtil
.getContextClassJVMQualifiedName(myPosition
);
780 if(contextClass
== null && myContextPsiClass
!= null) {
781 contextClass
= JVMNameUtil
.getJVMQualifiedName(myContextPsiClass
);
784 // throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(
785 // DebuggerBundle.message("evaluation.error.method.not.found", methodExpr.getReferenceName()))
791 if (objectEvaluator
== null) {
792 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", expression
.getText())));
795 if (psiMethod
!= null && !psiMethod
.isConstructor()) {
796 if (psiMethod
.getReturnType() == null) {
797 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(DebuggerBundle
.message("evaluation.error.unknown.method.return.type", psiMethod
.getText())));
801 myResult
= new MethodEvaluator(objectEvaluator
, contextClass
, methodExpr
.getReferenceName(), psiMethod
!= null ? JVMNameUtil
.getJVMSignature(psiMethod
) : null, argumentEvaluators
);
805 public void visitLiteralExpression(PsiLiteralExpression expression
) {
806 Object value
= expression
.getValue();
807 if(expression
.getParsingError() != null) {
808 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(expression
.getParsingError()));
810 myResult
= new LiteralEvaluator(value
, expression
.getType().getCanonicalText());
814 public void visitArrayAccessExpression(PsiArrayAccessExpression expression
) {
815 final PsiExpression indexExpression
= expression
.getIndexExpression();
816 if(indexExpression
== null) {
817 throw new EvaluateRuntimeException(EvaluateExceptionUtil
818 .createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", expression
.getText())));
820 indexExpression
.accept(this);
821 Evaluator indexEvaluator
= myResult
;
822 expression
.getArrayExpression().accept(this);
823 Evaluator arrayEvaluator
= myResult
;
824 myResult
= new ArrayAccessEvaluator(arrayEvaluator
, indexEvaluator
);
827 @SuppressWarnings({"ConstantConditions"})
829 public void visitTypeCastExpression(PsiTypeCastExpression expression
) {
830 final PsiExpression operandExpr
= expression
.getOperand();
831 operandExpr
.accept(this);
832 Evaluator operandEvaluator
= myResult
;
833 final PsiType castType
= expression
.getCastType().getType();
834 final PsiType operandType
= operandExpr
.getType();
836 if (!TypeConversionUtil
.areTypesConvertible(operandType
, castType
)) {
837 throw new EvaluateRuntimeException(
838 new EvaluateException(JavaErrorMessages
.message("inconvertible.type.cast", HighlightUtil
.formatType(operandType
), HighlightUtil
.formatType(castType
)))
842 final boolean shouldPerformBoxingConversion
= TypeConversionUtil
.boxingConversionApplicable(castType
, operandType
);
843 final boolean castingToPrimitive
= castType
instanceof PsiPrimitiveType
;
844 if (shouldPerformBoxingConversion
&& castingToPrimitive
) {
845 operandEvaluator
= new UnBoxingEvaluator(operandEvaluator
);
848 final boolean performCastToWrapperClass
= shouldPerformBoxingConversion
&& !castingToPrimitive
;
850 String castTypeName
= castType
.getCanonicalText();
851 if (performCastToWrapperClass
) {
852 final PsiPrimitiveType unboxedType
= PsiPrimitiveType
.getUnboxedType(castType
);
853 if (unboxedType
!= null) {
854 castTypeName
= unboxedType
.getCanonicalText();
858 myResult
= new TypeCastEvaluator(operandEvaluator
, castTypeName
, castingToPrimitive
);
860 if (performCastToWrapperClass
) {
861 myResult
= new BoxingEvaluator(myResult
);
866 public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression
) {
867 PsiType type
= expression
.getOperand().getType();
869 if (type
instanceof PsiPrimitiveType
) {
870 final JVMName typeName
= JVMNameUtil
.getJVMRawText(((PsiPrimitiveType
)type
).getBoxedTypeName());
871 myResult
= new FieldEvaluator(new TypeEvaluator(typeName
), FieldEvaluator
.TargetClassFilter
.ALL
, "TYPE");
874 myResult
= new ClassObjectEvaluator(new TypeEvaluator(JVMNameUtil
.getJVMQualifiedName(type
)));
879 public void visitNewExpression(PsiNewExpression expression
) {
880 PsiType expressionPsiType
= expression
.getType();
881 if (expressionPsiType
instanceof PsiArrayType
) {
882 Evaluator dimensionEvaluator
= null;
883 PsiExpression
[] dimensions
= expression
.getArrayDimensions();
884 if (dimensions
.length
== 1){
885 PsiExpression dimensionExpression
= dimensions
[0];
886 dimensionExpression
.accept(this);
887 if (myResult
!= null) {
888 dimensionEvaluator
= myResult
;
891 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(
892 DebuggerBundle
.message("evaluation.error.invalid.array.dimension.expression", dimensionExpression
.getText())));
895 else if (dimensions
.length
> 1){
896 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(
897 DebuggerBundle
.message("evaluation.error.multi.dimensional.arrays.creation.not.supported"))
901 Evaluator initializerEvaluator
= null;
902 PsiArrayInitializerExpression arrayInitializer
= expression
.getArrayInitializer();
903 if (arrayInitializer
!= null) {
904 if (dimensionEvaluator
!= null) { // initializer already exists
905 throw new EvaluateRuntimeException(EvaluateExceptionUtil
906 .createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", expression
.getText())));
908 arrayInitializer
.accept(this);
909 if (myResult
!= null) {
910 initializerEvaluator
= myResult
;
913 throw new EvaluateRuntimeException(EvaluateExceptionUtil
914 .createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", arrayInitializer
.getText())));
917 PsiExpression[] initializers = arrayInitializer.getInitializers();
918 initializerEvaluators = new Evaluator[initializers.length];
919 for (int idx = 0; idx < initializers.length; idx++) {
920 PsiExpression initializer = initializers[idx];
921 initializer.accept(this);
922 if (myResult instanceof Evaluator) {
923 initializerEvaluators[idx] = myResult;
926 throw new EvaluateException("Invalid expression for array initializer: " + initializer.getText(), true);
931 if (dimensionEvaluator
== null && initializerEvaluator
== null) {
932 throw new EvaluateRuntimeException(EvaluateExceptionUtil
933 .createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", expression
.getText())));
935 myResult
= new NewArrayInstanceEvaluator(
936 new TypeEvaluator(JVMNameUtil
.getJVMQualifiedName(expressionPsiType
)),
941 else { // must be a class ref
942 LOG
.assertTrue(expressionPsiType
instanceof PsiClassType
);
943 PsiClass aClass
= ((PsiClassType
)expressionPsiType
).resolve();
944 if(aClass
instanceof PsiAnonymousClass
) {
945 throw new EvaluateRuntimeException(EvaluateExceptionUtil
.createEvaluateException(
946 DebuggerBundle
.message("evaluation.error.anonymous.class.evaluation.not.supported"))
949 PsiExpressionList argumentList
= expression
.getArgumentList();
950 if (argumentList
== null) {
951 throw new EvaluateRuntimeException(EvaluateExceptionUtil
952 .createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", expression
.getText())));
954 PsiExpression
[] argExpressions
= argumentList
.getExpressions();
955 PsiMethod constructor
= expression
.resolveConstructor();
956 if (constructor
== null && argExpressions
.length
> 0) {
957 throw new EvaluateRuntimeException(new EvaluateException(
958 DebuggerBundle
.message("evaluation.error.cannot.resolve.constructor", expression
.getText()), null));
960 Evaluator
[] argumentEvaluators
= new Evaluator
[argExpressions
.length
];
961 // evaluate arguments
962 for (int idx
= 0; idx
< argExpressions
.length
; idx
++) {
963 PsiExpression argExpression
= argExpressions
[idx
];
964 argExpression
.accept(this);
965 if (myResult
!= null) {
966 argumentEvaluators
[idx
] = myResult
;
969 throw new EvaluateRuntimeException(EvaluateExceptionUtil
970 .createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", argExpression
.getText())));
973 //noinspection HardCodedStringLiteral
974 JVMName signature
= (constructor
!= null)? JVMNameUtil
.getJVMSignature(constructor
) : JVMNameUtil
.getJVMRawText("()V");
975 myResult
= new NewClassInstanceEvaluator(
976 new TypeEvaluator(JVMNameUtil
.getJVMQualifiedName(expressionPsiType
)),
984 public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression
) {
985 PsiExpression
[] initializers
= expression
.getInitializers();
986 Evaluator
[] evaluators
= new Evaluator
[initializers
.length
];
987 for (int idx
= 0; idx
< initializers
.length
; idx
++) {
988 PsiExpression initializer
= initializers
[idx
];
989 initializer
.accept(this);
990 if (myResult
!= null) {
991 evaluators
[idx
] = myResult
;
994 throw new EvaluateRuntimeException(EvaluateExceptionUtil
995 .createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", initializer
.getText())));
998 myResult
= new ArrayInitializerEvaluator(evaluators
);
1001 private PsiClass
getOuterClass(PsiClass aClass
) {
1002 if(aClass
== null) return null;
1003 return PsiTreeUtil
.getContextOfType(aClass
, PsiClass
.class, true);
1006 private PsiClass
getContainingClass(PsiVariable variable
) {
1007 PsiElement element
= PsiTreeUtil
.getParentOfType(variable
.getParent(), PsiClass
.class, false);
1008 return element
== null ?
getContextPsiClass() : (PsiClass
)element
;
1011 public PsiClass
getContextPsiClass() {
1012 return myContextPsiClass
;
1015 protected ExpressionEvaluator
buildElement(final PsiElement element
) throws EvaluateException
{
1016 LOG
.assertTrue(element
.isValid());
1018 myContextPsiClass
= PsiTreeUtil
.getContextOfType(element
, PsiClass
.class, false);
1020 element
.accept(this);
1022 catch (EvaluateRuntimeException e
) {
1025 if (myResult
== null) {
1026 throw EvaluateExceptionUtil
1027 .createEvaluateException(DebuggerBundle
.message("evaluation.error.invalid.expression", element
.toString()));
1029 return new ExpressionEvaluatorImpl(myResult
);