From 4c54fa80c599bd4840fb9cf47bc71141a905eb61 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 13 Sep 2011 17:05:29 +0200 Subject: [PATCH] cast to runtime type for anonymous classes --- .../JavaWithRuntimeCastSurrounder.java | 8 +- .../codeinsight/RuntimeTypeEvaluator.java | 83 +++++++++++++------ .../DefaultCodeFragmentFactory.java | 16 ++-- .../watch/DebuggerTreeNodeExpression.java | 51 +++++------- 4 files changed, 90 insertions(+), 68 deletions(-) diff --git a/java/debugger/impl/src/com/intellij/debugger/codeinsight/JavaWithRuntimeCastSurrounder.java b/java/debugger/impl/src/com/intellij/debugger/codeinsight/JavaWithRuntimeCastSurrounder.java index 4fbcb631fb8b..346ff0b9d30a 100644 --- a/java/debugger/impl/src/com/intellij/debugger/codeinsight/JavaWithRuntimeCastSurrounder.java +++ b/java/debugger/impl/src/com/intellij/debugger/codeinsight/JavaWithRuntimeCastSurrounder.java @@ -25,7 +25,6 @@ import com.intellij.debugger.impl.DebuggerSession; import com.intellij.debugger.ui.DebuggerExpressionComboBox; import com.intellij.openapi.application.Result; import com.intellij.openapi.command.WriteCommandAction; -import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ScrollType; import com.intellij.openapi.progress.ProgressIndicator; @@ -43,7 +42,6 @@ import org.jetbrains.annotations.Nullable; * Time: 7:51:01 PM */ public class JavaWithRuntimeCastSurrounder extends JavaExpressionSurrounder { - private static final Logger LOG = Logger.getInstance("#com.intellij.debugger.codeinsight.SurroundWithRuntimeCastHandler"); public String getTemplateDescription() { return CodeInsightBundle.message("surround.with.runtime.type.template"); @@ -81,7 +79,7 @@ public class JavaWithRuntimeCastSurrounder extends JavaExpressionSurrounder { } @Override - protected void typeCalculationFinished(@Nullable final String type) { + protected void typeCalculationFinished(@Nullable final PsiClass type) { if (type == null) { return; } @@ -93,11 +91,9 @@ public class JavaWithRuntimeCastSurrounder extends JavaExpressionSurrounder { new WriteCommandAction(project, CodeInsightBundle.message("command.name.surround.with.runtime.cast")) { protected void run(Result result) throws Throwable { try { - LOG.assertTrue(type != null); - PsiElementFactory factory = JavaPsiFacade.getInstance(myElement.getProject()).getElementFactory(); PsiParenthesizedExpression parenth = - (PsiParenthesizedExpression)factory.createExpressionFromText("((" + type + ")expr)", null); + (PsiParenthesizedExpression)factory.createExpressionFromText("((" + type.getQualifiedName() + ")expr)", null); PsiTypeCastExpression cast = (PsiTypeCastExpression)parenth.getExpression(); cast.getOperand().replace(myElement); parenth = (PsiParenthesizedExpression)JavaCodeStyleManager.getInstance(project).shortenClassReferences(parenth); diff --git a/java/debugger/impl/src/com/intellij/debugger/codeinsight/RuntimeTypeEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/codeinsight/RuntimeTypeEvaluator.java index bba064102462..ecb7556bf2c7 100644 --- a/java/debugger/impl/src/com/intellij/debugger/codeinsight/RuntimeTypeEvaluator.java +++ b/java/debugger/impl/src/com/intellij/debugger/codeinsight/RuntimeTypeEvaluator.java @@ -15,38 +15,41 @@ */ package com.intellij.debugger.codeinsight; -import com.intellij.debugger.ui.EditorEvaluationCommand; -import com.intellij.debugger.impl.DebuggerContextImpl; -import com.intellij.debugger.impl.DebuggerUtilsEx; -import com.intellij.debugger.engine.evaluation.EvaluateException; -import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; -import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil; -import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator; -import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl; -import com.intellij.debugger.engine.ContextUtil; +import com.intellij.debugger.DebuggerBundle; import com.intellij.debugger.DebuggerInvocationUtil; import com.intellij.debugger.EvaluatingComputable; -import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.engine.ContextUtil; +import com.intellij.debugger.engine.evaluation.EvaluateException; +import com.intellij.debugger.engine.evaluation.EvaluateExceptionUtil; +import com.intellij.debugger.engine.evaluation.EvaluationContextImpl; +import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl; +import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator; +import com.intellij.debugger.impl.DebuggerContextImpl; +import com.intellij.debugger.ui.EditorEvaluationCommand; +import com.intellij.openapi.application.AccessToken; +import com.intellij.openapi.application.ReadAction; import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProcessCanceledException; +import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; -import com.intellij.openapi.application.ApplicationManager; -import com.intellij.openapi.util.Computable; import com.intellij.psi.*; +import com.intellij.psi.search.GlobalSearchScope; +import com.sun.jdi.ClassType; +import com.sun.jdi.InterfaceType; +import com.sun.jdi.Type; import com.sun.jdi.Value; import org.jetbrains.annotations.Nullable; /** * @author peter */ -public abstract class RuntimeTypeEvaluator extends EditorEvaluationCommand { +public abstract class RuntimeTypeEvaluator extends EditorEvaluationCommand { public RuntimeTypeEvaluator(@Nullable Editor editor, PsiElement expression, DebuggerContextImpl context, final ProgressIndicator indicator) { super(editor, expression, context, indicator); } public void threadAction() { - String type = null; + PsiClass type = null; try { type = evaluate(); } @@ -59,9 +62,10 @@ public abstract class RuntimeTypeEvaluator extends EditorEvaluationCommand() { @@ -72,14 +76,45 @@ public abstract class RuntimeTypeEvaluator extends EditorEvaluationCommand() { - public String compute() { - return DebuggerUtilsEx.getQualifiedClassName(value.type().name(), project); - } - }); + return getCastableRuntimeType(project, value); } - else { - throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.surrounded.expression.null")); + + throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.surrounded.expression.null")); + } + + public static PsiClass getCastableRuntimeType(Project project, Value value) { + Type type = value.type(); + PsiClass psiClass = findPsiClass(project, type); + if (psiClass != null) { + return psiClass; + } + + if (type instanceof ClassType) { + ClassType superclass = ((ClassType)type).superclass(); + if (superclass != null && !CommonClassNames.JAVA_LANG_OBJECT.equals(superclass.name())) { + psiClass = findPsiClass(project, superclass); + if (psiClass != null) { + return psiClass; + } + } + + for (InterfaceType interfaceType : ((ClassType)type).interfaces()) { + psiClass = findPsiClass(project, interfaceType); + if (psiClass != null) { + return psiClass; + } + } + } + return null; + } + + private static PsiClass findPsiClass(Project project, Type type) { + AccessToken token = ReadAction.start(); + try { + return JavaPsiFacade.getInstance(project).findClass(type.name().replace('$', '.'), GlobalSearchScope.allScope(project)); + } + finally { + token.finish(); } } diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java index 6c85bdb9b444..c07bf964eb5d 100644 --- a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java +++ b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/DefaultCodeFragmentFactory.java @@ -16,8 +16,8 @@ package com.intellij.debugger.engine.evaluation; import com.intellij.codeInsight.completion.CompletionParameters; -import com.intellij.codeInsight.completion.JavaCompletionUtil; import com.intellij.codeInsight.completion.CompletionService; +import com.intellij.codeInsight.completion.JavaCompletionUtil; import com.intellij.debugger.DebuggerManagerEx; import com.intellij.debugger.codeinsight.RuntimeTypeEvaluator; import com.intellij.debugger.impl.DebuggerContextImpl; @@ -29,7 +29,6 @@ import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.*; -import com.intellij.psi.search.GlobalSearchScope; import com.intellij.util.PairFunction; import com.intellij.util.concurrency.Semaphore; import org.jetbrains.annotations.Nullable; @@ -91,11 +90,11 @@ public class DefaultCodeFragmentFactory implements CodeFragmentFactory { if (debuggerSession != null) { final Semaphore semaphore = new Semaphore(); semaphore.down(); - final AtomicReference nameRef = new AtomicReference(); + final AtomicReference nameRef = new AtomicReference(); final RuntimeTypeEvaluator worker = new RuntimeTypeEvaluator(null, expression, debuggerContext, ProgressManager.getInstance().getProgressIndicator()) { @Override - protected void typeCalculationFinished(@Nullable String type) { + protected void typeCalculationFinished(@Nullable PsiClass type) { nameRef.set(type); semaphore.up(); } @@ -105,12 +104,9 @@ public class DefaultCodeFragmentFactory implements CodeFragmentFactory { ProgressManager.checkCanceled(); if (semaphore.waitFor(20)) break; } - final String className = nameRef.get(); - if (className != null) { - final PsiClass psiClass = JavaPsiFacade.getInstance(project).findClass(className, GlobalSearchScope.allScope(project)); - if (psiClass != null) { - return JavaPsiFacade.getElementFactory(project).createType(psiClass); - } + final PsiClass psiClass = nameRef.get(); + if (psiClass != null) { + return JavaPsiFacade.getElementFactory(project).createType(psiClass); } } return null; diff --git a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeExpression.java b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeExpression.java index f744512122e8..56e0208d7d2c 100644 --- a/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeExpression.java +++ b/java/debugger/impl/src/com/intellij/debugger/ui/impl/watch/DebuggerTreeNodeExpression.java @@ -17,11 +17,11 @@ package com.intellij.debugger.ui.impl.watch; import com.intellij.codeInsight.ChangeContextUtil; import com.intellij.debugger.DebuggerBundle; +import com.intellij.debugger.codeinsight.RuntimeTypeEvaluator; import com.intellij.debugger.engine.evaluation.EvaluateException; import com.intellij.debugger.engine.evaluation.TextWithImports; import com.intellij.debugger.engine.evaluation.TextWithImportsImpl; import com.intellij.debugger.impl.DebuggerContextImpl; -import com.intellij.debugger.impl.DebuggerUtilsEx; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.Computable; @@ -197,37 +197,32 @@ public class DebuggerTreeNodeExpression { } public static PsiExpression castToRuntimeType(PsiExpression expression, Value value, PsiElement contextElement) throws EvaluateException { - if (value instanceof ObjectReference) { - return castToType(expression, ((ObjectReference)value).referenceType(), contextElement); - } - else { + if (!(value instanceof ObjectReference)) { return expression; } - } - - private static PsiExpression castToType(PsiExpression expression, ReferenceType valueType, PsiElement contextElement) throws EvaluateException{ - if (valueType != null) { - Project project = expression.getProject(); - - String typeName = DebuggerUtilsEx.getQualifiedClassName(valueType.name(), project); - PsiManager manager = PsiManager.getInstance(project); - - typeName = normalize(typeName, contextElement, project); - - PsiElementFactory elementFactory = JavaPsiFacade.getInstance(manager.getProject()).getElementFactory(); - try { - PsiParenthesizedExpression parenthExpression = (PsiParenthesizedExpression)elementFactory.createExpressionFromText( - "((" + typeName + ")expression)", null); - ((PsiTypeCastExpression)parenthExpression.getExpression()).getOperand().replace(expression); - return parenthExpression; - } - catch (IncorrectOperationException e) { - throw new EvaluateException(DebuggerBundle.message("error.invalid.type.name", typeName), e); - } - } - else { + + ReferenceType valueType = ((ObjectReference)value).referenceType(); + if (valueType == null) { return expression; } + + Project project = expression.getProject(); + + PsiClass type = RuntimeTypeEvaluator.getCastableRuntimeType(project, value); + if (type == null) { + return expression; + } + + PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project); + try { + PsiParenthesizedExpression parenthExpression = (PsiParenthesizedExpression)elementFactory.createExpressionFromText( + "((" + type.getQualifiedName() + ")expression)", null); + ((PsiTypeCastExpression)parenthExpression.getExpression()).getOperand().replace(expression); + return parenthExpression; + } + catch (IncorrectOperationException e) { + throw new EvaluateException(DebuggerBundle.message("error.invalid.type.name", type.getQualifiedName()), e); + } } /**