Merge branch 'master' of git@git.labs.intellij.net:idea/community
[idea/community.git] / java / debugger / impl / src / com / intellij / debugger / engine / evaluation / expression / EvaluatorBuilderImpl.java
1 /*
2  * Copyright 2000-2009 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 EvaluatorBuilderImpl
19  * @author Jeka
20  */
21 package com.intellij.debugger.engine.evaluation.expression;
22
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 com.sun.jdi.Value;
43 import org.jetbrains.annotations.Nullable;
44
45 import java.util.ArrayList;
46 import java.util.HashSet;
47 import java.util.List;
48 import java.util.Set;
49
50 public class EvaluatorBuilderImpl implements EvaluatorBuilder {
51   private static final EvaluatorBuilderImpl ourInstance = new EvaluatorBuilderImpl();
52   private final CodeFragmentFactory myCodeFactory;
53
54   private EvaluatorBuilderImpl() {
55     myCodeFactory = new CodeFragmentFactoryContextWrapper(DefaultCodeFragmentFactory.getInstance());
56   }
57
58   public static EvaluatorBuilder getInstance() {
59     return ourInstance;
60   }
61
62   public ExpressionEvaluator build(final TextWithImports text, final PsiElement contextElement, final SourcePosition position) throws EvaluateException {
63     if (contextElement == null) {
64       throw EvaluateExceptionUtil.CANNOT_FIND_SOURCE_CLASS;
65     }
66
67     final Project project = contextElement.getProject();
68
69     PsiCodeFragment codeFragment = myCodeFactory.createCodeFragment(text, contextElement, project);
70     if(codeFragment == null) {
71       throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", text.getText()));
72     }
73     codeFragment.forceResolveScope(GlobalSearchScope.allScope(project));
74     DebuggerUtils.checkSyntax(codeFragment);
75
76     return build(codeFragment, position);
77   }
78
79   public ExpressionEvaluator build(final PsiElement codeFragment, final SourcePosition position) throws EvaluateException {
80     return new Builder(position).buildElement(codeFragment);
81   }
82
83   private static class Builder extends JavaElementVisitor {
84     private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl");
85     private Evaluator myResult = null;
86     private PsiClass myContextPsiClass;
87     private CodeFragmentEvaluator myCurrentFragmentEvaluator;
88     private final Set<JavaCodeFragment> myVisitedFragments = new HashSet<JavaCodeFragment>();
89     @Nullable
90     private final SourcePosition myPosition;
91
92     private Builder(@Nullable SourcePosition position) {
93       myPosition = position;
94     }
95
96     @Override
97     public void visitCodeFragment(JavaCodeFragment codeFragment) {
98       myVisitedFragments.add(codeFragment);
99       ArrayList<Evaluator> evaluators = new ArrayList<Evaluator>();
100
101       CodeFragmentEvaluator oldFragmentEvaluator = myCurrentFragmentEvaluator;
102       myCurrentFragmentEvaluator = new CodeFragmentEvaluator(oldFragmentEvaluator);
103
104       for (PsiElement child = codeFragment.getFirstChild(); child != null; child = child.getNextSibling()) {
105         child.accept(this);
106         if(myResult != null) {
107           evaluators.add(myResult);
108         }
109         myResult = null;
110       }
111
112       myCurrentFragmentEvaluator.setStatements(evaluators.toArray(new Evaluator[evaluators.size()]));
113       myResult = myCurrentFragmentEvaluator;
114
115       myCurrentFragmentEvaluator = oldFragmentEvaluator;
116     }
117
118     @Override
119     public void visitErrorElement(PsiErrorElement element) {
120       throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", element.getText()));
121     }
122
123     @Override
124     public void visitAssignmentExpression(PsiAssignmentExpression expression) {
125       final PsiExpression rExpression = expression.getRExpression();
126       if(rExpression == null) {
127         throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return;
128       }
129
130       rExpression.accept(this);
131       Evaluator rEvaluator = myResult;
132
133       if(expression.getOperationSign().getTokenType() != JavaTokenType.EQ) {
134         throwEvaluateException(DebuggerBundle.message("evaluation.error.operation.not.supported", expression.getOperationSign().getText()));
135       }
136
137       final PsiExpression lExpression = expression.getLExpression();
138
139       final PsiType lType = lExpression.getType();
140       if(lType == null) {
141         throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", lExpression.getText()));
142       }
143
144       if(!TypeConversionUtil.areTypesAssignmentCompatible(lType, rExpression)) {
145         throwEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", expression.getOperationSign().getText()));
146       }
147       lExpression.accept(this);
148       Evaluator lEvaluator = myResult;
149
150       rEvaluator = handleAssignmentBoxingAndPrimitiveTypeConversions(lType, rExpression.getType(), rEvaluator);
151       
152       myResult = new AssignmentEvaluator(lEvaluator, rEvaluator);
153     }
154
155     // returns rEvaluator possibly wrapped with boxing/unboxing and casting evaluators
156     private static Evaluator handleAssignmentBoxingAndPrimitiveTypeConversions(PsiType lType, PsiType rType, Evaluator rEvaluator) {
157       final PsiType unboxedLType = PsiPrimitiveType.getUnboxedType(lType);
158
159       if (unboxedLType != null) {
160         if (rType instanceof PsiPrimitiveType && !PsiPrimitiveType.NULL.equals(rType)) {
161           if (!rType.equals(unboxedLType)) {
162             rEvaluator = new TypeCastEvaluator(rEvaluator, unboxedLType.getCanonicalText(), true);
163           }
164           rEvaluator = new BoxingEvaluator(rEvaluator);
165         }
166       }
167       else {
168         // either primitive type or not unboxable type
169         if (lType instanceof PsiPrimitiveType) {
170           if (rType instanceof PsiClassType) {
171             rEvaluator = new UnBoxingEvaluator(rEvaluator);
172           }
173           final PsiPrimitiveType unboxedRType = PsiPrimitiveType.getUnboxedType(rType);
174           final PsiType _rType = unboxedRType != null? unboxedRType : rType;
175           if (_rType instanceof PsiPrimitiveType && !PsiPrimitiveType.NULL.equals(_rType)) {
176             if (!lType.equals(_rType)) {
177               rEvaluator = new TypeCastEvaluator(rEvaluator, lType.getCanonicalText(), true);
178             }
179           }
180         }
181       }
182       return rEvaluator;
183     }
184
185     @Override
186     public void visitStatement(PsiStatement statement) {
187       throwEvaluateException(DebuggerBundle.message("evaluation.error.statement.not.supported", statement.getText()));
188     }
189
190     @Override
191     public void visitBlockStatement(PsiBlockStatement statement) {
192       PsiStatement[] statements = statement.getCodeBlock().getStatements();
193       Evaluator [] evaluators = new Evaluator[statements.length];
194       for (int i = 0; i < statements.length; i++) {
195         PsiStatement psiStatement = statements[i];
196         psiStatement.accept(this);
197         evaluators[i] = myResult;
198         myResult = null;
199       }
200       myResult = new BlockStatementEvaluator(evaluators);
201     }
202
203     @Override
204     public void visitWhileStatement(PsiWhileStatement statement) {
205       PsiStatement body = statement.getBody();
206       if(body == null) return;
207       body.accept(this);
208       Evaluator bodyEvaluator = myResult;
209
210       PsiExpression condition = statement.getCondition();
211       if(condition == null) return;
212       condition.accept(this);
213       String label = null;
214       if(statement.getParent() instanceof PsiLabeledStatement) {
215         label = ((PsiLabeledStatement)statement.getParent()).getLabelIdentifier().getText();
216       }
217       myResult = new WhileStatementEvaluator(myResult, bodyEvaluator, label);
218     }
219
220     @Override
221     public void visitForStatement(PsiForStatement statement) {
222       PsiStatement initializer = statement.getInitialization();
223       Evaluator initializerEvaluator = null;
224       if(initializer != null){
225         initializer.accept(this);
226         initializerEvaluator = myResult;
227       }
228
229       PsiExpression condition = statement.getCondition();
230       Evaluator conditionEvaluator = null;
231       if(condition != null) {
232         condition.accept(this);
233         conditionEvaluator = myResult;
234       }
235
236       PsiStatement update = statement.getUpdate();
237       Evaluator updateEvaluator = null;
238       if(update != null){
239         update.accept(this);
240         updateEvaluator = myResult;
241       }
242
243       PsiStatement body = statement.getBody();
244       if(body == null) return;
245       body.accept(this);
246       Evaluator bodyEvaluator = myResult;
247
248       String label = null;
249       if(statement.getParent() instanceof PsiLabeledStatement) {
250         label = ((PsiLabeledStatement)statement.getParent()).getLabelIdentifier().getText();
251       }
252       myResult = new ForStatementEvaluator(initializerEvaluator, conditionEvaluator, updateEvaluator, bodyEvaluator, label);
253     }
254
255     @Override
256     public void visitIfStatement(PsiIfStatement statement) {
257       PsiStatement thenBranch = statement.getThenBranch();
258       if(thenBranch == null) return;
259       thenBranch.accept(this);
260       Evaluator thenEvaluator = myResult;
261
262       PsiStatement elseBranch = statement.getElseBranch();
263       Evaluator elseEvaluator = null;
264       if(elseBranch != null){
265         elseBranch.accept(this);
266         elseEvaluator = myResult;
267       }
268
269       PsiExpression condition = statement.getCondition();
270       if(condition == null) return;
271       condition.accept(this);
272
273       myResult = new IfStatementEvaluator(myResult, thenEvaluator, elseEvaluator);
274     }
275
276     @Override
277     public void visitBreakStatement(PsiBreakStatement statement) {
278       PsiIdentifier labelIdentifier = statement.getLabelIdentifier();
279       myResult = BreakContinueStatementEvaluator.createBreakEvaluator(labelIdentifier != null ? labelIdentifier.getText() : null);
280     }
281
282     @Override
283     public void visitContinueStatement(PsiContinueStatement statement) {
284       PsiIdentifier labelIdentifier = statement.getLabelIdentifier();
285       myResult = BreakContinueStatementEvaluator.createContinueEvaluator(labelIdentifier != null ? labelIdentifier.getText() : null);
286     }
287
288     @Override
289     public void visitExpressionStatement(PsiExpressionStatement statement) {
290       statement.getExpression().accept(this);
291     }
292
293     @Override
294     public void visitExpression(PsiExpression expression) {
295       if (LOG.isDebugEnabled()) {
296         LOG.debug("visitExpression " + expression);
297       }
298     }
299
300     @Override
301     public void visitBinaryExpression(PsiBinaryExpression expression) {
302       if (LOG.isDebugEnabled()) {
303         LOG.debug("visitBinaryExpression " + expression);
304       }
305       final PsiExpression lOperand = expression.getLOperand();
306       lOperand.accept(this);
307       Evaluator lResult = myResult;
308       final PsiExpression rOperand = expression.getROperand();
309       if(rOperand == null) {
310         throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return;
311       }
312       rOperand.accept(this);
313       Evaluator rResult = myResult;
314       IElementType opType = expression.getOperationSign().getTokenType();
315       PsiType expressionExpectedType = expression.getType();
316       if (expressionExpectedType == null) {
317         throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", expression.getText()));
318       }
319       myResult = createBinaryEvaluator(lResult, lOperand.getType(), rResult, rOperand.getType(), opType, expressionExpectedType);
320     }
321
322
323     // constructs binary evaluator handling unboxing and numeric promotion issues
324     private static BinaryExpressionEvaluator createBinaryEvaluator(
325       Evaluator lResult, final PsiType lType, Evaluator rResult, final PsiType rType, final IElementType operation, final PsiType expressionExpectedType) {
326       // handle unboxing if neccesary
327       if (isUnboxingInBinaryExpressionApplicable(lType, rType, operation)) {
328         if (rType instanceof PsiClassType && UnBoxingEvaluator.isTypeUnboxable(rType.getCanonicalText())) {
329           rResult = new UnBoxingEvaluator(rResult);
330         }
331         if (lType instanceof PsiClassType && UnBoxingEvaluator.isTypeUnboxable(lType.getCanonicalText())) {
332           lResult = new UnBoxingEvaluator(lResult);
333         }
334       }
335       if (isBinaryNumericPromotionApplicable(lType, rType, operation)) {
336         PsiType _lType = lType;
337         final PsiPrimitiveType unboxedLType = PsiPrimitiveType.getUnboxedType(lType);
338         if (unboxedLType != null) {
339           _lType = unboxedLType;
340         }
341
342         PsiType _rType = rType;
343         final PsiPrimitiveType unboxedRType = PsiPrimitiveType.getUnboxedType(rType);
344         if (unboxedRType != null) {
345           _rType = unboxedRType;
346         }
347
348         // handle numeric promotion
349         if (PsiType.DOUBLE.equals(_lType)) {
350           if (TypeConversionUtil.areTypesConvertible(_rType, PsiType.DOUBLE)) {
351             rResult = new TypeCastEvaluator(rResult, PsiType.DOUBLE.getCanonicalText(), true);
352           }
353         }
354         else if (PsiType.DOUBLE.equals(_rType)) {
355           if (TypeConversionUtil.areTypesConvertible(_lType, PsiType.DOUBLE)) {
356             lResult = new TypeCastEvaluator(lResult, PsiType.DOUBLE.getCanonicalText(), true);
357           }
358         }
359         else if (PsiType.FLOAT.equals(_lType)) {
360           if (TypeConversionUtil.areTypesConvertible(_rType, PsiType.FLOAT)) {
361             rResult = new TypeCastEvaluator(rResult, PsiType.FLOAT.getCanonicalText(), true);
362           }
363         }
364         else if (PsiType.FLOAT.equals(_rType)) {
365           if (TypeConversionUtil.areTypesConvertible(_lType, PsiType.FLOAT)) {
366             lResult = new TypeCastEvaluator(lResult, PsiType.FLOAT.getCanonicalText(), true);
367           }
368         }
369         else if (PsiType.LONG.equals(_lType)) {
370           if (TypeConversionUtil.areTypesConvertible(_rType, PsiType.LONG)) {
371             rResult = new TypeCastEvaluator(rResult, PsiType.LONG.getCanonicalText(), true);
372           }
373         }
374         else if (PsiType.LONG.equals(_rType)) {
375           if (TypeConversionUtil.areTypesConvertible(_lType, PsiType.LONG)) {
376             lResult = new TypeCastEvaluator(lResult, PsiType.LONG.getCanonicalText(), true);
377           }
378         }
379         else {
380           if (!PsiType.INT.equals(_lType) && TypeConversionUtil.areTypesConvertible(_lType, PsiType.INT)) {
381             lResult = new TypeCastEvaluator(lResult, PsiType.INT.getCanonicalText(), true);
382           }
383           if (!PsiType.INT.equals(_rType) && TypeConversionUtil.areTypesConvertible(_rType, PsiType.INT)) {
384             rResult = new TypeCastEvaluator(rResult, PsiType.INT.getCanonicalText(), true);
385           }
386         }
387       }
388
389       return new BinaryExpressionEvaluator(lResult, rResult, operation, expressionExpectedType.getCanonicalText());
390     }
391
392     private static boolean isBinaryNumericPromotionApplicable(PsiType lType, PsiType rType, IElementType opType) {
393       if (lType == null || rType == null) {
394         return false;
395       }
396       if (opType == JavaTokenType.EQEQ || opType == JavaTokenType.NE) {
397         if (PsiType.NULL.equals(lType) || PsiType.NULL.equals(rType)) {
398           return false;
399         }
400         if (lType instanceof PsiClassType && rType instanceof PsiClassType) {
401           return false;
402         }
403         if (lType instanceof PsiClassType) {
404           return PsiPrimitiveType.getUnboxedType(lType) != null; // should be unboxable
405         }
406         if (rType instanceof PsiClassType) {
407           return PsiPrimitiveType.getUnboxedType(rType) != null; // should be unboxable
408         }
409         return true;
410       }
411
412       return opType == JavaTokenType.ASTERISK ||
413           opType == JavaTokenType.DIV         ||
414           opType == JavaTokenType.PERC        ||
415           opType == JavaTokenType.PLUS        ||
416           opType == JavaTokenType.MINUS       ||
417           opType == JavaTokenType.LT          ||
418           opType == JavaTokenType.LE          ||
419           opType == JavaTokenType.GT          ||
420           opType == JavaTokenType.GE          ||
421           opType == JavaTokenType.AND         ||
422           opType == JavaTokenType.XOR         ||
423           opType == JavaTokenType.OR;
424
425     }
426
427     private static boolean isUnboxingInBinaryExpressionApplicable(PsiType lType, PsiType rType, IElementType opCode) {
428       if (PsiType.NULL.equals(lType) || PsiType.NULL.equals(rType)) {
429         return false;
430       }
431       // handle '==' and '!=' separately
432       if (opCode == JavaTokenType.EQEQ || opCode == JavaTokenType.NE) {
433         return lType instanceof PsiPrimitiveType && rType instanceof PsiClassType ||
434                lType instanceof PsiClassType     && rType instanceof PsiPrimitiveType;
435       }
436       // all other operations at least one should be of class type
437       return lType instanceof PsiClassType || rType instanceof PsiClassType;
438     }
439
440     /**
441      * @param type
442      * @return promotion type to cast to or null if no casting needed
443      */
444     @Nullable
445     private static PsiType calcUnaryNumericPromotionType(PsiPrimitiveType type) {
446       if (PsiType.BYTE.equals(type) || PsiType.SHORT.equals(type) || PsiType.CHAR.equals(type) || PsiType.INT.equals(type)) {
447         return PsiType.INT;
448       }
449       return null;
450     }
451
452     @Override
453     public void visitDeclarationStatement(PsiDeclarationStatement statement) {
454       List<Evaluator> evaluators = new ArrayList<Evaluator>();
455
456       PsiElement[] declaredElements = statement.getDeclaredElements();
457       for (PsiElement declaredElement : declaredElements) {
458         if (declaredElement instanceof PsiLocalVariable) {
459           if (myCurrentFragmentEvaluator != null) {
460             final PsiLocalVariable localVariable = (PsiLocalVariable)declaredElement;
461
462             final PsiType lType = localVariable.getType();
463
464             PsiElementFactory elementFactory = JavaPsiFacade.getInstance(localVariable.getProject()).getElementFactory();
465             try {
466               PsiExpression initialValue = elementFactory.createExpressionFromText(PsiTypesUtil.getDefaultValueOfType(lType), null);
467               Object value = JavaConstantExpressionEvaluator.computeConstantExpression(initialValue, true);
468               myCurrentFragmentEvaluator.setInitialValue(localVariable.getName(), value);
469             }
470             catch (IncorrectOperationException e) {
471               LOG.error(e);
472             }
473             catch (EvaluateException e) {
474               throw new EvaluateRuntimeException(e);
475             }
476
477             PsiExpression initializer = localVariable.getInitializer();
478             if (initializer != null) {
479               try {
480                 if (!TypeConversionUtil.areTypesAssignmentCompatible(lType, initializer)) {
481                   throwEvaluateException(
482                     DebuggerBundle.message("evaluation.error.incompatible.variable.initializer.type", localVariable.getName()));
483                 }
484                 final PsiType rType = initializer.getType();
485                 initializer.accept(this);
486                 Evaluator rEvaluator = myResult;
487
488                 PsiExpression localVarReference = elementFactory.createExpressionFromText(localVariable.getName(), initializer);
489
490                 localVarReference.accept(this);
491                 Evaluator lEvaluator = myResult;
492                 rEvaluator = handleAssignmentBoxingAndPrimitiveTypeConversions(localVarReference.getType(), rType, rEvaluator);
493
494                 Evaluator assignment = new AssignmentEvaluator(lEvaluator, rEvaluator);
495                 evaluators.add(assignment);
496               }
497               catch (IncorrectOperationException e) {
498                 LOG.error(e);
499               }
500             }
501           }
502           else {
503             throw new EvaluateRuntimeException(new EvaluateException(
504               DebuggerBundle.message("evaluation.error.local.variable.declarations.not.supported"), null));
505           }
506         }
507         else {
508           throw new EvaluateRuntimeException(new EvaluateException(
509             DebuggerBundle.message("evaluation.error.unsupported.declaration", declaredElement.getText()), null));
510         }
511       }
512
513       if(!evaluators.isEmpty()) {
514         CodeFragmentEvaluator codeFragmentEvaluator = new CodeFragmentEvaluator(myCurrentFragmentEvaluator);
515         codeFragmentEvaluator.setStatements(evaluators.toArray(new Evaluator[evaluators.size()]));
516         myResult = codeFragmentEvaluator;
517       } else {
518         myResult = null;
519       }
520     }
521
522     @Override
523     public void visitConditionalExpression(PsiConditionalExpression expression) {
524       if (LOG.isDebugEnabled()) {
525         LOG.debug("visitConditionalExpression " + expression);
526       }
527       final PsiExpression thenExpression = expression.getThenExpression();
528       final PsiExpression elseExpression = expression.getElseExpression();
529       if (thenExpression == null || elseExpression == null){
530         throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return;
531       }
532       PsiExpression condition = expression.getCondition();
533       condition.accept(this);
534       if (myResult == null) {
535         throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", condition.getText())); return;
536       }
537       Evaluator conditionEvaluator = myResult;
538       thenExpression.accept(this);
539       if (myResult == null) {
540         throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", thenExpression.getText())); return;
541       }
542       Evaluator thenEvaluator = myResult;
543       elseExpression.accept(this);
544       if (myResult == null) {
545         throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", elseExpression.getText())); return;
546       }
547       Evaluator elseEvaluator = myResult;
548       myResult = new ConditionalExpressionEvaluator(conditionEvaluator, thenEvaluator, elseEvaluator);
549     }
550
551     @Override
552     public void visitReferenceExpression(PsiReferenceExpression expression) {
553       if (LOG.isDebugEnabled()) {
554         LOG.debug("visitReferenceExpression " + expression);
555       }
556       PsiExpression qualifier = expression.getQualifierExpression();
557       JavaResolveResult resolveResult = expression.advancedResolve(true);
558       PsiElement element = resolveResult.getElement();
559
560       if (element instanceof PsiLocalVariable || element instanceof PsiParameter) {
561         final Value labeledValue = element.getUserData(CodeFragmentFactoryContextWrapper.LABEL_VARIABLE_VALUE_KEY);
562         if (labeledValue != null) {
563           myResult = new IdentityEvaluator(labeledValue);
564           return;
565         }
566         //synthetic variable
567         final PsiFile containingFile = element.getContainingFile();
568         if(containingFile instanceof PsiCodeFragment && myCurrentFragmentEvaluator != null && myVisitedFragments.contains(containingFile)) {
569           // psiVariable may live in PsiCodeFragment not only in debugger editors, for example Fabrique has such variables.
570           // So treat it as synthetic var only when this code fragment is located in DebuggerEditor,
571           // that's why we need to check that containing code fragment is the one we visited
572           myResult = new SyntheticVariableEvaluator(myCurrentFragmentEvaluator, ((PsiVariable)element).getName());
573           return;
574         }
575         // local variable
576         final PsiVariable psiVar = (PsiVariable)element;
577         final String localName = psiVar.getName();
578         PsiClass variableClass = getContainingClass(psiVar);
579         if (getContextPsiClass() == null || getContextPsiClass().equals(variableClass)) {
580           final LocalVariableEvaluator localVarEvaluator = new LocalVariableEvaluator(localName, ContextUtil.isJspImplicit(element));
581           if (psiVar instanceof PsiParameter) {
582             final PsiParameter param = (PsiParameter)psiVar;
583             final PsiParameterList paramList = PsiTreeUtil.getParentOfType(param, PsiParameterList.class, true);
584             if (paramList != null) {
585               localVarEvaluator.setParameterIndex(paramList.getParameterIndex(param));
586             }
587           }
588           myResult = localVarEvaluator;
589           return;
590         }
591         // the expression references final var outside the context's class (in some of the outer classes)
592         int iterationCount = 0;
593         PsiClass aClass = getOuterClass(getContextPsiClass());
594         while (aClass != null && !aClass.equals(variableClass)) {
595           iterationCount++;
596           aClass = getOuterClass(aClass);
597         }
598         if (aClass != null) {
599           PsiExpression initializer = psiVar.getInitializer();
600           if(initializer != null) {
601             Object value = JavaPsiFacade.getInstance(psiVar.getProject()).getConstantEvaluationHelper().computeConstantExpression(initializer);
602             if(value != null) {
603               PsiType type = resolveResult.getSubstitutor().substitute(psiVar.getType());
604               myResult = new LiteralEvaluator(value, type.getCanonicalText());
605               return;
606             }
607           }
608           Evaluator objectEvaluator = new ThisEvaluator(iterationCount);
609           //noinspection HardCodedStringLiteral
610           final PsiClass classAt = myPosition != null? JVMNameUtil.getClassAt(myPosition) : null;
611           FieldEvaluator.TargetClassFilter filter = FieldEvaluator.createClassFilter(classAt != null? classAt : getContextPsiClass());
612           myResult = new FieldEvaluator(objectEvaluator, filter, "val$" + localName);
613           return;
614         }
615         throwEvaluateException(DebuggerBundle.message("evaluation.error.local.variable.missing.from.class.closure", localName));
616       }
617       else if (element instanceof PsiField) {
618         final PsiField psiField = (PsiField)element;
619         final PsiClass fieldClass = psiField.getContainingClass();
620         if(fieldClass == null) {
621           throwEvaluateException(DebuggerBundle.message("evaluation.error.cannot.resolve.field.class", psiField.getName())); return;
622         }
623         Evaluator objectEvaluator;
624         if (psiField.hasModifierProperty(PsiModifier.STATIC)) {
625           objectEvaluator = new TypeEvaluator(JVMNameUtil.getContextClassJVMQualifiedName(SourcePosition.createFromElement(psiField)));
626         }
627         else if(qualifier != null) {
628           qualifier.accept(this);
629           objectEvaluator = myResult;
630         }
631         else if (fieldClass.equals(getContextPsiClass()) || getContextPsiClass().isInheritor(fieldClass, true)) {
632             objectEvaluator = new ThisEvaluator();
633         }
634         else {  // myContextPsiClass != fieldClass && myContextPsiClass is not a subclass of fieldClass
635           int iterationCount = 0;
636           PsiClass aClass = getContextPsiClass();
637           while (aClass != null && !(aClass.equals(fieldClass) || aClass.isInheritor(fieldClass, true))) {
638             iterationCount++;
639             aClass = getOuterClass(aClass);
640           }
641           if (aClass == null) {
642             throwEvaluateException(DebuggerBundle.message("evaluation.error.cannot.sources.for.field.class", psiField.getName()));
643           }
644           objectEvaluator = new ThisEvaluator(iterationCount);
645         }
646         myResult = new FieldEvaluator(objectEvaluator, FieldEvaluator.createClassFilter(fieldClass), psiField.getName());
647       }
648       else {
649         //let's guess what this could be
650         PsiElement nameElement = expression.getReferenceNameElement(); // get "b" part
651         String name;
652         if (nameElement instanceof PsiIdentifier) {
653           name = nameElement.getText();
654         }
655         else {
656           //noinspection HardCodedStringLiteral
657           final String elementDisplayString = nameElement != null ? nameElement.getText() : "(null)";
658           throwEvaluateException(DebuggerBundle.message("evaluation.error.identifier.expected", elementDisplayString));
659           return;
660         }
661
662         if(qualifier != null) {
663           final PsiElement qualifierTarget = qualifier instanceof PsiReferenceExpression
664                                              ? ((PsiReferenceExpression)qualifier).resolve() : null;
665           if (qualifierTarget instanceof PsiClass) {
666             // this is a call to a 'static' field
667             PsiClass psiClass = (PsiClass)qualifierTarget;
668             final JVMName typeName = JVMNameUtil.getJVMQualifiedName(psiClass);
669             myResult = new FieldEvaluator(new TypeEvaluator(typeName), FieldEvaluator.createClassFilter(psiClass), name);
670           }
671           else {
672             PsiType type = qualifier.getType();
673             if(type == null) {
674               throwEvaluateException(DebuggerBundle.message("evaluation.error.qualifier.type.unknown", qualifier.getText()));
675             }
676
677             qualifier.accept(this);
678             if (myResult == null) {
679               throwEvaluateException(DebuggerBundle.message("evaluation.error.cannot.evaluate.qualifier", qualifier.getText()));
680             }
681
682             myResult = new FieldEvaluator(myResult, FieldEvaluator.createClassFilter(type), name);
683           }
684         }
685         else {
686           myResult = new LocalVariableEvaluator(name, false);
687         }
688       }
689     }
690
691     private static void throwEvaluateException(String message) throws EvaluateRuntimeException {
692       //noinspection ThrowableResultOfMethodCallIgnored
693       throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(message));
694     }
695
696     @Override
697     public void visitSuperExpression(PsiSuperExpression expression) {
698       if (LOG.isDebugEnabled()) {
699         LOG.debug("visitSuperExpression " + expression);
700       }
701       final int iterationCount = calcIterationCount(expression.getQualifier());
702       myResult = new SuperEvaluator(iterationCount);
703     }
704
705     @Override
706     public void visitThisExpression(PsiThisExpression expression) {
707       if (LOG.isDebugEnabled()) {
708         LOG.debug("visitThisExpression " + expression);
709       }
710       final int iterationCount = calcIterationCount(expression.getQualifier());
711       myResult = new ThisEvaluator(iterationCount);
712     }
713
714     private int calcIterationCount(final PsiJavaCodeReferenceElement qualifier) {
715       int iterationCount = 0;
716       if (qualifier != null) {
717         PsiElement targetClass = qualifier.resolve();
718         if (targetClass == null || getContextPsiClass() == null) {
719           throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", qualifier.getText()));
720         }
721         try {
722           PsiClass aClass = getContextPsiClass();
723           while (aClass != null && !aClass.equals(targetClass)) {
724             iterationCount++;
725             aClass = getOuterClass(aClass);
726           }
727         }
728         catch (Exception e) {
729           //noinspection ThrowableResultOfMethodCallIgnored
730           throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(e));
731         }
732       }
733       return iterationCount;
734     }
735
736     @Override
737     public void visitInstanceOfExpression(PsiInstanceOfExpression expression) {
738       if (LOG.isDebugEnabled()) {
739         LOG.debug("visitInstanceOfExpression " + expression);
740       }
741       PsiTypeElement checkType = expression.getCheckType();
742       if(checkType == null) {
743         throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText()));
744         return;
745       }
746       PsiType type = checkType.getType();
747       expression.getOperand().accept(this);
748 //    ClassObjectEvaluator typeEvaluator = new ClassObjectEvaluator(type.getCanonicalText());
749       Evaluator operandEvaluator = myResult;
750       myResult = new InstanceofEvaluator(operandEvaluator, new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(type)));
751     }
752
753     @Override
754     public void visitParenthesizedExpression(PsiParenthesizedExpression expression) {
755       if (LOG.isDebugEnabled()) {
756         LOG.debug("visitParenthesizedExpression " + expression);
757       }
758       PsiExpression expr = expression.getExpression();
759       if (expr != null){
760         expr.accept(this);
761       }
762     }
763
764     @Override
765     public void visitPostfixExpression(PsiPostfixExpression expression) {
766       if(expression.getType() == null) {
767         throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", expression.getText()));
768       }
769
770       final PsiExpression operandExpression = expression.getOperand();
771       operandExpression.accept(this);
772
773       final Evaluator operandEvaluator = myResult;
774
775       final IElementType operation = expression.getOperationSign().getTokenType();
776       final PsiType operandType = operandExpression.getType();
777       @Nullable final PsiType unboxedOperandType = PsiPrimitiveType.getUnboxedType(operandType);
778
779       Evaluator incrementImpl = createBinaryEvaluator(
780         operandEvaluator, operandType,
781         new LiteralEvaluator(Integer.valueOf(1), "int"), PsiType.INT,
782         operation == JavaTokenType.PLUSPLUS ? JavaTokenType.PLUS : JavaTokenType.MINUS,
783         unboxedOperandType!= null? unboxedOperandType : operandType
784       );
785       if (unboxedOperandType != null) {
786         incrementImpl = new BoxingEvaluator(incrementImpl);
787       }
788       myResult = new PostfixOperationEvaluator(operandEvaluator, incrementImpl);
789     }
790
791     @Override
792     public void visitPrefixExpression(final PsiPrefixExpression expression) {
793       final PsiType expressionType = expression.getType();
794       if(expressionType == null) {
795         throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", expression.getText()));
796       }
797
798       final PsiExpression operandExpression = expression.getOperand();
799       if (operandExpression == null) {
800         throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.operand", expression.getText()));
801       }
802       
803       operandExpression.accept(this);
804       Evaluator operandEvaluator = myResult;
805
806       // handle unboxing issues
807       final PsiType operandType = operandExpression.getType();
808       @Nullable
809       final PsiType unboxedOperandType = PsiPrimitiveType.getUnboxedType(operandType);
810
811       final IElementType operation = expression.getOperationSign().getTokenType();
812
813       if(operation == JavaTokenType.PLUSPLUS || operation == JavaTokenType.MINUSMINUS) {
814         try {
815           final BinaryExpressionEvaluator rightEval = createBinaryEvaluator(
816             operandEvaluator, operandType,
817             new LiteralEvaluator(Integer.valueOf(1), "int"), PsiType.INT,
818             operation == JavaTokenType.PLUSPLUS ? JavaTokenType.PLUS : JavaTokenType.MINUS,
819             unboxedOperandType!= null? unboxedOperandType : operandType
820           );
821           myResult = new AssignmentEvaluator(operandEvaluator, unboxedOperandType != null? new BoxingEvaluator(rightEval) : rightEval);
822         }
823         catch (IncorrectOperationException e) {
824           LOG.error(e);
825         }
826       }
827       else {
828         if (JavaTokenType.PLUS.equals(operation) || JavaTokenType.MINUS.equals(operation)|| JavaTokenType.TILDE.equals(operation)) {
829           operandEvaluator = handleUnaryNumericPromotion(operandType, operandEvaluator);
830         }
831         else {
832           if (unboxedOperandType != null) {
833             operandEvaluator = new UnBoxingEvaluator(operandEvaluator);
834           }
835         }
836         myResult = new UnaryExpressionEvaluator(operation, expressionType.getCanonicalText(), operandEvaluator, expression.getOperationSign().getText());
837       }
838     }
839
840     @Override
841     public void visitMethodCallExpression(PsiMethodCallExpression expression) {
842       if (LOG.isDebugEnabled()) {
843         LOG.debug("visitMethodCallExpression " + expression);
844       }
845       final PsiExpressionList argumentList = expression.getArgumentList();
846       final PsiExpression[] argExpressions = argumentList.getExpressions();
847       List<Evaluator> argumentEvaluators = new ArrayList<Evaluator>(argExpressions.length);
848       // evaluate arguments
849       for (PsiExpression psiExpression : argExpressions) {
850         psiExpression.accept(this);
851         if (myResult == null) {
852           // cannot build evaluator
853           throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", psiExpression.getText()));
854         }
855         argumentEvaluators.add(myResult);
856       }
857       PsiReferenceExpression methodExpr = expression.getMethodExpression();
858
859       final JavaResolveResult resolveResult = methodExpr.advancedResolve(false);
860       final PsiMethod psiMethod = (PsiMethod)resolveResult.getElement();
861
862       PsiExpression qualifier = methodExpr.getQualifierExpression();
863       Evaluator objectEvaluator;
864       JVMName contextClass = null;
865
866       if(psiMethod != null) {
867         PsiClass methodPsiClass = psiMethod.getContainingClass();
868         contextClass =  JVMNameUtil.getJVMQualifiedName(methodPsiClass);
869         if (psiMethod.hasModifierProperty(PsiModifier.STATIC)) {
870           objectEvaluator = new TypeEvaluator(contextClass);
871         }
872         else if (qualifier != null ) {
873           qualifier.accept(this);
874           objectEvaluator = myResult;
875         }
876         else {
877           int iterationCount = 0;
878           final PsiElement currentFileResolveScope = resolveResult.getCurrentFileResolveScope();
879           if (currentFileResolveScope instanceof PsiClass) {
880             PsiClass aClass = getContextPsiClass();
881             while(aClass != null && !aClass.equals(currentFileResolveScope)) {
882               aClass = getOuterClass(aClass);
883               iterationCount++;
884             }
885           }
886           objectEvaluator = new ThisEvaluator(iterationCount);
887         }
888       }
889       else {
890         //trying to guess
891         if (qualifier != null) {
892           PsiType type = qualifier.getType();
893
894           if (type != null) {
895             contextClass = JVMNameUtil.getJVMQualifiedName(type);
896           }
897
898           if (qualifier instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifier).resolve() instanceof PsiClass) {
899             // this is a call to a 'static' method
900             if (contextClass == null && type == null) {
901               throwEvaluateException(DebuggerBundle.message("evaluation.error.qualifier.type.unknown", qualifier.getText()));
902             }
903             assert contextClass != null;
904             objectEvaluator = new TypeEvaluator(contextClass);
905           }
906           else {
907             qualifier.accept(this);
908             objectEvaluator = myResult;
909           }
910         }
911         else {
912           objectEvaluator = new ThisEvaluator();
913           contextClass = JVMNameUtil.getContextClassJVMQualifiedName(myPosition);
914           if(contextClass == null && myContextPsiClass != null) {
915             contextClass = JVMNameUtil.getJVMQualifiedName(myContextPsiClass);
916           }
917           //else {
918           //  throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(
919           //    DebuggerBundle.message("evaluation.error.method.not.found", methodExpr.getReferenceName()))
920           //  );
921           //}
922         }
923       }
924
925       if (objectEvaluator == null) {
926         throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText()));
927       }
928
929       if (psiMethod != null && !psiMethod.isConstructor()) {
930         if (psiMethod.getReturnType() == null) {
931           throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.method.return.type", psiMethod.getText()));
932         }
933       }
934
935       if (psiMethod != null) {
936         // handle autoboxing
937         final PsiParameter[] declaredParams = psiMethod.getParameterList().getParameters();
938         for (int i = 0, parametersLength = declaredParams.length; i < parametersLength; i++) {
939           if (i >= argExpressions.length) {
940             break; // actual arguments count is less than number of declared params 
941           }
942           final PsiType declaredParamType = declaredParams[i].getType();
943           PsiType substituted = resolveResult.getSubstitutor().substitute(declaredParamType);
944           final PsiType actualArgType = argExpressions[i].getType();
945           if (TypeConversionUtil.boxingConversionApplicable(substituted, actualArgType)) {
946             final Evaluator argEval = argumentEvaluators.get(i);
947             argumentEvaluators.set(i, substituted instanceof PsiPrimitiveType
948                                       ? new UnBoxingEvaluator(argEval) : new BoxingEvaluator(argEval));
949           }
950         }
951       }
952
953       myResult = new MethodEvaluator(objectEvaluator, contextClass, methodExpr.getReferenceName(), psiMethod != null ? JVMNameUtil.getJVMSignature(psiMethod) : null, argumentEvaluators);
954     }
955
956     @Override
957     public void visitLiteralExpression(PsiLiteralExpression expression) {
958       Object value = expression.getValue();
959       if(expression.getParsingError() != null) {
960         throwEvaluateException(expression.getParsingError());
961       }
962       myResult = new LiteralEvaluator(value, expression.getType().getCanonicalText());
963     }
964
965     @Override
966     public void visitArrayAccessExpression(PsiArrayAccessExpression expression) {
967       final PsiExpression indexExpression = expression.getIndexExpression();
968       if(indexExpression == null) {
969         throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return;
970       }
971       indexExpression.accept(this);
972       final Evaluator indexEvaluator = handleUnaryNumericPromotion(indexExpression.getType(), myResult); 
973
974       expression.getArrayExpression().accept(this);
975       Evaluator arrayEvaluator = myResult;
976       myResult = new ArrayAccessEvaluator(arrayEvaluator, indexEvaluator);
977     }
978
979
980     /**
981      * Handles unboxing and numeric promotion issues for
982      * - array diumention expressions
983      * - array index expression
984      * - unary +, -, and ~ operations
985      * @param operandExpressionType
986      * @param operandEvaluator  @return operandEvaluator possibly 'wrapped' with neccesary unboxing and type-casting evaluators to make returning value
987      * sutable for mentioned contexts            
988      */
989     private static Evaluator handleUnaryNumericPromotion(final PsiType operandExpressionType, Evaluator operandEvaluator) {
990       final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(operandExpressionType);
991       if (unboxedType != null && !PsiType.BOOLEAN.equals(unboxedType)) {
992         operandEvaluator = new UnBoxingEvaluator(operandEvaluator);
993       }
994
995       // handle numeric promotion
996       final PsiType _unboxedIndexType = unboxedType != null? unboxedType : operandExpressionType;
997       if (_unboxedIndexType instanceof PsiPrimitiveType) {
998         final PsiType promotionType = calcUnaryNumericPromotionType((PsiPrimitiveType)_unboxedIndexType);
999         if (promotionType != null) {
1000           operandEvaluator = new TypeCastEvaluator(operandEvaluator, promotionType.getCanonicalText(), true);
1001         }
1002       }
1003       return operandEvaluator;
1004     }
1005
1006     @SuppressWarnings({"ConstantConditions"})
1007     @Override
1008     public void visitTypeCastExpression(PsiTypeCastExpression expression) {
1009       final PsiExpression operandExpr = expression.getOperand();
1010       operandExpr.accept(this);
1011       Evaluator operandEvaluator = myResult;
1012       final PsiType castType = expression.getCastType().getType();
1013       final PsiType operandType = operandExpr.getType();
1014
1015       if (castType != null && operandType != null && !TypeConversionUtil.areTypesConvertible(operandType, castType)) {
1016         throw new EvaluateRuntimeException(
1017           new EvaluateException(JavaErrorMessages.message("inconvertible.type.cast", HighlightUtil.formatType(operandType), HighlightUtil.formatType(castType)))
1018         );
1019       }
1020
1021       final boolean shouldPerformBoxingConversion = castType != null && operandType != null && TypeConversionUtil.boxingConversionApplicable(castType, operandType);
1022       final boolean castingToPrimitive = castType instanceof PsiPrimitiveType;
1023       if (shouldPerformBoxingConversion && castingToPrimitive) {
1024         operandEvaluator = new UnBoxingEvaluator(operandEvaluator);
1025       }
1026
1027       final boolean performCastToWrapperClass = shouldPerformBoxingConversion && !castingToPrimitive;
1028
1029       String castTypeName = castType.getCanonicalText();
1030       if (performCastToWrapperClass) {
1031         final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(castType);
1032         if (unboxedType != null) {
1033           castTypeName = unboxedType.getCanonicalText();
1034         }
1035       }
1036
1037       myResult = new TypeCastEvaluator(operandEvaluator, castTypeName, castingToPrimitive);
1038       
1039       if (performCastToWrapperClass) {
1040         myResult = new BoxingEvaluator(myResult);
1041       }
1042     }
1043
1044     @Override
1045     public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) {
1046       PsiType type = expression.getOperand().getType();
1047
1048       if (type instanceof PsiPrimitiveType) {
1049         final JVMName typeName = JVMNameUtil.getJVMRawText(((PsiPrimitiveType)type).getBoxedTypeName());
1050         myResult = new FieldEvaluator(new TypeEvaluator(typeName), FieldEvaluator.TargetClassFilter.ALL, "TYPE");
1051       }
1052       else {
1053         myResult = new ClassObjectEvaluator(new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(type)));
1054       }
1055     }
1056
1057     @Override
1058     public void visitNewExpression(PsiNewExpression expression) {
1059       PsiType expressionPsiType = expression.getType();
1060       if (expressionPsiType instanceof PsiArrayType) {
1061         Evaluator dimensionEvaluator = null;
1062         PsiExpression[] dimensions = expression.getArrayDimensions();
1063         if (dimensions.length == 1){
1064           PsiExpression dimensionExpression = dimensions[0];
1065           dimensionExpression.accept(this);
1066           if (myResult != null) {
1067             dimensionEvaluator = handleUnaryNumericPromotion(dimensionExpression.getType(), myResult);
1068           }
1069           else {
1070             throwEvaluateException(
1071               DebuggerBundle.message("evaluation.error.invalid.array.dimension.expression", dimensionExpression.getText()));
1072           }
1073         }
1074         else if (dimensions.length > 1){
1075           throwEvaluateException(DebuggerBundle.message("evaluation.error.multi.dimensional.arrays.creation.not.supported"));
1076         }
1077
1078         Evaluator initializerEvaluator = null;
1079         PsiArrayInitializerExpression arrayInitializer = expression.getArrayInitializer();
1080         if (arrayInitializer != null) {
1081           if (dimensionEvaluator != null) { // initializer already exists
1082             throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText()));
1083           }
1084           arrayInitializer.accept(this);
1085           if (myResult != null) {
1086             initializerEvaluator = handleUnaryNumericPromotion(arrayInitializer.getType(), myResult);
1087           }
1088           else {
1089             throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", arrayInitializer.getText()));
1090           }
1091           /*
1092           PsiExpression[] initializers = arrayInitializer.getInitializers();
1093           initializerEvaluators = new Evaluator[initializers.length];
1094           for (int idx = 0; idx < initializers.length; idx++) {
1095             PsiExpression initializer = initializers[idx];
1096             initializer.accept(this);
1097             if (myResult instanceof Evaluator) {
1098               initializerEvaluators[idx] = myResult;
1099             }
1100             else {
1101               throw new EvaluateException("Invalid expression for array initializer: " + initializer.getText(), true);
1102             }
1103           }
1104           */
1105         }
1106         if (dimensionEvaluator == null && initializerEvaluator == null) {
1107           throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText()));
1108         }
1109         myResult = new NewArrayInstanceEvaluator(
1110           new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(expressionPsiType)),
1111           dimensionEvaluator,
1112           initializerEvaluator
1113         );
1114       }
1115       else { // must be a class ref
1116         LOG.assertTrue(expressionPsiType instanceof PsiClassType);
1117         PsiClass aClass = ((PsiClassType)expressionPsiType).resolve();
1118         if(aClass instanceof PsiAnonymousClass) {
1119           throwEvaluateException(DebuggerBundle.message("evaluation.error.anonymous.class.evaluation.not.supported"));
1120         }
1121         PsiExpressionList argumentList = expression.getArgumentList();
1122         if (argumentList == null) {
1123           throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return;
1124         }
1125         PsiExpression[] argExpressions = argumentList.getExpressions();
1126         PsiMethod constructor = expression.resolveConstructor();
1127         if (constructor == null && argExpressions.length > 0) {
1128           throw new EvaluateRuntimeException(new EvaluateException(
1129             DebuggerBundle.message("evaluation.error.cannot.resolve.constructor", expression.getText()), null));
1130         }
1131         Evaluator[] argumentEvaluators = new Evaluator[argExpressions.length];
1132         // evaluate arguments
1133         for (int idx = 0; idx < argExpressions.length; idx++) {
1134           PsiExpression argExpression = argExpressions[idx];
1135           argExpression.accept(this);
1136           if (myResult != null) {
1137             argumentEvaluators[idx] = myResult;
1138           }
1139           else {
1140             throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", argExpression.getText()));
1141           }
1142         }
1143         //noinspection HardCodedStringLiteral
1144         JVMName signature = constructor != null ? JVMNameUtil.getJVMSignature(constructor) : JVMNameUtil.getJVMRawText("()V");
1145         myResult = new NewClassInstanceEvaluator(
1146           new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(expressionPsiType)),
1147           signature,
1148           argumentEvaluators
1149         );
1150       }
1151     }
1152
1153     @Override
1154     public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) {
1155       PsiExpression[] initializers = expression.getInitializers();
1156       Evaluator[] evaluators = new Evaluator[initializers.length];
1157       for (int idx = 0; idx < initializers.length; idx++) {
1158         PsiExpression initializer = initializers[idx];
1159         initializer.accept(this);
1160         if (myResult != null) {
1161           evaluators[idx] = handleUnaryNumericPromotion(initializer.getType(), myResult);
1162         }
1163         else {
1164           throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", initializer.getText()));
1165         }
1166       }
1167       myResult = new ArrayInitializerEvaluator(evaluators);
1168     }
1169
1170     private static PsiClass getOuterClass(PsiClass aClass) {
1171       if(aClass == null) return null;
1172       return PsiTreeUtil.getContextOfType(aClass, PsiClass.class, true);
1173     }
1174
1175     private PsiClass getContainingClass(PsiVariable variable) {
1176       PsiElement element = PsiTreeUtil.getParentOfType(variable.getParent(), PsiClass.class, false);
1177       return element == null ? getContextPsiClass() : (PsiClass)element;
1178     }
1179
1180     public PsiClass getContextPsiClass() {
1181       return myContextPsiClass;
1182     }
1183
1184     protected ExpressionEvaluator buildElement(final PsiElement element) throws EvaluateException {
1185       LOG.assertTrue(element.isValid());
1186
1187       myContextPsiClass = PsiTreeUtil.getContextOfType(element, PsiClass.class, false);
1188       try {
1189         element.accept(this);
1190       }
1191       catch (EvaluateRuntimeException e) {
1192         throw e.getCause();
1193       }
1194       if (myResult == null) {
1195         throw EvaluateExceptionUtil
1196           .createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", element.toString()));
1197       }
1198       return new ExpressionEvaluatorImpl(myResult);
1199     }
1200   }
1201 }