cast to runtime type for anonymous classes

This commit is contained in:
peter
2011-09-13 17:06:52 +02:00
parent a3a880da44
commit 4c54fa80c5
4 changed files with 90 additions and 68 deletions
@@ -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);
@@ -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<String> {
public abstract class RuntimeTypeEvaluator extends EditorEvaluationCommand<PsiClass> {
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<Strin
}
}
protected abstract void typeCalculationFinished(@Nullable String type);
protected abstract void typeCalculationFinished(@Nullable PsiClass type);
protected String evaluate(final EvaluationContextImpl evaluationContext) throws EvaluateException {
@Nullable
protected PsiClass evaluate(final EvaluationContextImpl evaluationContext) throws EvaluateException {
final Project project = evaluationContext.getProject();
ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(project, new EvaluatingComputable<ExpressionEvaluator>() {
@@ -72,14 +76,45 @@ public abstract class RuntimeTypeEvaluator extends EditorEvaluationCommand<Strin
final Value value = evaluator.evaluate(evaluationContext);
if(value != null){
return ApplicationManager.getApplication().runReadAction(new Computable<String>() {
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();
}
}
@@ -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<String> nameRef = new AtomicReference<String>();
final AtomicReference<PsiClass> nameRef = new AtomicReference<PsiClass>();
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;
@@ -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);
}
}
/**