57aead799666f3c3e8d302209a46726c64e27112
[fedora-idea.git] / java / debugger / impl / src / com / intellij / debugger / engine / evaluation / expression / EvaluatorBuilderImpl.java
blob57aead799666f3c3e8d302209a46726c64e27112
1 /*
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
19 * @author Jeka
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;
47 import java.util.Set;
49 public class EvaluatorBuilderImpl implements EvaluatorBuilder {
50 private static final EvaluatorBuilderImpl ourInstance = new EvaluatorBuilderImpl();
52 private EvaluatorBuilderImpl() {
55 public static EvaluatorBuilder getInstance() {
56 return ourInstance;
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>();
86 @Nullable
87 private final SourcePosition myPosition;
89 private Builder(@Nullable SourcePosition position) {
90 myPosition = position;
93 @Override
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()) {
102 child.accept(this);
103 if(myResult != null) {
104 evaluators.add(myResult);
106 myResult = null;
109 myCurrentFragmentEvaluator.setStatements(evaluators.toArray(new Evaluator[evaluators.size()]));
110 myResult = myCurrentFragmentEvaluator;
112 myCurrentFragmentEvaluator = oldFragmentEvaluator;
115 @Override
116 public void visitErrorElement(PsiErrorElement element) {
117 throw new EvaluateRuntimeException(EvaluateExceptionUtil
118 .createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", element.getText())));
121 @Override
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();
142 if(lType == null) {
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);
160 @Override
161 public void visitStatement(PsiStatement statement) {
162 throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.statement.not.supported", statement.getText())));
165 @Override
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;
173 myResult = null;
175 myResult = new BlockStatementEvaluator(evaluators);
178 @Override
179 public void visitWhileStatement(PsiWhileStatement statement) {
180 PsiStatement body = statement.getBody();
181 if(body == null) return;
182 body.accept(this);
183 Evaluator bodyEvaluator = myResult;
185 PsiExpression condition = statement.getCondition();
186 if(condition == null) return;
187 condition.accept(this);
188 String label = null;
189 if(statement.getParent() instanceof PsiLabeledStatement) {
190 label = ((PsiLabeledStatement)statement.getParent()).getLabelIdentifier().getText();
192 myResult = new WhileStatementEvaluator(myResult, bodyEvaluator, label);
195 @Override
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;
213 if(update != null){
214 update.accept(this);
215 updateEvaluator = myResult;
218 PsiStatement body = statement.getBody();
219 if(body == null) return;
220 body.accept(this);
221 Evaluator bodyEvaluator = myResult;
223 String label = null;
224 if(statement.getParent() instanceof PsiLabeledStatement) {
225 label = ((PsiLabeledStatement)statement.getParent()).getLabelIdentifier().getText();
227 myResult = new ForStatementEvaluator(initializerEvaluator, conditionEvaluator, updateEvaluator, bodyEvaluator, label);
230 @Override
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);
251 @Override
252 public void visitBreakStatement(PsiBreakStatement statement) {
253 PsiIdentifier labelIdentifier = statement.getLabelIdentifier();
254 myResult = BreakContinueStatementEvaluator.createBreakEvaluator(labelIdentifier != null ? labelIdentifier.getText() : null);
257 @Override
258 public void visitContinueStatement(PsiContinueStatement statement) {
259 PsiIdentifier labelIdentifier = statement.getLabelIdentifier();
260 myResult = BreakContinueStatementEvaluator.createContinueEvaluator(labelIdentifier != null ? labelIdentifier.getText() : null);
263 @Override
264 public void visitExpressionStatement(PsiExpressionStatement statement) {
265 statement.getExpression().accept(this);
268 @Override
269 public void visitExpression(PsiExpression expression) {
270 if (LOG.isDebugEnabled()) {
271 LOG.debug("visitExpression " + expression);
275 @Override
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();
291 if (type == null) {
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());
310 @Override
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();
323 try {
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) {
329 LOG.error(e);
331 catch (EvaluateException e) {
332 throw new EvaluateRuntimeException(e);
335 PsiExpression initializer = localVariable.getInitializer();
336 if (initializer != null) {
337 try {
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);
356 else {
357 assignment = new BoxingEvaluator(assignment);
360 evaluators.add(assignment);
362 catch (IncorrectOperationException e) {
363 LOG.error(e);
367 else {
368 throw new EvaluateRuntimeException(new EvaluateException(
369 DebuggerBundle.message("evaluation.error.local.variable.declarations.not.supported"), null));
372 else {
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;
382 } else {
383 myResult = null;
387 @Override
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);
420 @Override
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) {
429 //synthetic variable
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());
436 return;
438 // local variable
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;
452 return;
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)) {
458 iterationCount++;
459 aClass = getOuterClass(aClass);
461 if (aClass != null) {
462 if(psiVar.getInitializer() != null) {
463 Object value = JavaPsiFacade.getInstance(psiVar.getProject()).getConstantEvaluationHelper().computeConstantExpression(psiVar.getInitializer());
464 if(value != null) {
465 myResult = new LiteralEvaluator(value, psiVar.getType().getCanonicalText());
466 return;
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);
474 return;
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))) {
502 iterationCount++;
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());
513 else {
514 //let's guess what this could be
515 PsiElement nameElement = expression.getReferenceNameElement(); // get "b" part
516 String name;
517 if (nameElement instanceof PsiIdentifier) {
518 name = nameElement.getText();
520 else {
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);
535 else {
536 PsiType type = qualifier.getType();
537 if(type == null) {
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);
553 else {
554 myResult = new LocalVariableEvaluator(name, false);
559 @Override
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);
568 @Override
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())));
585 try {
586 PsiClass aClass = getContextPsiClass();
587 while (aClass != null && !aClass.equals(targetClass)) {
588 iterationCount++;
589 aClass = getOuterClass(aClass);
592 catch (Exception e) {
593 throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(e));
596 return iterationCount;
599 @Override
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)));
615 @Override
616 public void visitParenthesizedExpression(PsiParenthesizedExpression expression) {
617 if (LOG.isDebugEnabled()) {
618 LOG.debug("visitParenthesizedExpression " + expression);
620 PsiExpression expr = expression.getExpression();
621 if (expr != null){
622 expr.accept(this);
626 @Override
627 public void visitPostfixExpression(PsiPostfixExpression expression) {
628 expression.getOperand().accept(this);
629 PsiType type = expression.getType();
630 if(type == null) {
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());
637 @Override
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;
663 try {
664 PsiElementFactory elementFactory = JavaPsiFacade.getInstance(expression.getProject()).getElementFactory();
665 PsiExpression one = elementFactory.createExpressionFromText("1", null);
666 one.accept(this);
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) {
686 LOG.error(e);
689 else {
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;
702 @Override
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;
740 else {
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);
747 iterationCount++;
750 objectEvaluator = new ThisEvaluator(iterationCount);
753 else {
754 //trying to guess
755 if (qualifier != null) {
756 PsiType type = qualifier.getType();
758 if (type != null) {
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);
772 else {
773 qualifier.accept(this);
774 objectEvaluator = myResult;
777 else {
778 objectEvaluator = new ThisEvaluator();
779 contextClass = JVMNameUtil.getContextClassJVMQualifiedName(myPosition);
780 if(contextClass == null && myContextPsiClass != null) {
781 contextClass = JVMNameUtil.getJVMQualifiedName(myContextPsiClass);
783 //else {
784 // throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(
785 // DebuggerBundle.message("evaluation.error.method.not.found", methodExpr.getReferenceName()))
786 // );
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 if (psiMethod != null) {
802 // handle autoboxing
803 for (int i = 0, parametersLength = psiMethod.getParameterList().getParameters().length; i < parametersLength; i++) {
804 PsiParameter parameter = psiMethod.getParameterList().getParameters()[i];
805 final PsiType paramType = parameter.getType();
806 final PsiType realArgType = argExpressions[i].getType();
807 if (TypeConversionUtil.boxingConversionApplicable(paramType, realArgType)) {
808 final Evaluator argEval = argumentEvaluators.get(i);
809 argumentEvaluators.set(i, (paramType instanceof PsiPrimitiveType)? new UnBoxingEvaluator(argEval) : new BoxingEvaluator(argEval));
814 myResult = new MethodEvaluator(objectEvaluator, contextClass, methodExpr.getReferenceName(), psiMethod != null ? JVMNameUtil.getJVMSignature(psiMethod) : null, argumentEvaluators);
817 @Override
818 public void visitLiteralExpression(PsiLiteralExpression expression) {
819 Object value = expression.getValue();
820 if(expression.getParsingError() != null) {
821 throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(expression.getParsingError()));
823 myResult = new LiteralEvaluator(value, expression.getType().getCanonicalText());
826 @Override
827 public void visitArrayAccessExpression(PsiArrayAccessExpression expression) {
828 final PsiExpression indexExpression = expression.getIndexExpression();
829 if(indexExpression == null) {
830 throw new EvaluateRuntimeException(EvaluateExceptionUtil
831 .createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())));
833 indexExpression.accept(this);
834 Evaluator indexEvaluator = myResult;
835 expression.getArrayExpression().accept(this);
836 Evaluator arrayEvaluator = myResult;
837 myResult = new ArrayAccessEvaluator(arrayEvaluator, indexEvaluator);
840 @SuppressWarnings({"ConstantConditions"})
841 @Override
842 public void visitTypeCastExpression(PsiTypeCastExpression expression) {
843 final PsiExpression operandExpr = expression.getOperand();
844 operandExpr.accept(this);
845 Evaluator operandEvaluator = myResult;
846 final PsiType castType = expression.getCastType().getType();
847 final PsiType operandType = operandExpr.getType();
849 if (!TypeConversionUtil.areTypesConvertible(operandType, castType)) {
850 throw new EvaluateRuntimeException(
851 new EvaluateException(JavaErrorMessages.message("inconvertible.type.cast", HighlightUtil.formatType(operandType), HighlightUtil.formatType(castType)))
855 final boolean shouldPerformBoxingConversion = TypeConversionUtil.boxingConversionApplicable(castType, operandType);
856 final boolean castingToPrimitive = castType instanceof PsiPrimitiveType;
857 if (shouldPerformBoxingConversion && castingToPrimitive) {
858 operandEvaluator = new UnBoxingEvaluator(operandEvaluator);
861 final boolean performCastToWrapperClass = shouldPerformBoxingConversion && !castingToPrimitive;
863 String castTypeName = castType.getCanonicalText();
864 if (performCastToWrapperClass) {
865 final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(castType);
866 if (unboxedType != null) {
867 castTypeName = unboxedType.getCanonicalText();
871 myResult = new TypeCastEvaluator(operandEvaluator, castTypeName, castingToPrimitive);
873 if (performCastToWrapperClass) {
874 myResult = new BoxingEvaluator(myResult);
878 @Override
879 public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) {
880 PsiType type = expression.getOperand().getType();
882 if (type instanceof PsiPrimitiveType) {
883 final JVMName typeName = JVMNameUtil.getJVMRawText(((PsiPrimitiveType)type).getBoxedTypeName());
884 myResult = new FieldEvaluator(new TypeEvaluator(typeName), FieldEvaluator.TargetClassFilter.ALL, "TYPE");
886 else {
887 myResult = new ClassObjectEvaluator(new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(type)));
891 @Override
892 public void visitNewExpression(PsiNewExpression expression) {
893 PsiType expressionPsiType = expression.getType();
894 if (expressionPsiType instanceof PsiArrayType) {
895 Evaluator dimensionEvaluator = null;
896 PsiExpression[] dimensions = expression.getArrayDimensions();
897 if (dimensions.length == 1){
898 PsiExpression dimensionExpression = dimensions[0];
899 dimensionExpression.accept(this);
900 if (myResult != null) {
901 dimensionEvaluator = myResult;
903 else {
904 throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(
905 DebuggerBundle.message("evaluation.error.invalid.array.dimension.expression", dimensionExpression.getText())));
908 else if (dimensions.length > 1){
909 throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(
910 DebuggerBundle.message("evaluation.error.multi.dimensional.arrays.creation.not.supported"))
914 Evaluator initializerEvaluator = null;
915 PsiArrayInitializerExpression arrayInitializer = expression.getArrayInitializer();
916 if (arrayInitializer != null) {
917 if (dimensionEvaluator != null) { // initializer already exists
918 throw new EvaluateRuntimeException(EvaluateExceptionUtil
919 .createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())));
921 arrayInitializer.accept(this);
922 if (myResult != null) {
923 initializerEvaluator = myResult;
925 else {
926 throw new EvaluateRuntimeException(EvaluateExceptionUtil
927 .createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", arrayInitializer.getText())));
930 PsiExpression[] initializers = arrayInitializer.getInitializers();
931 initializerEvaluators = new Evaluator[initializers.length];
932 for (int idx = 0; idx < initializers.length; idx++) {
933 PsiExpression initializer = initializers[idx];
934 initializer.accept(this);
935 if (myResult instanceof Evaluator) {
936 initializerEvaluators[idx] = myResult;
938 else {
939 throw new EvaluateException("Invalid expression for array initializer: " + initializer.getText(), true);
944 if (dimensionEvaluator == null && initializerEvaluator == null) {
945 throw new EvaluateRuntimeException(EvaluateExceptionUtil
946 .createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())));
948 myResult = new NewArrayInstanceEvaluator(
949 new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(expressionPsiType)),
950 dimensionEvaluator,
951 initializerEvaluator
954 else { // must be a class ref
955 LOG.assertTrue(expressionPsiType instanceof PsiClassType);
956 PsiClass aClass = ((PsiClassType)expressionPsiType).resolve();
957 if(aClass instanceof PsiAnonymousClass) {
958 throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(
959 DebuggerBundle.message("evaluation.error.anonymous.class.evaluation.not.supported"))
962 PsiExpressionList argumentList = expression.getArgumentList();
963 if (argumentList == null) {
964 throw new EvaluateRuntimeException(EvaluateExceptionUtil
965 .createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())));
967 PsiExpression[] argExpressions = argumentList.getExpressions();
968 PsiMethod constructor = expression.resolveConstructor();
969 if (constructor == null && argExpressions.length > 0) {
970 throw new EvaluateRuntimeException(new EvaluateException(
971 DebuggerBundle.message("evaluation.error.cannot.resolve.constructor", expression.getText()), null));
973 Evaluator[] argumentEvaluators = new Evaluator[argExpressions.length];
974 // evaluate arguments
975 for (int idx = 0; idx < argExpressions.length; idx++) {
976 PsiExpression argExpression = argExpressions[idx];
977 argExpression.accept(this);
978 if (myResult != null) {
979 argumentEvaluators[idx] = myResult;
981 else {
982 throw new EvaluateRuntimeException(EvaluateExceptionUtil
983 .createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", argExpression.getText())));
986 //noinspection HardCodedStringLiteral
987 JVMName signature = (constructor != null)? JVMNameUtil.getJVMSignature(constructor) : JVMNameUtil.getJVMRawText("()V");
988 myResult = new NewClassInstanceEvaluator(
989 new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(expressionPsiType)),
990 signature,
991 argumentEvaluators
996 @Override
997 public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) {
998 PsiExpression[] initializers = expression.getInitializers();
999 Evaluator[] evaluators = new Evaluator[initializers.length];
1000 for (int idx = 0; idx < initializers.length; idx++) {
1001 PsiExpression initializer = initializers[idx];
1002 initializer.accept(this);
1003 if (myResult != null) {
1004 evaluators[idx] = myResult;
1006 else {
1007 throw new EvaluateRuntimeException(EvaluateExceptionUtil
1008 .createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", initializer.getText())));
1011 myResult = new ArrayInitializerEvaluator(evaluators);
1014 private PsiClass getOuterClass(PsiClass aClass) {
1015 if(aClass == null) return null;
1016 return PsiTreeUtil.getContextOfType(aClass, PsiClass.class, true);
1019 private PsiClass getContainingClass(PsiVariable variable) {
1020 PsiElement element = PsiTreeUtil.getParentOfType(variable.getParent(), PsiClass.class, false);
1021 return element == null ? getContextPsiClass() : (PsiClass)element;
1024 public PsiClass getContextPsiClass() {
1025 return myContextPsiClass;
1028 protected ExpressionEvaluator buildElement(final PsiElement element) throws EvaluateException {
1029 LOG.assertTrue(element.isValid());
1031 myContextPsiClass = PsiTreeUtil.getContextOfType(element, PsiClass.class, false);
1032 try {
1033 element.accept(this);
1035 catch (EvaluateRuntimeException e) {
1036 throw e.getCause();
1038 if (myResult == null) {
1039 throw EvaluateExceptionUtil
1040 .createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", element.toString()));
1042 return new ExpressionEvaluatorImpl(myResult);