2 * Copyright 2000-2015 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 * Class EvaluatorBuilderImpl
21 package com.intellij.debugger.engine.evaluation.expression;
23 import com.intellij.codeInsight.daemon.JavaErrorMessages;
24 import com.intellij.codeInsight.daemon.impl.HighlightInfo;
25 import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil;
26 import com.intellij.codeInsight.daemon.impl.analysis.JavaHighlightUtil;
27 import com.intellij.debugger.DebuggerBundle;
28 import com.intellij.debugger.SourcePosition;
29 import com.intellij.debugger.engine.ContextUtil;
30 import com.intellij.debugger.engine.DebuggerUtils;
31 import com.intellij.debugger.engine.JVMName;
32 import com.intellij.debugger.engine.JVMNameUtil;
33 import com.intellij.debugger.engine.evaluation.*;
34 import com.intellij.debugger.impl.DebuggerUtilsEx;
35 import com.intellij.openapi.diagnostic.Logger;
36 import com.intellij.openapi.project.Project;
37 import com.intellij.psi.*;
38 import com.intellij.psi.impl.JavaConstantExpressionEvaluator;
39 import com.intellij.psi.search.GlobalSearchScope;
40 import com.intellij.psi.tree.IElementType;
41 import com.intellij.psi.util.PsiTreeUtil;
42 import com.intellij.psi.util.PsiTypesUtil;
43 import com.intellij.psi.util.PsiUtil;
44 import com.intellij.psi.util.TypeConversionUtil;
45 import com.intellij.util.IncorrectOperationException;
46 import com.sun.jdi.Value;
47 import org.jetbrains.annotations.NotNull;
48 import org.jetbrains.annotations.Nullable;
52 public class EvaluatorBuilderImpl implements EvaluatorBuilder {
53 private static final EvaluatorBuilderImpl ourInstance = new EvaluatorBuilderImpl();
55 private EvaluatorBuilderImpl() {
58 public static EvaluatorBuilder getInstance() {
62 public static ExpressionEvaluator build(final TextWithImports text, @Nullable PsiElement contextElement, final SourcePosition position) throws EvaluateException {
63 if (contextElement == null) {
64 throw EvaluateExceptionUtil.CANNOT_FIND_SOURCE_CLASS;
67 final Project project = contextElement.getProject();
69 CodeFragmentFactory factory = DebuggerUtilsEx.findAppropriateCodeFragmentFactory(text, contextElement);
70 PsiCodeFragment codeFragment = factory.createCodeFragment(text, contextElement, project);
71 if (codeFragment == null) {
72 throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", text.getText()));
74 codeFragment.forceResolveScope(GlobalSearchScope.allScope(project));
75 DebuggerUtils.checkSyntax(codeFragment);
77 return factory.getEvaluatorBuilder().build(codeFragment, position);
81 public ExpressionEvaluator build(final PsiElement codeFragment, final SourcePosition position) throws EvaluateException {
82 return new Builder(position).buildElement(codeFragment);
85 private static class Builder extends JavaElementVisitor {
86 private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl");
87 private Evaluator myResult = null;
88 private PsiClass myContextPsiClass;
89 private CodeFragmentEvaluator myCurrentFragmentEvaluator;
90 private final Set<JavaCodeFragment> myVisitedFragments = new HashSet<JavaCodeFragment>();
92 private final SourcePosition myPosition;
94 private Builder(@Nullable SourcePosition position) {
95 myPosition = position;
99 public void visitCodeFragment(JavaCodeFragment codeFragment) {
100 myVisitedFragments.add(codeFragment);
101 ArrayList<Evaluator> evaluators = new ArrayList<Evaluator>();
103 CodeFragmentEvaluator oldFragmentEvaluator = myCurrentFragmentEvaluator;
104 myCurrentFragmentEvaluator = new CodeFragmentEvaluator(oldFragmentEvaluator);
106 for (PsiElement child = codeFragment.getFirstChild(); child != null; child = child.getNextSibling()) {
108 if(myResult != null) {
109 evaluators.add(myResult);
114 myCurrentFragmentEvaluator.setStatements(evaluators.toArray(new Evaluator[evaluators.size()]));
115 myResult = myCurrentFragmentEvaluator;
117 myCurrentFragmentEvaluator = oldFragmentEvaluator;
121 public void visitErrorElement(PsiErrorElement element) {
122 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", element.getText()));
126 public void visitAssignmentExpression(PsiAssignmentExpression expression) {
127 final PsiExpression rExpression = expression.getRExpression();
128 if(rExpression == null) {
129 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return;
132 rExpression.accept(this);
133 Evaluator rEvaluator = myResult;
135 final PsiExpression lExpression = expression.getLExpression();
136 final PsiType lType = lExpression.getType();
138 throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", lExpression.getText()));
141 IElementType assignmentType = expression.getOperationTokenType();
142 PsiType rType = rExpression.getType();
143 if(!TypeConversionUtil.areTypesAssignmentCompatible(lType, rExpression) && rType != null) {
144 throwEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", expression.getOperationSign().getText()));
146 lExpression.accept(this);
147 Evaluator lEvaluator = myResult;
149 rEvaluator = handleAssignmentBoxingAndPrimitiveTypeConversions(lType, rType, rEvaluator);
151 if (assignmentType != JavaTokenType.EQ) {
152 IElementType opType = TypeConversionUtil.convertEQtoOperation(assignmentType);
153 final PsiType typeForBinOp = TypeConversionUtil.calcTypeForBinaryExpression(lType, rType, opType, true);
154 if (typeForBinOp == null || rType == null) {
155 throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", expression.getText()));
157 rEvaluator = createBinaryEvaluator(lEvaluator, lType, rEvaluator, rType, opType, typeForBinOp);
159 myResult = new AssignmentEvaluator(lEvaluator, rEvaluator);
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);
166 if (unboxedLType != null) {
167 if (rType instanceof PsiPrimitiveType && !PsiType.NULL.equals(rType)) {
168 if (!rType.equals(unboxedLType)) {
169 rEvaluator = new TypeCastEvaluator(rEvaluator, unboxedLType.getCanonicalText(), true);
171 rEvaluator = new BoxingEvaluator(rEvaluator);
175 // either primitive type or not unboxable type
176 if (lType instanceof PsiPrimitiveType) {
177 if (rType instanceof PsiClassType) {
178 rEvaluator = new UnBoxingEvaluator(rEvaluator);
180 final PsiPrimitiveType unboxedRType = PsiPrimitiveType.getUnboxedType(rType);
181 final PsiType _rType = unboxedRType != null? unboxedRType : rType;
182 if (_rType instanceof PsiPrimitiveType && !PsiType.NULL.equals(_rType)) {
183 if (!lType.equals(_rType)) {
184 rEvaluator = new TypeCastEvaluator(rEvaluator, lType.getCanonicalText(), true);
193 public void visitTryStatement(PsiTryStatement statement) {
194 throw new EvaluateRuntimeException(new UnsupportedExpressionException(statement.getText()));
198 public void visitStatement(PsiStatement statement) {
199 throwEvaluateException(DebuggerBundle.message("evaluation.error.statement.not.supported", statement.getText()));
203 public void visitBlockStatement(PsiBlockStatement statement) {
204 PsiStatement[] statements = statement.getCodeBlock().getStatements();
205 Evaluator [] evaluators = new Evaluator[statements.length];
206 for (int i = 0; i < statements.length; i++) {
207 PsiStatement psiStatement = statements[i];
208 psiStatement.accept(this);
209 evaluators[i] = new DisableGC(myResult);
212 myResult = new BlockStatementEvaluator(evaluators);
216 public void visitLabeledStatement(PsiLabeledStatement labeledStatement) {
217 PsiStatement statement = labeledStatement.getStatement();
218 if (statement != null) {
219 statement.accept(this);
223 private static String getLabel(PsiElement element) {
225 if(element.getParent() instanceof PsiLabeledStatement) {
226 label = ((PsiLabeledStatement)element.getParent()).getName();
232 public void visitDoWhileStatement(PsiDoWhileStatement statement) {
233 Evaluator bodyEvaluator = accept(statement.getBody());
234 Evaluator conditionEvaluator = accept(statement.getCondition());
235 if (conditionEvaluator != null) {
236 myResult = new DoWhileStatementEvaluator(new UnBoxingEvaluator(conditionEvaluator), bodyEvaluator, getLabel(statement));
241 public void visitWhileStatement(PsiWhileStatement statement) {
242 Evaluator bodyEvaluator = accept(statement.getBody());
243 Evaluator conditionEvaluator = accept(statement.getCondition());
244 if (conditionEvaluator != null) {
245 myResult = new WhileStatementEvaluator(new UnBoxingEvaluator(conditionEvaluator), bodyEvaluator, getLabel(statement));
250 public void visitForStatement(PsiForStatement statement) {
251 Evaluator initializerEvaluator = accept(statement.getInitialization());
252 Evaluator conditionEvaluator = accept(statement.getCondition());
253 if (conditionEvaluator != null) {
254 conditionEvaluator = new UnBoxingEvaluator(conditionEvaluator);
256 Evaluator updateEvaluator = accept(statement.getUpdate());
257 Evaluator bodyEvaluator = accept(statement.getBody());
258 if (bodyEvaluator != null) {
259 myResult = new ForStatementEvaluator(initializerEvaluator, conditionEvaluator, updateEvaluator, bodyEvaluator, getLabel(statement));
264 public void visitForeachStatement(PsiForeachStatement statement) {
266 String iterationParameterName = statement.getIterationParameter().getName();
267 myCurrentFragmentEvaluator.setInitialValue(iterationParameterName, null);
268 SyntheticVariableEvaluator iterationParameterEvaluator = new SyntheticVariableEvaluator(myCurrentFragmentEvaluator, iterationParameterName);
270 Evaluator iteratedValueEvaluator = accept(statement.getIteratedValue());
271 Evaluator bodyEvaluator = accept(statement.getBody());
272 if (bodyEvaluator != null) {
273 myResult = new ForeachStatementEvaluator(iterationParameterEvaluator, iteratedValueEvaluator, bodyEvaluator, getLabel(statement));
276 catch (EvaluateException e) {
277 throw new EvaluateRuntimeException(e);
282 private Evaluator accept(@Nullable PsiElement element) {
283 if (element == null || element instanceof PsiEmptyStatement) {
286 element.accept(this);
291 public void visitIfStatement(PsiIfStatement statement) {
292 PsiStatement thenBranch = statement.getThenBranch();
293 if(thenBranch == null) return;
294 thenBranch.accept(this);
295 Evaluator thenEvaluator = myResult;
297 PsiStatement elseBranch = statement.getElseBranch();
298 Evaluator elseEvaluator = null;
299 if(elseBranch != null){
300 elseBranch.accept(this);
301 elseEvaluator = myResult;
304 PsiExpression condition = statement.getCondition();
305 if(condition == null) return;
306 condition.accept(this);
308 myResult = new IfStatementEvaluator(new UnBoxingEvaluator(myResult), thenEvaluator, elseEvaluator);
312 public void visitBreakStatement(PsiBreakStatement statement) {
313 PsiIdentifier labelIdentifier = statement.getLabelIdentifier();
314 myResult = BreakContinueStatementEvaluator.createBreakEvaluator(labelIdentifier != null ? labelIdentifier.getText() : null);
318 public void visitContinueStatement(PsiContinueStatement statement) {
319 PsiIdentifier labelIdentifier = statement.getLabelIdentifier();
320 myResult = BreakContinueStatementEvaluator.createContinueEvaluator(labelIdentifier != null ? labelIdentifier.getText() : null);
324 public void visitExpressionStatement(PsiExpressionStatement statement) {
325 statement.getExpression().accept(this);
329 public void visitExpression(PsiExpression expression) {
330 if (LOG.isDebugEnabled()) {
331 LOG.debug("visitExpression " + expression);
336 public void visitPolyadicExpression(PsiPolyadicExpression wideExpression) {
337 if (LOG.isDebugEnabled()) {
338 LOG.debug("visitPolyadicExpression " + wideExpression);
340 PsiExpression[] operands = wideExpression.getOperands();
341 operands[0].accept(this);
342 Evaluator result = myResult;
343 PsiType lType = operands[0].getType();
344 for (int i = 1; i < operands.length; i++) {
345 PsiExpression expression = operands[i];
346 if (expression == null) {
347 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", wideExpression.getText()));
350 expression.accept(this);
351 Evaluator rResult = myResult;
352 IElementType opType = wideExpression.getOperationTokenType();
353 PsiType rType = expression.getType();
355 throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", expression.getText()));
357 final PsiType typeForBinOp = TypeConversionUtil.calcTypeForBinaryExpression(lType, rType, opType, true);
358 if (typeForBinOp == null) {
359 throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", wideExpression.getText()));
361 myResult = createBinaryEvaluator(result, lType, rResult, rType, opType, typeForBinOp);
362 lType = typeForBinOp;
367 // constructs binary evaluator handling unboxing and numeric promotion issues
368 private static BinaryExpressionEvaluator createBinaryEvaluator(Evaluator lResult,
371 @NotNull PsiType rType,
372 @NotNull IElementType operation,
373 @NotNull PsiType expressionExpectedType) {
374 // handle unboxing if necessary
375 if (isUnboxingInBinaryExpressionApplicable(lType, rType, operation)) {
376 if (rType instanceof PsiClassType && UnBoxingEvaluator.isTypeUnboxable(rType.getCanonicalText())) {
377 rResult = new UnBoxingEvaluator(rResult);
379 if (lType instanceof PsiClassType && UnBoxingEvaluator.isTypeUnboxable(lType.getCanonicalText())) {
380 lResult = new UnBoxingEvaluator(lResult);
383 if (isBinaryNumericPromotionApplicable(lType, rType, operation)) {
384 PsiType _lType = lType;
385 final PsiPrimitiveType unboxedLType = PsiPrimitiveType.getUnboxedType(lType);
386 if (unboxedLType != null) {
387 _lType = unboxedLType;
390 PsiType _rType = rType;
391 final PsiPrimitiveType unboxedRType = PsiPrimitiveType.getUnboxedType(rType);
392 if (unboxedRType != null) {
393 _rType = unboxedRType;
396 // handle numeric promotion
397 if (PsiType.DOUBLE.equals(_lType)) {
398 if (TypeConversionUtil.areTypesConvertible(_rType, PsiType.DOUBLE)) {
399 rResult = new TypeCastEvaluator(rResult, PsiType.DOUBLE.getCanonicalText(), true);
402 else if (PsiType.DOUBLE.equals(_rType)) {
403 if (TypeConversionUtil.areTypesConvertible(_lType, PsiType.DOUBLE)) {
404 lResult = new TypeCastEvaluator(lResult, PsiType.DOUBLE.getCanonicalText(), true);
407 else if (PsiType.FLOAT.equals(_lType)) {
408 if (TypeConversionUtil.areTypesConvertible(_rType, PsiType.FLOAT)) {
409 rResult = new TypeCastEvaluator(rResult, PsiType.FLOAT.getCanonicalText(), true);
412 else if (PsiType.FLOAT.equals(_rType)) {
413 if (TypeConversionUtil.areTypesConvertible(_lType, PsiType.FLOAT)) {
414 lResult = new TypeCastEvaluator(lResult, PsiType.FLOAT.getCanonicalText(), true);
417 else if (PsiType.LONG.equals(_lType)) {
418 if (TypeConversionUtil.areTypesConvertible(_rType, PsiType.LONG)) {
419 rResult = new TypeCastEvaluator(rResult, PsiType.LONG.getCanonicalText(), true);
422 else if (PsiType.LONG.equals(_rType)) {
423 if (TypeConversionUtil.areTypesConvertible(_lType, PsiType.LONG)) {
424 lResult = new TypeCastEvaluator(lResult, PsiType.LONG.getCanonicalText(), true);
428 if (!PsiType.INT.equals(_lType) && TypeConversionUtil.areTypesConvertible(_lType, PsiType.INT)) {
429 lResult = new TypeCastEvaluator(lResult, PsiType.INT.getCanonicalText(), true);
431 if (!PsiType.INT.equals(_rType) && TypeConversionUtil.areTypesConvertible(_rType, PsiType.INT)) {
432 rResult = new TypeCastEvaluator(rResult, PsiType.INT.getCanonicalText(), true);
437 return new BinaryExpressionEvaluator(lResult, rResult, operation, expressionExpectedType.getCanonicalText());
440 private static boolean isBinaryNumericPromotionApplicable(PsiType lType, PsiType rType, IElementType opType) {
441 if (lType == null || rType == null) {
444 if (!TypeConversionUtil.isNumericType(lType) || !TypeConversionUtil.isNumericType(rType)) {
447 if (opType == JavaTokenType.EQEQ || opType == JavaTokenType.NE) {
448 if (PsiType.NULL.equals(lType) || PsiType.NULL.equals(rType)) {
451 if (lType instanceof PsiClassType && rType instanceof PsiClassType) {
454 if (lType instanceof PsiClassType) {
455 return PsiPrimitiveType.getUnboxedType(lType) != null; // should be unboxable
457 if (rType instanceof PsiClassType) {
458 return PsiPrimitiveType.getUnboxedType(rType) != null; // should be unboxable
463 return opType == JavaTokenType.ASTERISK ||
464 opType == JavaTokenType.DIV ||
465 opType == JavaTokenType.PERC ||
466 opType == JavaTokenType.PLUS ||
467 opType == JavaTokenType.MINUS ||
468 opType == JavaTokenType.LT ||
469 opType == JavaTokenType.LE ||
470 opType == JavaTokenType.GT ||
471 opType == JavaTokenType.GE ||
472 opType == JavaTokenType.AND ||
473 opType == JavaTokenType.XOR ||
474 opType == JavaTokenType.OR;
478 private static boolean isUnboxingInBinaryExpressionApplicable(PsiType lType, PsiType rType, IElementType opCode) {
479 if (PsiType.NULL.equals(lType) || PsiType.NULL.equals(rType)) {
482 // handle '==' and '!=' separately
483 if (opCode == JavaTokenType.EQEQ || opCode == JavaTokenType.NE) {
484 return lType instanceof PsiPrimitiveType && rType instanceof PsiClassType ||
485 lType instanceof PsiClassType && rType instanceof PsiPrimitiveType;
487 // all other operations at least one should be of class type
488 return lType instanceof PsiClassType || rType instanceof PsiClassType;
493 * @return promotion type to cast to or null if no casting needed
496 private static PsiType calcUnaryNumericPromotionType(PsiPrimitiveType type) {
497 if (PsiType.BYTE.equals(type) || PsiType.SHORT.equals(type) || PsiType.CHAR.equals(type) || PsiType.INT.equals(type)) {
504 public void visitDeclarationStatement(PsiDeclarationStatement statement) {
505 List<Evaluator> evaluators = new ArrayList<Evaluator>();
507 PsiElement[] declaredElements = statement.getDeclaredElements();
508 for (PsiElement declaredElement : declaredElements) {
509 if (declaredElement instanceof PsiLocalVariable) {
510 if (myCurrentFragmentEvaluator != null) {
511 final PsiLocalVariable localVariable = (PsiLocalVariable)declaredElement;
513 final PsiType lType = localVariable.getType();
515 PsiElementFactory elementFactory = JavaPsiFacade.getInstance(localVariable.getProject()).getElementFactory();
517 PsiExpression initialValue = elementFactory.createExpressionFromText(PsiTypesUtil.getDefaultValueOfType(lType), null);
518 Object value = JavaConstantExpressionEvaluator.computeConstantExpression(initialValue, true);
519 myCurrentFragmentEvaluator.setInitialValue(localVariable.getName(), value);
521 catch (IncorrectOperationException e) {
524 catch (EvaluateException e) {
525 throw new EvaluateRuntimeException(e);
528 PsiExpression initializer = localVariable.getInitializer();
529 if (initializer != null) {
531 if (!TypeConversionUtil.areTypesAssignmentCompatible(lType, initializer)) {
532 throwEvaluateException(
533 DebuggerBundle.message("evaluation.error.incompatible.variable.initializer.type", localVariable.getName()));
535 final PsiType rType = initializer.getType();
536 initializer.accept(this);
537 Evaluator rEvaluator = myResult;
539 PsiExpression localVarReference = elementFactory.createExpressionFromText(localVariable.getName(), initializer);
541 localVarReference.accept(this);
542 Evaluator lEvaluator = myResult;
543 rEvaluator = handleAssignmentBoxingAndPrimitiveTypeConversions(localVarReference.getType(), rType, rEvaluator);
545 Evaluator assignment = new AssignmentEvaluator(lEvaluator, rEvaluator);
546 evaluators.add(assignment);
548 catch (IncorrectOperationException e) {
554 throw new EvaluateRuntimeException(new EvaluateException(
555 DebuggerBundle.message("evaluation.error.local.variable.declarations.not.supported"), null));
559 throw new EvaluateRuntimeException(new EvaluateException(
560 DebuggerBundle.message("evaluation.error.unsupported.declaration", declaredElement.getText()), null));
564 if(!evaluators.isEmpty()) {
565 CodeFragmentEvaluator codeFragmentEvaluator = new CodeFragmentEvaluator(myCurrentFragmentEvaluator);
566 codeFragmentEvaluator.setStatements(evaluators.toArray(new Evaluator[evaluators.size()]));
567 myResult = codeFragmentEvaluator;
574 public void visitConditionalExpression(PsiConditionalExpression expression) {
575 if (LOG.isDebugEnabled()) {
576 LOG.debug("visitConditionalExpression " + expression);
578 final PsiExpression thenExpression = expression.getThenExpression();
579 final PsiExpression elseExpression = expression.getElseExpression();
580 if (thenExpression == null || elseExpression == null){
581 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return;
583 PsiExpression condition = expression.getCondition();
584 condition.accept(this);
585 if (myResult == null) {
586 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", condition.getText())); return;
588 Evaluator conditionEvaluator = new UnBoxingEvaluator(myResult);
589 thenExpression.accept(this);
590 if (myResult == null) {
591 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", thenExpression.getText())); return;
593 Evaluator thenEvaluator = myResult;
594 elseExpression.accept(this);
595 if (myResult == null) {
596 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", elseExpression.getText())); return;
598 Evaluator elseEvaluator = myResult;
599 myResult = new ConditionalExpressionEvaluator(conditionEvaluator, thenEvaluator, elseEvaluator);
603 public void visitReferenceExpression(PsiReferenceExpression expression) {
604 if (LOG.isDebugEnabled()) {
605 LOG.debug("visitReferenceExpression " + expression);
607 PsiExpression qualifier = expression.getQualifierExpression();
608 JavaResolveResult resolveResult = expression.advancedResolve(true);
609 PsiElement element = resolveResult.getElement();
611 if (element instanceof PsiLocalVariable || element instanceof PsiParameter) {
612 final Value labeledValue = element.getUserData(CodeFragmentFactoryContextWrapper.LABEL_VARIABLE_VALUE_KEY);
613 if (labeledValue != null) {
614 myResult = new IdentityEvaluator(labeledValue);
618 final PsiFile containingFile = element.getContainingFile();
619 if(containingFile instanceof PsiCodeFragment && myCurrentFragmentEvaluator != null && myVisitedFragments.contains(containingFile)) {
620 // psiVariable may live in PsiCodeFragment not only in debugger editors, for example Fabrique has such variables.
621 // So treat it as synthetic var only when this code fragment is located in DebuggerEditor,
622 // that's why we need to check that containing code fragment is the one we visited
623 myResult = new SyntheticVariableEvaluator(myCurrentFragmentEvaluator, ((PsiVariable)element).getName());
627 final PsiVariable psiVar = (PsiVariable)element;
628 final String localName = psiVar.getName();
629 PsiClass variableClass = getContainingClass(psiVar);
630 if (getContextPsiClass() == null || getContextPsiClass().equals(variableClass)) {
631 final LocalVariableEvaluator localVarEvaluator = new LocalVariableEvaluator(localName, ContextUtil.isJspImplicit(element));
632 if (psiVar instanceof PsiParameter) {
633 final PsiParameter param = (PsiParameter)psiVar;
634 final PsiParameterList paramList = PsiTreeUtil.getParentOfType(param, PsiParameterList.class, true);
635 if (paramList != null) {
636 localVarEvaluator.setParameterIndex(paramList.getParameterIndex(param));
639 myResult = localVarEvaluator;
642 // the expression references final var outside the context's class (in some of the outer classes)
643 int iterationCount = 0;
644 PsiClass aClass = getOuterClass(getContextPsiClass());
645 while (aClass != null && !aClass.equals(variableClass)) {
647 aClass = getOuterClass(aClass);
649 if (aClass != null) {
650 PsiExpression initializer = psiVar.getInitializer();
651 if(initializer != null) {
652 Object value = JavaPsiFacade.getInstance(psiVar.getProject()).getConstantEvaluationHelper().computeConstantExpression(initializer);
654 PsiType type = resolveResult.getSubstitutor().substitute(psiVar.getType());
655 myResult = new LiteralEvaluator(value, type.getCanonicalText());
659 Evaluator objectEvaluator = new ThisEvaluator(iterationCount);
660 //noinspection HardCodedStringLiteral
661 final PsiClass classAt = myPosition != null? JVMNameUtil.getClassAt(myPosition) : null;
662 FieldEvaluator.TargetClassFilter filter = FieldEvaluator.createClassFilter(classAt != null? classAt : getContextPsiClass());
663 myResult = new FieldEvaluator(objectEvaluator, filter, "val$" + localName);
666 throwEvaluateException(DebuggerBundle.message("evaluation.error.local.variable.missing.from.class.closure", localName));
668 else if (element instanceof PsiField) {
669 final PsiField psiField = (PsiField)element;
670 final PsiClass fieldClass = psiField.getContainingClass();
671 if(fieldClass == null) {
672 throwEvaluateException(DebuggerBundle.message("evaluation.error.cannot.resolve.field.class", psiField.getName())); return;
674 Evaluator objectEvaluator;
675 if (psiField.hasModifierProperty(PsiModifier.STATIC)) {
676 objectEvaluator = new TypeEvaluator(JVMNameUtil.getContextClassJVMQualifiedName(SourcePosition.createFromElement(psiField)));
678 else if(qualifier != null) {
679 qualifier.accept(this);
680 objectEvaluator = myResult;
682 else if (fieldClass.equals(getContextPsiClass()) || getContextPsiClass().isInheritor(fieldClass, true)) {
683 objectEvaluator = new ThisEvaluator();
685 else { // myContextPsiClass != fieldClass && myContextPsiClass is not a subclass of fieldClass
686 int iterationCount = 0;
687 PsiClass aClass = getContextPsiClass();
688 while (aClass != null && !(aClass.equals(fieldClass) || aClass.isInheritor(fieldClass, true))) {
690 aClass = getOuterClass(aClass);
692 if (aClass == null) {
693 throwEvaluateException(DebuggerBundle.message("evaluation.error.cannot.sources.for.field.class", psiField.getName()));
695 objectEvaluator = new ThisEvaluator(iterationCount);
697 myResult = new FieldEvaluator(objectEvaluator, FieldEvaluator.createClassFilter(fieldClass), psiField.getName());
700 //let's guess what this could be
701 PsiElement nameElement = expression.getReferenceNameElement(); // get "b" part
703 if (nameElement instanceof PsiIdentifier) {
704 name = nameElement.getText();
707 //noinspection HardCodedStringLiteral
708 final String elementDisplayString = nameElement != null ? nameElement.getText() : "(null)";
709 throwEvaluateException(DebuggerBundle.message("evaluation.error.identifier.expected", elementDisplayString));
713 if(qualifier != null) {
714 final PsiElement qualifierTarget = qualifier instanceof PsiReferenceExpression
715 ? ((PsiReferenceExpression)qualifier).resolve() : null;
716 if (qualifierTarget instanceof PsiClass) {
717 // this is a call to a 'static' field
718 PsiClass psiClass = (PsiClass)qualifierTarget;
719 final JVMName typeName = JVMNameUtil.getJVMQualifiedName(psiClass);
720 myResult = new FieldEvaluator(new TypeEvaluator(typeName), FieldEvaluator.createClassFilter(psiClass), name);
723 qualifier.accept(this);
724 if (myResult == null) {
725 throwEvaluateException(DebuggerBundle.message("evaluation.error.cannot.evaluate.qualifier", qualifier.getText()));
728 myResult = new FieldEvaluator(myResult, FieldEvaluator.createClassFilter(qualifier.getType()), name);
732 myResult = new LocalVariableEvaluator(name, false);
737 private static void throwEvaluateException(String message) throws EvaluateRuntimeException {
738 //noinspection ThrowableResultOfMethodCallIgnored
739 throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(message));
743 public void visitSuperExpression(PsiSuperExpression expression) {
744 if (LOG.isDebugEnabled()) {
745 LOG.debug("visitSuperExpression " + expression);
747 final int iterationCount = calcIterationCount(expression.getQualifier());
748 myResult = new SuperEvaluator(iterationCount);
752 public void visitThisExpression(PsiThisExpression expression) {
753 if (LOG.isDebugEnabled()) {
754 LOG.debug("visitThisExpression " + expression);
756 final int iterationCount = calcIterationCount(expression.getQualifier());
757 myResult = new ThisEvaluator(iterationCount);
760 private int calcIterationCount(final PsiJavaCodeReferenceElement qualifier) {
761 if (qualifier != null) {
762 return calcIterationCount(qualifier.resolve(), qualifier.getText());
767 private int calcIterationCount(PsiElement targetClass, String name) {
768 int iterationCount = 0;
769 if (targetClass == null || getContextPsiClass() == null) {
770 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", name));
773 PsiClass aClass = getContextPsiClass();
774 while (aClass != null && !aClass.equals(targetClass)) {
776 aClass = getOuterClass(aClass);
779 catch (Exception e) {
780 //noinspection ThrowableResultOfMethodCallIgnored
781 throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(e));
783 return iterationCount;
787 public void visitInstanceOfExpression(PsiInstanceOfExpression expression) {
788 if (LOG.isDebugEnabled()) {
789 LOG.debug("visitInstanceOfExpression " + expression);
791 PsiTypeElement checkType = expression.getCheckType();
792 if(checkType == null) {
793 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText()));
796 PsiType type = checkType.getType();
797 expression.getOperand().accept(this);
798 // ClassObjectEvaluator typeEvaluator = new ClassObjectEvaluator(type.getCanonicalText());
799 Evaluator operandEvaluator = myResult;
800 myResult = new InstanceofEvaluator(operandEvaluator, new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(type)));
804 public void visitParenthesizedExpression(PsiParenthesizedExpression expression) {
805 if (LOG.isDebugEnabled()) {
806 LOG.debug("visitParenthesizedExpression " + expression);
808 PsiExpression expr = expression.getExpression();
815 public void visitPostfixExpression(PsiPostfixExpression expression) {
816 if(expression.getType() == null) {
817 throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", expression.getText()));
820 final PsiExpression operandExpression = expression.getOperand();
821 operandExpression.accept(this);
823 final Evaluator operandEvaluator = myResult;
825 final IElementType operation = expression.getOperationTokenType();
826 final PsiType operandType = operandExpression.getType();
827 @Nullable final PsiType unboxedOperandType = PsiPrimitiveType.getUnboxedType(operandType);
829 Evaluator incrementImpl = createBinaryEvaluator(
830 operandEvaluator, operandType,
831 new LiteralEvaluator(Integer.valueOf(1), "int"), PsiType.INT,
832 operation == JavaTokenType.PLUSPLUS ? JavaTokenType.PLUS : JavaTokenType.MINUS,
833 unboxedOperandType!= null? unboxedOperandType : operandType
835 if (unboxedOperandType != null) {
836 incrementImpl = new BoxingEvaluator(incrementImpl);
838 myResult = new PostfixOperationEvaluator(operandEvaluator, incrementImpl);
842 public void visitPrefixExpression(final PsiPrefixExpression expression) {
843 final PsiType expressionType = expression.getType();
844 if(expressionType == null) {
845 throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", expression.getText()));
848 final PsiExpression operandExpression = expression.getOperand();
849 if (operandExpression == null) {
850 throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.operand", expression.getText()));
853 operandExpression.accept(this);
854 Evaluator operandEvaluator = myResult;
856 // handle unboxing issues
857 final PsiType operandType = operandExpression.getType();
859 final PsiType unboxedOperandType = PsiPrimitiveType.getUnboxedType(operandType);
861 final IElementType operation = expression.getOperationTokenType();
863 if(operation == JavaTokenType.PLUSPLUS || operation == JavaTokenType.MINUSMINUS) {
865 final BinaryExpressionEvaluator rightEval = createBinaryEvaluator(
866 operandEvaluator, operandType,
867 new LiteralEvaluator(Integer.valueOf(1), "int"), PsiType.INT,
868 operation == JavaTokenType.PLUSPLUS ? JavaTokenType.PLUS : JavaTokenType.MINUS,
869 unboxedOperandType!= null? unboxedOperandType : operandType
871 myResult = new AssignmentEvaluator(operandEvaluator, unboxedOperandType != null? new BoxingEvaluator(rightEval) : rightEval);
873 catch (IncorrectOperationException e) {
878 if (JavaTokenType.PLUS.equals(operation) || JavaTokenType.MINUS.equals(operation)|| JavaTokenType.TILDE.equals(operation)) {
879 operandEvaluator = handleUnaryNumericPromotion(operandType, operandEvaluator);
882 if (unboxedOperandType != null) {
883 operandEvaluator = new UnBoxingEvaluator(operandEvaluator);
886 myResult = new UnaryExpressionEvaluator(operation, expressionType.getCanonicalText(), operandEvaluator, expression.getOperationSign().getText());
891 public void visitMethodCallExpression(PsiMethodCallExpression expression) {
892 if (LOG.isDebugEnabled()) {
893 LOG.debug("visitMethodCallExpression " + expression);
895 final PsiExpressionList argumentList = expression.getArgumentList();
896 final PsiExpression[] argExpressions = argumentList.getExpressions();
897 Evaluator[] argumentEvaluators = new Evaluator[argExpressions.length];
898 // evaluate arguments
899 for (int idx = 0; idx < argExpressions.length; idx++) {
900 final PsiExpression psiExpression = argExpressions[idx];
901 psiExpression.accept(this);
902 if (myResult == null) {
903 // cannot build evaluator
904 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", psiExpression.getText()));
906 argumentEvaluators[idx] = new DisableGC(myResult);
908 PsiReferenceExpression methodExpr = expression.getMethodExpression();
910 final JavaResolveResult resolveResult = methodExpr.advancedResolve(false);
911 final PsiMethod psiMethod = (PsiMethod)resolveResult.getElement();
913 PsiExpression qualifier = methodExpr.getQualifierExpression();
914 Evaluator objectEvaluator;
915 JVMName contextClass = null;
917 if(psiMethod != null) {
918 PsiClass methodPsiClass = psiMethod.getContainingClass();
919 contextClass = JVMNameUtil.getJVMQualifiedName(methodPsiClass);
920 if (psiMethod.hasModifierProperty(PsiModifier.STATIC)) {
921 objectEvaluator = new TypeEvaluator(contextClass);
923 else if (qualifier != null ) {
924 qualifier.accept(this);
925 objectEvaluator = myResult;
928 int iterationCount = 0;
929 final PsiElement currentFileResolveScope = resolveResult.getCurrentFileResolveScope();
930 if (currentFileResolveScope instanceof PsiClass) {
931 PsiClass aClass = getContextPsiClass();
932 while(aClass != null && !aClass.equals(currentFileResolveScope)) {
933 aClass = getOuterClass(aClass);
937 objectEvaluator = new ThisEvaluator(iterationCount);
942 if (qualifier != null) {
943 PsiType type = qualifier.getType();
946 contextClass = JVMNameUtil.getJVMQualifiedName(type);
949 if (qualifier instanceof PsiReferenceExpression && ((PsiReferenceExpression)qualifier).resolve() instanceof PsiClass) {
950 // this is a call to a 'static' method but class is not available, try to evaluate by qname
951 if (contextClass == null) {
952 contextClass = JVMNameUtil.getJVMRawText(((PsiReferenceExpression)qualifier).getQualifiedName());
954 objectEvaluator = new TypeEvaluator(contextClass);
957 qualifier.accept(this);
958 objectEvaluator = myResult;
962 objectEvaluator = new ThisEvaluator();
963 contextClass = JVMNameUtil.getContextClassJVMQualifiedName(myPosition);
964 if(contextClass == null && myContextPsiClass != null) {
965 contextClass = JVMNameUtil.getJVMQualifiedName(myContextPsiClass);
968 // throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(
969 // DebuggerBundle.message("evaluation.error.method.not.found", methodExpr.getReferenceName()))
975 if (objectEvaluator == null) {
976 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText()));
979 if (psiMethod != null && !psiMethod.isConstructor()) {
980 if (psiMethod.getReturnType() == null) {
981 throwEvaluateException(DebuggerBundle.message("evaluation.error.unknown.method.return.type", psiMethod.getText()));
985 boolean defaultInterfaceMethod = false;
986 boolean mustBeVararg = false;
988 if (psiMethod != null) {
989 processBoxingConversions(psiMethod.getParameterList().getParameters(), argExpressions, resolveResult.getSubstitutor(), argumentEvaluators);
990 argumentEvaluators = wrapVarargs(psiMethod.getParameterList().getParameters(), argExpressions, resolveResult.getSubstitutor(), argumentEvaluators);
991 defaultInterfaceMethod = psiMethod.hasModifierProperty(PsiModifier.DEFAULT);
992 mustBeVararg = psiMethod.isVarArgs();
995 myResult = new MethodEvaluator(objectEvaluator, contextClass, methodExpr.getReferenceName(),
996 psiMethod != null ? JVMNameUtil.getJVMSignature(psiMethod) : null, argumentEvaluators,
997 defaultInterfaceMethod, mustBeVararg);
1001 public void visitLiteralExpression(PsiLiteralExpression expression) {
1002 final HighlightInfo parsingError = HighlightUtil.checkLiteralExpressionParsingError(expression, null, null);
1003 if (parsingError != null) {
1004 throwEvaluateException(parsingError.getDescription());
1008 final PsiType type = expression.getType();
1010 throwEvaluateException(expression + ": null type");
1014 myResult = new LiteralEvaluator(expression.getValue(), type.getCanonicalText());
1018 public void visitArrayAccessExpression(PsiArrayAccessExpression expression) {
1019 final PsiExpression indexExpression = expression.getIndexExpression();
1020 if(indexExpression == null) {
1021 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return;
1023 indexExpression.accept(this);
1024 final Evaluator indexEvaluator = handleUnaryNumericPromotion(indexExpression.getType(), myResult);
1026 expression.getArrayExpression().accept(this);
1027 Evaluator arrayEvaluator = myResult;
1028 myResult = new ArrayAccessEvaluator(arrayEvaluator, indexEvaluator);
1033 * Handles unboxing and numeric promotion issues for
1034 * - array dimension expressions
1035 * - array index expression
1036 * - unary +, -, and ~ operations
1037 * @param operandExpressionType
1038 * @param operandEvaluator @return operandEvaluator possibly 'wrapped' with necessary unboxing and type-casting evaluators to make returning value
1039 * suitable for mentioned contexts
1041 private static Evaluator handleUnaryNumericPromotion(final PsiType operandExpressionType, Evaluator operandEvaluator) {
1042 final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(operandExpressionType);
1043 if (unboxedType != null && !PsiType.BOOLEAN.equals(unboxedType)) {
1044 operandEvaluator = new UnBoxingEvaluator(operandEvaluator);
1047 // handle numeric promotion
1048 final PsiType _unboxedIndexType = unboxedType != null? unboxedType : operandExpressionType;
1049 if (_unboxedIndexType instanceof PsiPrimitiveType) {
1050 final PsiType promotionType = calcUnaryNumericPromotionType((PsiPrimitiveType)_unboxedIndexType);
1051 if (promotionType != null) {
1052 operandEvaluator = new TypeCastEvaluator(operandEvaluator, promotionType.getCanonicalText(), true);
1055 return operandEvaluator;
1058 @SuppressWarnings({"ConstantConditions"})
1060 public void visitTypeCastExpression(PsiTypeCastExpression expression) {
1061 final PsiExpression operandExpr = expression.getOperand();
1062 operandExpr.accept(this);
1063 Evaluator operandEvaluator = myResult;
1064 final PsiType castType = expression.getCastType().getType();
1065 final PsiType operandType = operandExpr.getType();
1067 // if operand type can not be resolved in current context - leave it for runtime checks
1068 if (castType != null && operandType != null && !TypeConversionUtil.areTypesConvertible(operandType, castType) && PsiUtil.resolveClassInType(operandType) != null) {
1069 throw new EvaluateRuntimeException(
1070 new EvaluateException(JavaErrorMessages.message("inconvertible.type.cast", JavaHighlightUtil.formatType(operandType), JavaHighlightUtil
1071 .formatType(castType)))
1075 final boolean shouldPerformBoxingConversion = castType != null && operandType != null && TypeConversionUtil.boxingConversionApplicable(castType, operandType);
1076 final boolean castingToPrimitive = castType instanceof PsiPrimitiveType;
1077 if (shouldPerformBoxingConversion && castingToPrimitive) {
1078 operandEvaluator = new UnBoxingEvaluator(operandEvaluator);
1081 final boolean performCastToWrapperClass = shouldPerformBoxingConversion && !castingToPrimitive;
1083 if (!(PsiUtil.resolveClassInClassTypeOnly(castType) instanceof PsiTypeParameter)) {
1084 String castTypeName = castType.getCanonicalText();
1085 if (performCastToWrapperClass) {
1086 final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(castType);
1087 if (unboxedType != null) {
1088 castTypeName = unboxedType.getCanonicalText();
1092 myResult = new TypeCastEvaluator(operandEvaluator, castTypeName, castingToPrimitive);
1095 if (performCastToWrapperClass) {
1096 myResult = new BoxingEvaluator(myResult);
1101 public void visitClassObjectAccessExpression(PsiClassObjectAccessExpression expression) {
1102 PsiType type = expression.getOperand().getType();
1104 if (type instanceof PsiPrimitiveType) {
1105 final JVMName typeName = JVMNameUtil.getJVMRawText(((PsiPrimitiveType)type).getBoxedTypeName());
1106 myResult = new FieldEvaluator(new TypeEvaluator(typeName), FieldEvaluator.TargetClassFilter.ALL, "TYPE");
1109 myResult = new ClassObjectEvaluator(new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(type)));
1114 public void visitLambdaExpression(PsiLambdaExpression expression) {
1115 throw new EvaluateRuntimeException(new UnsupportedExpressionException(DebuggerBundle.message("evaluation.error.lambda.evaluation.not.supported")));
1119 public void visitMethodReferenceExpression(PsiMethodReferenceExpression expression) {
1120 throw new EvaluateRuntimeException(new UnsupportedExpressionException(DebuggerBundle.message("evaluation.error.method.reference.evaluation.not.supported")));
1124 public void visitNewExpression(final PsiNewExpression expression) {
1125 PsiType expressionPsiType = expression.getType();
1126 if (expressionPsiType instanceof PsiArrayType) {
1127 Evaluator dimensionEvaluator = null;
1128 PsiExpression[] dimensions = expression.getArrayDimensions();
1129 if (dimensions.length == 1){
1130 PsiExpression dimensionExpression = dimensions[0];
1131 dimensionExpression.accept(this);
1132 if (myResult != null) {
1133 dimensionEvaluator = handleUnaryNumericPromotion(dimensionExpression.getType(), myResult);
1136 throwEvaluateException(
1137 DebuggerBundle.message("evaluation.error.invalid.array.dimension.expression", dimensionExpression.getText()));
1140 else if (dimensions.length > 1){
1141 throwEvaluateException(DebuggerBundle.message("evaluation.error.multi.dimensional.arrays.creation.not.supported"));
1144 Evaluator initializerEvaluator = null;
1145 PsiArrayInitializerExpression arrayInitializer = expression.getArrayInitializer();
1146 if (arrayInitializer != null) {
1147 if (dimensionEvaluator != null) { // initializer already exists
1148 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText()));
1150 arrayInitializer.accept(this);
1151 if (myResult != null) {
1152 initializerEvaluator = handleUnaryNumericPromotion(arrayInitializer.getType(), myResult);
1155 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", arrayInitializer.getText()));
1158 PsiExpression[] initializers = arrayInitializer.getInitializers();
1159 initializerEvaluators = new Evaluator[initializers.length];
1160 for (int idx = 0; idx < initializers.length; idx++) {
1161 PsiExpression initializer = initializers[idx];
1162 initializer.accept(this);
1163 if (myResult instanceof Evaluator) {
1164 initializerEvaluators[idx] = myResult;
1167 throw new EvaluateException("Invalid expression for array initializer: " + initializer.getText(), true);
1172 if (dimensionEvaluator == null && initializerEvaluator == null) {
1173 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText()));
1175 myResult = new NewArrayInstanceEvaluator(
1176 new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(expressionPsiType)),
1178 initializerEvaluator
1181 else if (expressionPsiType instanceof PsiClassType){ // must be a class ref
1182 PsiClass aClass = ((PsiClassType)expressionPsiType).resolve();
1183 if(aClass instanceof PsiAnonymousClass) {
1184 throw new EvaluateRuntimeException(new UnsupportedExpressionException(DebuggerBundle.message("evaluation.error.anonymous.class.evaluation.not.supported")));
1186 PsiExpressionList argumentList = expression.getArgumentList();
1187 if (argumentList == null) {
1188 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())); return;
1190 final PsiExpression[] argExpressions = argumentList.getExpressions();
1191 final JavaResolveResult constructorResolveResult = expression.resolveMethodGenerics();
1192 final PsiMethod constructor = (PsiMethod)constructorResolveResult.getElement();
1193 if (constructor == null && argExpressions.length > 0) {
1194 throw new EvaluateRuntimeException(new EvaluateException(
1195 DebuggerBundle.message("evaluation.error.cannot.resolve.constructor", expression.getText()), null));
1197 Evaluator[] argumentEvaluators = new Evaluator[argExpressions.length];
1198 // evaluate arguments
1199 for (int idx = 0; idx < argExpressions.length; idx++) {
1200 PsiExpression argExpression = argExpressions[idx];
1201 argExpression.accept(this);
1202 if (myResult != null) {
1203 argumentEvaluators[idx] = new DisableGC(myResult);
1206 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", argExpression.getText()));
1210 if (constructor != null) {
1211 processBoxingConversions(constructor.getParameterList().getParameters(), argExpressions, constructorResolveResult.getSubstitutor(), argumentEvaluators);
1212 argumentEvaluators = wrapVarargs(constructor.getParameterList().getParameters(), argExpressions, constructorResolveResult.getSubstitutor(), argumentEvaluators);
1215 if (aClass != null && aClass.getContainingClass() != null && !aClass.hasModifierProperty(PsiModifier.STATIC)) {
1216 argumentEvaluators = addThisEvaluator(argumentEvaluators, aClass.getContainingClass());
1219 JVMName signature = JVMNameUtil.getJVMConstructorSignature(constructor, aClass);
1220 myResult = new NewClassInstanceEvaluator(
1221 new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(expressionPsiType)),
1227 if (expressionPsiType != null) {
1228 throwEvaluateException("Unsupported expression type: " + expressionPsiType.getPresentableText());
1231 throwEvaluateException("Unknown type for expression: " + expression.getText());
1236 private Evaluator[] addThisEvaluator(Evaluator[] argumentEvaluators, PsiClass cls) {
1237 Evaluator[] res = new Evaluator[argumentEvaluators.length+1];
1238 int depth = calcIterationCount(cls, "this");
1239 res[0] = new ThisEvaluator(depth);
1240 System.arraycopy(argumentEvaluators, 0, res, 1, argumentEvaluators.length);
1245 public void visitArrayInitializerExpression(PsiArrayInitializerExpression expression) {
1246 PsiExpression[] initializers = expression.getInitializers();
1247 Evaluator[] evaluators = new Evaluator[initializers.length];
1248 final PsiType type = expression.getType();
1249 boolean primitive = type instanceof PsiArrayType && ((PsiArrayType)type).getComponentType() instanceof PsiPrimitiveType;
1250 for (int idx = 0; idx < initializers.length; idx++) {
1251 PsiExpression initializer = initializers[idx];
1252 initializer.accept(this);
1253 if (myResult != null) {
1254 final Evaluator coerced =
1255 primitive ? handleUnaryNumericPromotion(initializer.getType(), myResult) : new BoxingEvaluator(myResult);
1256 evaluators[idx] = new DisableGC(coerced);
1259 throwEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", initializer.getText()));
1262 myResult = new ArrayInitializerEvaluator(evaluators);
1263 if (type != null && !(expression.getParent() instanceof PsiNewExpression)) {
1264 myResult = new NewArrayInstanceEvaluator(new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(type)),
1271 private static PsiClass getOuterClass(PsiClass aClass) {
1272 return aClass == null ? null : PsiTreeUtil.getContextOfType(aClass, PsiClass.class, true);
1275 private PsiClass getContainingClass(PsiVariable variable) {
1276 PsiElement element = PsiTreeUtil.getParentOfType(variable.getParent(), PsiClass.class, false);
1277 return element == null ? getContextPsiClass() : (PsiClass)element;
1280 public PsiClass getContextPsiClass() {
1281 return myContextPsiClass;
1284 protected ExpressionEvaluator buildElement(final PsiElement element) throws EvaluateException {
1285 LOG.assertTrue(element.isValid());
1287 myContextPsiClass = PsiTreeUtil.getContextOfType(element, PsiClass.class, false);
1289 element.accept(this);
1291 catch (EvaluateRuntimeException e) {
1294 if (myResult == null) {
1295 throw EvaluateExceptionUtil
1296 .createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", element.toString()));
1298 return new ExpressionEvaluatorImpl(myResult);
1302 private static Evaluator[] wrapVarargs(final PsiParameter[] declaredParams,
1303 final PsiExpression[] actualArgumentExpressions,
1304 final PsiSubstitutor methodResolveSubstitutor,
1305 final Evaluator[] argumentEvaluators) {
1306 int lastParam = declaredParams.length - 1;
1307 if (lastParam >= 0 && declaredParams[lastParam].isVarArgs() && argumentEvaluators.length > lastParam) {
1308 // only wrap if the first varargs parameter is null for now
1309 if (!TypeConversionUtil.isNullType(actualArgumentExpressions[lastParam].getType())) {
1310 return argumentEvaluators;
1312 // do not wrap arrays twice
1313 if (argumentEvaluators.length - lastParam == 1 && actualArgumentExpressions[lastParam].getType() instanceof PsiArrayType) {
1314 return argumentEvaluators;
1316 PsiEllipsisType declaredParamType = (PsiEllipsisType)methodResolveSubstitutor.substitute(declaredParams[lastParam].getType());
1317 ArrayInitializerEvaluator varargArrayEvaluator =
1318 new ArrayInitializerEvaluator(Arrays.copyOfRange(argumentEvaluators, lastParam, argumentEvaluators.length));
1319 NewArrayInstanceEvaluator evaluator =
1320 new NewArrayInstanceEvaluator(new TypeEvaluator(JVMNameUtil.getJVMQualifiedName(declaredParamType.toArrayType())), null,
1321 varargArrayEvaluator);
1322 Evaluator[] res = new Evaluator[declaredParams.length];
1323 System.arraycopy(argumentEvaluators, 0, res, 0, lastParam);
1324 res[lastParam] = new DisableGC(evaluator);
1327 return argumentEvaluators;
1330 private static void processBoxingConversions(final PsiParameter[] declaredParams,
1331 final PsiExpression[] actualArgumentExpressions,
1332 final PsiSubstitutor methodResolveSubstitutor,
1333 final Evaluator[] argumentEvaluators) {
1334 if (declaredParams.length > 0) {
1335 final int paramCount = Math.max(declaredParams.length, actualArgumentExpressions.length);
1336 PsiType varargType = null;
1337 for (int idx = 0; idx < paramCount; idx++) {
1338 if (idx >= actualArgumentExpressions.length) {
1339 break; // actual arguments count is less than number of declared params
1341 PsiType declaredParamType;
1342 if (idx < declaredParams.length) {
1343 declaredParamType = methodResolveSubstitutor.substitute(declaredParams[idx].getType());
1344 if (declaredParamType instanceof PsiEllipsisType) {
1345 declaredParamType = varargType = ((PsiEllipsisType)declaredParamType).getComponentType();
1348 else if (varargType != null) {
1349 declaredParamType = varargType;
1354 final PsiType actualArgType = actualArgumentExpressions[idx].getType();
1355 if (TypeConversionUtil.boxingConversionApplicable(declaredParamType, actualArgType)) {
1356 final Evaluator argEval = argumentEvaluators[idx];
1357 argumentEvaluators[idx] = declaredParamType instanceof PsiPrimitiveType ? new UnBoxingEvaluator(argEval) : new BoxingEvaluator(argEval);