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