mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
use runtime type information in debugger evaluation completion
This commit is contained in:
@@ -354,19 +354,20 @@ public class SetValueAction extends DebuggerAction {
|
||||
|
||||
PsiFile psiFile = PsiDocumentManager.getInstance(debuggerContext.getProject()).getPsiFile(editor.getDocument());
|
||||
|
||||
EditorEvaluationCommand evaluationCommand = new EditorEvaluationCommand(getEditor(), psiFile, debuggerContext) {
|
||||
final ProgressWindowWithNotification progressWindow = new ProgressWindowWithNotification(true, getProject());
|
||||
EditorEvaluationCommand evaluationCommand = new EditorEvaluationCommand(getEditor(), psiFile, debuggerContext, progressWindow) {
|
||||
public void threadAction() {
|
||||
try {
|
||||
evaluate();
|
||||
}
|
||||
catch(EvaluateException e) {
|
||||
getProgressWindow().cancel();
|
||||
progressWindow.cancel();
|
||||
}
|
||||
catch(ProcessCanceledException e) {
|
||||
getProgressWindow().cancel();
|
||||
progressWindow.cancel();
|
||||
}
|
||||
finally{
|
||||
if (!getProgressWindow().isCanceled()) {
|
||||
if (!progressWindow.isCanceled()) {
|
||||
DebuggerInvocationUtil.swingInvokeLater(debuggerContext.getProject(), new Runnable() {
|
||||
public void run() {
|
||||
comboBox.addRecent(text);
|
||||
@@ -389,7 +390,7 @@ public class SetValueAction extends DebuggerAction {
|
||||
InvalidTypeException,
|
||||
EvaluateException,
|
||||
IncompatibleThreadStateException {
|
||||
if(!getProgressWindow().isCanceled()) {
|
||||
if(!progressWindow.isCanceled()) {
|
||||
setValueRunnable.setValue(evaluationContext, newValue);
|
||||
node.calcValue();
|
||||
}
|
||||
@@ -408,7 +409,6 @@ public class SetValueAction extends DebuggerAction {
|
||||
}
|
||||
};
|
||||
|
||||
final ProgressWindowWithNotification progressWindow = evaluationCommand.getProgressWindow();
|
||||
progressWindow.addListener(new ProgressIndicatorListenerAdapter() {
|
||||
//should return whether to stop processing
|
||||
public void stopped() {
|
||||
|
||||
+50
-87
@@ -5,31 +5,22 @@ import com.intellij.codeInsight.generation.surroundWith.JavaExpressionSurrounder
|
||||
import com.intellij.debugger.DebuggerBundle;
|
||||
import com.intellij.debugger.DebuggerInvocationUtil;
|
||||
import com.intellij.debugger.DebuggerManagerEx;
|
||||
import com.intellij.debugger.EvaluatingComputable;
|
||||
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.impl.DebuggerSession;
|
||||
import com.intellij.debugger.impl.DebuggerUtilsEx;
|
||||
import com.intellij.debugger.ui.DebuggerExpressionComboBox;
|
||||
import com.intellij.debugger.ui.EditorEvaluationCommand;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.command.CommandProcessor;
|
||||
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.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.util.ProgressWindowWithNotification;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.openapi.util.TextRange;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.codeStyle.JavaCodeStyleManager;
|
||||
import com.intellij.util.IncorrectOperationException;
|
||||
import com.sun.jdi.Value;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* User: lex
|
||||
@@ -46,99 +37,71 @@ public class JavaWithRuntimeCastSurrounder extends JavaExpressionSurrounder {
|
||||
public boolean isApplicable(PsiExpression expr) {
|
||||
PsiFile file = expr.getContainingFile();
|
||||
if (!(file instanceof PsiCodeFragment)) return false;
|
||||
return file.getUserData(DebuggerExpressionComboBox.KEY) != null;
|
||||
if (file.getUserData(DebuggerExpressionComboBox.KEY) == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return RuntimeTypeEvaluator.isSubtypeable(expr);
|
||||
}
|
||||
|
||||
public TextRange surroundExpression(Project project, Editor editor, PsiExpression expr) throws IncorrectOperationException {
|
||||
DebuggerContextImpl debuggerContext = (DebuggerManagerEx.getInstanceEx(project)).getContext();
|
||||
DebuggerSession debuggerSession = debuggerContext.getDebuggerSession();
|
||||
if (debuggerSession != null) {
|
||||
SurroundWithCastWorker worker = new SurroundWithCastWorker(editor, expr, debuggerContext);
|
||||
worker.getProgressWindow().setTitle(DebuggerBundle.message("title.evaluating"));
|
||||
debuggerContext.getDebugProcess().getManagerThread().startProgress(worker, worker.getProgressWindow());
|
||||
final ProgressWindowWithNotification progressWindow = new ProgressWindowWithNotification(true, expr.getProject());
|
||||
SurroundWithCastWorker worker = new SurroundWithCastWorker(editor, expr, debuggerContext, progressWindow);
|
||||
progressWindow.setTitle(DebuggerBundle.message("title.evaluating"));
|
||||
debuggerContext.getDebugProcess().getManagerThread().startProgress(worker, progressWindow);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private class SurroundWithCastWorker extends EditorEvaluationCommand<String> {
|
||||
public SurroundWithCastWorker(Editor editor, PsiExpression expression, DebuggerContextImpl context) {
|
||||
super(editor, expression, context);
|
||||
private class SurroundWithCastWorker extends RuntimeTypeEvaluator {
|
||||
private final Editor myEditor;
|
||||
|
||||
public SurroundWithCastWorker(Editor editor, PsiExpression expression, DebuggerContextImpl context, final ProgressIndicator indicator) {
|
||||
super(editor, expression, context, indicator);
|
||||
myEditor = editor;
|
||||
}
|
||||
|
||||
protected void executeWriteCommand(final Project project, final Runnable runnable) {
|
||||
DebuggerInvocationUtil.invokeLater(project, new Runnable() {
|
||||
public void run() {
|
||||
ApplicationManager.getApplication().runWriteAction(new Runnable() {
|
||||
public void run() {
|
||||
CommandProcessor.getInstance().executeCommand(project, runnable, CodeInsightBundle.message("command.name.surround.with.runtime.cast"), null);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, getProgressWindow().getModalityState());
|
||||
}
|
||||
|
||||
public void threadAction() {
|
||||
final String type;
|
||||
try {
|
||||
type = evaluate();
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
@Override
|
||||
protected void typeCalculationFinished(@Nullable final String type) {
|
||||
if (type == null) {
|
||||
return;
|
||||
}
|
||||
catch (EvaluateException e) {
|
||||
return;
|
||||
}
|
||||
|
||||
final Project project = myElement.getProject();
|
||||
|
||||
hold();
|
||||
|
||||
executeWriteCommand(project, new Runnable() {
|
||||
final Project project = myElement.getProject();
|
||||
DebuggerInvocationUtil.invokeLater(project, new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
LOG.assertTrue(type != null);
|
||||
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);
|
||||
PsiTypeCastExpression cast = (PsiTypeCastExpression) parenth.getExpression();
|
||||
cast.getOperand().replace(myElement);
|
||||
parenth = (PsiParenthesizedExpression)JavaCodeStyleManager.getInstance(project).shortenClassReferences(parenth);
|
||||
PsiExpression expr = (PsiExpression) myElement.replace(parenth);
|
||||
TextRange range = expr.getTextRange();
|
||||
getEditor().getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset());
|
||||
getEditor().getCaretModel().moveToOffset(range.getEndOffset());
|
||||
getEditor().getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
// OK here. Can be caused by invalid type like one for proxy starts with . '.Proxy34'
|
||||
}
|
||||
finally{
|
||||
release();
|
||||
}
|
||||
PsiElementFactory factory = JavaPsiFacade.getInstance(myElement.getProject()).getElementFactory();
|
||||
PsiParenthesizedExpression parenth =
|
||||
(PsiParenthesizedExpression)factory.createExpressionFromText("((" + type + ")expr)", null);
|
||||
PsiTypeCastExpression cast = (PsiTypeCastExpression)parenth.getExpression();
|
||||
cast.getOperand().replace(myElement);
|
||||
parenth = (PsiParenthesizedExpression)JavaCodeStyleManager.getInstance(project).shortenClassReferences(parenth);
|
||||
PsiExpression expr = (PsiExpression)myElement.replace(parenth);
|
||||
TextRange range = expr.getTextRange();
|
||||
myEditor.getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset());
|
||||
myEditor.getCaretModel().moveToOffset(range.getEndOffset());
|
||||
myEditor.getScrollingModel().scrollToCaret(ScrollType.RELATIVE);
|
||||
}
|
||||
catch (IncorrectOperationException e) {
|
||||
// OK here. Can be caused by invalid type like one for proxy starts with . '.Proxy34'
|
||||
}
|
||||
finally {
|
||||
release();
|
||||
}
|
||||
}
|
||||
}.execute();
|
||||
}
|
||||
});
|
||||
}, myProgressIndicator.getModalityState());
|
||||
}
|
||||
|
||||
protected String evaluate(final EvaluationContextImpl evaluationContext) throws EvaluateException {
|
||||
final Project project = evaluationContext.getProject();
|
||||
|
||||
ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(project, new EvaluatingComputable<ExpressionEvaluator>() {
|
||||
public ExpressionEvaluator compute() throws EvaluateException {
|
||||
return EvaluatorBuilderImpl.getInstance().build(myElement, ContextUtil.getSourcePosition(evaluationContext));
|
||||
}
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.surrounded.expression.null"));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
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.DebuggerInvocationUtil;
|
||||
import com.intellij.debugger.EvaluatingComputable;
|
||||
import com.intellij.debugger.DebuggerBundle;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.util.Computable;
|
||||
import com.intellij.psi.*;
|
||||
import com.sun.jdi.Value;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public abstract class RuntimeTypeEvaluator extends EditorEvaluationCommand<String> {
|
||||
public RuntimeTypeEvaluator(@Nullable Editor editor, PsiElement expression, DebuggerContextImpl context, final ProgressIndicator indicator) {
|
||||
super(editor, expression, context, indicator);
|
||||
}
|
||||
|
||||
public void threadAction() {
|
||||
String type = null;
|
||||
try {
|
||||
type = evaluate();
|
||||
}
|
||||
catch (ProcessCanceledException ignored) {
|
||||
}
|
||||
catch (EvaluateException ignored) {
|
||||
}
|
||||
finally {
|
||||
typeCalculationFinished(type);
|
||||
}
|
||||
}
|
||||
|
||||
protected abstract void typeCalculationFinished(@Nullable String type);
|
||||
|
||||
protected String evaluate(final EvaluationContextImpl evaluationContext) throws EvaluateException {
|
||||
final Project project = evaluationContext.getProject();
|
||||
|
||||
ExpressionEvaluator evaluator = DebuggerInvocationUtil.commitAndRunReadAction(project, new EvaluatingComputable<ExpressionEvaluator>() {
|
||||
public ExpressionEvaluator compute() throws EvaluateException {
|
||||
return EvaluatorBuilderImpl.getInstance().build(myElement, ContextUtil.getSourcePosition(evaluationContext));
|
||||
}
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
throw EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.surrounded.expression.null"));
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isSubtypeable(PsiExpression expr) {
|
||||
final PsiType type = expr.getType();
|
||||
if (type instanceof PsiPrimitiveType) {
|
||||
return false;
|
||||
}
|
||||
if (type instanceof PsiClassType) {
|
||||
final PsiClass psiClass = ((PsiClassType)type).resolve();
|
||||
if (psiClass != null && psiClass.hasModifierProperty(PsiModifier.FINAL)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
+57
-5
@@ -4,15 +4,26 @@
|
||||
*/
|
||||
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.debugger.DebuggerManagerEx;
|
||||
import com.intellij.debugger.codeinsight.RuntimeTypeEvaluator;
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl;
|
||||
import com.intellij.debugger.impl.DebuggerSession;
|
||||
import com.intellij.debugger.ui.DebuggerExpressionComboBox;
|
||||
import com.intellij.openapi.fileTypes.LanguageFileType;
|
||||
import com.intellij.openapi.fileTypes.StdFileTypes;
|
||||
import com.intellij.openapi.progress.ProgressManager;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.JavaCodeFragment;
|
||||
import com.intellij.psi.JavaPsiFacade;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementFactory;
|
||||
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;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
/**
|
||||
* @author Eugene Zhuravlev
|
||||
@@ -31,7 +42,7 @@ public class DefaultCodeFragmentFactory implements CodeFragmentFactory {
|
||||
return createCodeFragment(item, context, project);
|
||||
}
|
||||
|
||||
public JavaCodeFragment createCodeFragment(TextWithImports item, PsiElement context, Project project) {
|
||||
public JavaCodeFragment createCodeFragment(TextWithImports item, PsiElement context, final Project project) {
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(project).getElementFactory();
|
||||
final String text = item.getText();
|
||||
|
||||
@@ -50,6 +61,47 @@ public class DefaultCodeFragmentFactory implements CodeFragmentFactory {
|
||||
fragment.setVisibilityChecker(JavaCodeFragment.VisibilityChecker.EVERYTHING_VISIBLE);
|
||||
//noinspection HardCodedStringLiteral
|
||||
fragment.putUserData(DebuggerExpressionComboBox.KEY, "DebuggerComboBoxEditor.IS_DEBUGGER_EDITOR");
|
||||
fragment.putCopyableUserData(JavaCompletionUtil.DYNAMIC_TYPE_EVALUATOR, new PairFunction<PsiExpression, CompletionParameters, PsiType>() {
|
||||
public PsiType fun(PsiExpression expression, CompletionParameters parameters) {
|
||||
if (!RuntimeTypeEvaluator.isSubtypeable(expression)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (parameters.getInvocationCount() == 1 && JavaCompletionUtil.containsMethodCalls(expression)) {
|
||||
final CompletionService service = CompletionService.getCompletionService();
|
||||
if (service.getAdvertisementText() == null) {
|
||||
service.setAdvertisementText("Invoke completion once more to see runtime type variants");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
final DebuggerContextImpl debuggerContext = DebuggerManagerEx.getInstanceEx(project).getContext();
|
||||
DebuggerSession debuggerSession = debuggerContext.getDebuggerSession();
|
||||
if (debuggerSession != null) {
|
||||
final Semaphore semaphore = new Semaphore();
|
||||
semaphore.down();
|
||||
final AtomicReference<String> nameRef = new AtomicReference<String>();
|
||||
final RuntimeTypeEvaluator worker =
|
||||
new RuntimeTypeEvaluator(null, expression, debuggerContext, ProgressManager.getInstance().getProgressIndicator()) {
|
||||
@Override
|
||||
protected void typeCalculationFinished(@Nullable String type) {
|
||||
nameRef.set(type);
|
||||
semaphore.up();
|
||||
}
|
||||
};
|
||||
debuggerContext.getDebugProcess().getManagerThread().invoke(worker);
|
||||
semaphore.waitFor(1000);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@@ -11,27 +11,25 @@ import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
|
||||
import com.intellij.debugger.impl.DebuggerContextImpl;
|
||||
import com.intellij.openapi.editor.Editor;
|
||||
import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.progress.util.ProgressWindowWithNotification;
|
||||
import com.intellij.openapi.progress.ProgressIndicator;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* Created by IntelliJ IDEA.
|
||||
* User: lex
|
||||
* Date: Mar 15, 2004
|
||||
* Time: 4:07:59 PM
|
||||
* To change this template use File | Settings | File Templates.
|
||||
* @author lex
|
||||
*/
|
||||
public abstract class EditorEvaluationCommand<T> extends DebuggerContextCommandImpl {
|
||||
protected final PsiElement myElement;
|
||||
private final Editor myEditor;
|
||||
private final ProgressWindowWithNotification myProgressWindow;
|
||||
@Nullable private final Editor myEditor;
|
||||
protected final ProgressIndicator myProgressIndicator;
|
||||
private final DebuggerContextImpl myDebuggerContext;
|
||||
|
||||
public EditorEvaluationCommand(Editor editor, PsiElement expression, DebuggerContextImpl context) {
|
||||
public EditorEvaluationCommand(@Nullable Editor editor, PsiElement expression, DebuggerContextImpl context,
|
||||
final ProgressIndicator indicator) {
|
||||
super(context);
|
||||
Project project = expression.getProject();
|
||||
myProgressWindow = new ProgressWindowWithNotification(true, project);
|
||||
myProgressIndicator = indicator;
|
||||
myEditor = editor;
|
||||
myElement = expression;
|
||||
myDebuggerContext = (DebuggerManagerEx.getInstanceEx(project)).getContext();
|
||||
@@ -44,20 +42,22 @@ public abstract class EditorEvaluationCommand<T> extends DebuggerContextCommandI
|
||||
protected abstract T evaluate(EvaluationContextImpl evaluationContext) throws EvaluateException;
|
||||
|
||||
public T evaluate() throws EvaluateException {
|
||||
getProgressWindow().setText(DebuggerBundle.message("progress.evaluating", myElement.getText()));
|
||||
myProgressIndicator.setText(DebuggerBundle.message("progress.evaluating", myElement.getText()));
|
||||
|
||||
try {
|
||||
T result = evaluate(myDebuggerContext.createEvaluationContext());
|
||||
|
||||
if(getProgressWindow().isCanceled()) throw new ProcessCanceledException();
|
||||
if (myProgressIndicator.isCanceled()) throw new ProcessCanceledException();
|
||||
|
||||
return result;
|
||||
} catch (final EvaluateException e) {
|
||||
DebuggerInvocationUtil.invokeLater(myDebuggerContext.getProject(), new Runnable() {
|
||||
public void run() {
|
||||
showEvaluationHint(myEditor, myElement, e);
|
||||
}
|
||||
}, myProgressWindow.getModalityState());
|
||||
if (myEditor != null) {
|
||||
DebuggerInvocationUtil.invokeLater(myDebuggerContext.getProject(), new Runnable() {
|
||||
public void run() {
|
||||
showEvaluationHint(myEditor, myElement, e);
|
||||
}
|
||||
}, myProgressIndicator.getModalityState());
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
@@ -71,11 +71,4 @@ public abstract class EditorEvaluationCommand<T> extends DebuggerContextCommandI
|
||||
1500);
|
||||
}
|
||||
|
||||
public ProgressWindowWithNotification getProgressWindow() {
|
||||
return myProgressWindow;
|
||||
}
|
||||
|
||||
public Editor getEditor() {
|
||||
return myEditor;
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -170,7 +170,7 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
if (ANNOTATION_ATTRIBUTE_NAME.accepts(insertedElement)) {
|
||||
ApplicationManager.getApplication().runReadAction(new Runnable() {
|
||||
public void run() {
|
||||
completeAnnotationAttributeName(_result, file, insertedElement, completionData);
|
||||
completeAnnotationAttributeName(_result, file, insertedElement, parameters);
|
||||
}
|
||||
});
|
||||
_result.stopHere();
|
||||
@@ -191,7 +191,7 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
(PsiJavaReference) reference,
|
||||
new ElementExtractorFilter(filter),
|
||||
checkAccess,
|
||||
result.getPrefixMatcher())) {
|
||||
result.getPrefixMatcher(), parameters)) {
|
||||
if (isSwitchLabel) {
|
||||
result.addElement(TailTypeDecorator.createDecorator(element, TailType.createSimpleTailType(':')));
|
||||
} else {
|
||||
@@ -257,7 +257,7 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
|
||||
private static void completeAnnotationAttributeName(CompletionResultSet result, PsiFile file, PsiElement insertedElement,
|
||||
JavaAwareCompletionData completionData) {
|
||||
CompletionParameters parameters) {
|
||||
PsiNameValuePair pair = PsiTreeUtil.getParentOfType(insertedElement, PsiNameValuePair.class);
|
||||
PsiAnnotationParameterList parameterList = (PsiAnnotationParameterList)pair.getParent();
|
||||
PsiAnnotation anno = (PsiAnnotation)parameterList.getParent();
|
||||
@@ -275,7 +275,7 @@ public class JavaCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
|
||||
if (showClasses && insertedElement.getParent() instanceof PsiReferenceExpression) {
|
||||
final Set<LookupElement> set = JavaCompletionUtil.processJavaReference(insertedElement, (PsiJavaReference)insertedElement.getParent(), TrueFilter.INSTANCE, true, result.getPrefixMatcher());
|
||||
final Set<LookupElement> set = JavaCompletionUtil.processJavaReference(insertedElement, (PsiJavaReference)insertedElement.getParent(), TrueFilter.INSTANCE, true, result.getPrefixMatcher(), parameters);
|
||||
|
||||
for (final LookupElement element : set) {
|
||||
result.addElement(element);
|
||||
|
||||
@@ -11,10 +11,10 @@ import com.intellij.codeInsight.guess.GuessManager;
|
||||
import com.intellij.codeInsight.lookup.*;
|
||||
import com.intellij.featureStatistics.FeatureUsageTracker;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.*;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.openapi.editor.Document;
|
||||
import static com.intellij.patterns.PlatformPatterns.psiElement;
|
||||
import com.intellij.patterns.PsiElementPattern;
|
||||
import com.intellij.psi.*;
|
||||
@@ -35,6 +35,7 @@ import com.intellij.psi.xml.XmlToken;
|
||||
import com.intellij.psi.xml.XmlTokenType;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.NullableFunction;
|
||||
import com.intellij.util.PairFunction;
|
||||
import com.intellij.util.containers.HashMap;
|
||||
import gnu.trove.THashSet;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -45,6 +46,7 @@ import java.util.*;
|
||||
|
||||
public class JavaCompletionUtil {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.completion.JavaCompletionUtil");
|
||||
public static final Key<PairFunction<PsiExpression, CompletionParameters, PsiType>> DYNAMIC_TYPE_EVALUATOR = Key.create("DYNAMIC_TYPE_EVALUATOR");
|
||||
|
||||
static final Key<PsiType> QUALIFIER_TYPE_ATTR = Key.create("qualifierType"); // SmartPsiElementPointer to PsiType of "qualifier"
|
||||
@NonNls
|
||||
@@ -827,7 +829,7 @@ public class JavaCompletionUtil {
|
||||
}
|
||||
|
||||
public static Set<LookupElement> processJavaReference(PsiElement element, PsiJavaReference javaReference, ElementFilter elementFilter,
|
||||
final boolean checkAccess, @Nullable final PrefixMatcher matcher) {
|
||||
final boolean checkAccess, @Nullable final PrefixMatcher matcher, CompletionParameters parameters) {
|
||||
final THashSet<LookupElement> set = new THashSet<LookupElement>();
|
||||
final Condition<String> nameCondition = matcher == null ? null : new Condition<String>() {
|
||||
public boolean value(String s) {
|
||||
@@ -839,7 +841,7 @@ public class JavaCompletionUtil {
|
||||
final Collection<CompletionElement> plainResults = processor.getResults();
|
||||
|
||||
final PsiType qualifierType = processor.getQualifierType();
|
||||
PsiType castedQualifierType = addQualifierCastingVariants(javaReference, processor, set);
|
||||
PsiType castedQualifierType = addQualifierCastingVariants(javaReference, processor, set, parameters);
|
||||
|
||||
boolean mayHighlight = qualifierType != null && (castedQualifierType == null || !qualifierType.isAssignableFrom(castedQualifierType));
|
||||
|
||||
@@ -854,35 +856,52 @@ public class JavaCompletionUtil {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiType addQualifierCastingVariants(PsiJavaReference javaReference, JavaCompletionProcessor processor, THashSet<LookupElement> set) {
|
||||
private static PsiType addQualifierCastingVariants(PsiJavaReference javaReference, JavaCompletionProcessor processor, THashSet<LookupElement> set, CompletionParameters parameters) {
|
||||
if (javaReference instanceof PsiReferenceExpression) {
|
||||
final PsiReferenceExpression refExpr = (PsiReferenceExpression)javaReference;
|
||||
final PsiExpression qualifier = refExpr.getQualifierExpression();
|
||||
if (qualifier != null) {
|
||||
final Project project = qualifier.getProject();
|
||||
final PsiType type = GuessManager.getInstance(project).getDataFlowCastedExpressionType(qualifier);
|
||||
final PairFunction<PsiExpression, CompletionParameters, PsiType> evaluator = refExpr.getContainingFile().getCopyableUserData(DYNAMIC_TYPE_EVALUATOR);
|
||||
PsiType type = null;
|
||||
if (evaluator != null) {
|
||||
type = evaluator.fun(qualifier, parameters);
|
||||
}
|
||||
if (type == null) {
|
||||
type = GuessManager.getInstance(project).getDataFlowCastedExpressionType(qualifier);
|
||||
}
|
||||
if (type != null) {
|
||||
processor.clear();
|
||||
|
||||
final String newText = "((" + type.getCanonicalText() + ") " + qualifier.getText() + ")." + refExpr.getReferenceName();
|
||||
final PsiExpression newRef = JavaPsiFacade.getElementFactory(project).createExpressionFromText(newText, refExpr);
|
||||
((PsiReferenceExpression)newRef).processVariants(processor);
|
||||
|
||||
final LookupElement castItem = PsiTypeLookupItem.createLookupItem(type);
|
||||
|
||||
for (CompletionElement completionElement : processor.getResults()) {
|
||||
final LookupElement item = createLookupElement(completionElement, type);
|
||||
if (item != null) {
|
||||
set.add(highlightIfNeeded(type, castQualifier(project, item, castItem)));
|
||||
}
|
||||
}
|
||||
return type;
|
||||
return addQualifierCastingVariants(processor, refExpr, type, set);
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PsiType addQualifierCastingVariants(JavaCompletionProcessor processor, PsiReferenceExpression refExpr,
|
||||
PsiType castTo,
|
||||
THashSet<LookupElement> set) {
|
||||
Project project = refExpr.getProject();
|
||||
|
||||
PsiExpression qualifier = refExpr.getQualifierExpression();
|
||||
assert qualifier != null;
|
||||
final String newText = "((" + castTo.getCanonicalText() + ") " + qualifier.getText() + ")." + refExpr.getReferenceName();
|
||||
final PsiExpression newRef = JavaPsiFacade.getElementFactory(project).createExpressionFromText(newText, refExpr);
|
||||
((PsiReferenceExpression)newRef).processVariants(processor);
|
||||
|
||||
final LookupElement castItem = PsiTypeLookupItem.createLookupItem(castTo);
|
||||
|
||||
for (CompletionElement completionElement : processor.getResults()) {
|
||||
final LookupElement item = createLookupElement(completionElement, castTo);
|
||||
if (item != null) {
|
||||
set.add(highlightIfNeeded(castTo, castQualifier(project, item, castItem)));
|
||||
}
|
||||
}
|
||||
return castTo;
|
||||
}
|
||||
|
||||
private static LookupElementDecorator<LookupElement> castQualifier(final Project project, LookupElement item, final LookupElement to) {
|
||||
return LookupElementDecorator.withInsertHandler(item, new InsertHandlerDecorator<LookupElement>() {
|
||||
public void handleInsert(InsertionContext context, LookupElementDecorator<LookupElement> item) {
|
||||
@@ -999,4 +1018,15 @@ public class JavaCompletionUtil {
|
||||
ret.setAttribute(LookupItem.TAIL_TEXT_SMALL_ATTR, "");
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static PsiElement getQualifier(final PsiElement element) {
|
||||
return element instanceof PsiJavaCodeReferenceElement ? ((PsiJavaCodeReferenceElement)element).getQualifier() : null;
|
||||
}
|
||||
|
||||
public static boolean containsMethodCalls(@Nullable final PsiElement qualifier) {
|
||||
if (qualifier == null) return false;
|
||||
if (qualifier instanceof PsiMethodCallExpression) return true;
|
||||
return containsMethodCalls(getQualifier(qualifier));
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -189,7 +189,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
|
||||
final ElementFilter filter = getReferenceFilter(element);
|
||||
if (filter != null) {
|
||||
final List<ExpectedTypeInfo> infos = Arrays.asList(getExpectedTypes(parameters));
|
||||
for (final LookupElement item : completeReference(element, reference, filter, true)) {
|
||||
for (final LookupElement item : completeReference(element, reference, filter, true, parameters)) {
|
||||
if (AFTER_THROW_NEW.accepts(element)) {
|
||||
((LookupItem)item).setAttribute(LookupItem.DONT_CHECK_FOR_INNERS, "");
|
||||
if (item.getObject() instanceof PsiClass) {
|
||||
@@ -203,7 +203,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
else if (INSIDE_TYPECAST.accepts(element)) {
|
||||
final ReturnTypeFilter rfilter = new ReturnTypeFilter(new GeneratorFilter(AssignableToFilter.class, new CastTypeGetter()));
|
||||
for (final LookupElement item : completeReference(element, reference, rfilter, false)) {
|
||||
for (final LookupElement item : completeReference(element, reference, rfilter, false, parameters)) {
|
||||
result.addElement(item);
|
||||
}
|
||||
}
|
||||
@@ -626,7 +626,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
|
||||
result.addElement(decorate(item, infos));
|
||||
}
|
||||
|
||||
static Set<LookupElement> completeReference(final PsiElement element, PsiReference reference, final ElementFilter filter, final boolean acceptClasses) {
|
||||
static Set<LookupElement> completeReference(final PsiElement element, PsiReference reference, final ElementFilter filter, final boolean acceptClasses, CompletionParameters parameters) {
|
||||
if (reference instanceof PsiMultiReference) {
|
||||
reference = ContainerUtil.findInstance(((PsiMultiReference) reference).getReferences(), PsiJavaReference.class);
|
||||
}
|
||||
@@ -651,7 +651,7 @@ public class JavaSmartCompletionContributor extends CompletionContributor {
|
||||
ReflectionCache.isAssignable(CandidateInfo.class, hintClass) ||
|
||||
ReflectionCache.isAssignable(PsiKeyword.class, hintClass);
|
||||
}
|
||||
}, true, null);
|
||||
}, true, null, parameters);
|
||||
}
|
||||
|
||||
return Collections.emptySet();
|
||||
|
||||
+7
-18
@@ -95,14 +95,14 @@ public class ReferenceExpressionCompletionContributor extends ExpressionSmartCom
|
||||
final PsiReference reference = element.getContainingFile().findReferenceAt(offset);
|
||||
if (reference != null) {
|
||||
final ElementFilter filter = getReferenceFilter(element, false, false);
|
||||
final Set<LookupElement> set = JavaSmartCompletionContributor.completeReference(element, reference, filter, false);
|
||||
final Set<LookupElement> set = JavaSmartCompletionContributor.completeReference(element, reference, filter, false, parameters);
|
||||
for (final LookupElement item : set) {
|
||||
result.addElement(item);
|
||||
}
|
||||
|
||||
if (parameters.getInvocationCount() >= 2) {
|
||||
ElementFilter baseFilter = getReferenceFilter(element, true, false);
|
||||
for (final LookupElement baseItem : JavaSmartCompletionContributor.completeReference(element, reference, baseFilter, false)) {
|
||||
for (final LookupElement baseItem : JavaSmartCompletionContributor.completeReference(element, reference, baseFilter, false, parameters)) {
|
||||
addSecondCompletionVariants(element, reference, baseItem, parameters, result);
|
||||
}
|
||||
|
||||
@@ -127,11 +127,11 @@ public class ReferenceExpressionCompletionContributor extends ExpressionSmartCom
|
||||
PsiType itemType = JavaCompletionUtil.getLookupElementType(baseItem);
|
||||
if (itemType == null) return;
|
||||
|
||||
final PsiElement qualifier = getQualifier(reference.getElement());
|
||||
final PsiElement qualifier = JavaCompletionUtil.getQualifier(reference.getElement());
|
||||
final PsiType expectedType = parameters.getExpectedType();
|
||||
if (!OBJECT_METHOD_PATTERN.accepts(object) || allowGetClass(object, parameters)) {
|
||||
if (!itemType.equalsToText(CommonClassNames.JAVA_LANG_STRING)) {
|
||||
addChainedCallVariants(element, baseItem, result, itemType, expectedType);
|
||||
addChainedCallVariants(element, baseItem, result, itemType, expectedType, parameters);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -191,11 +191,6 @@ public class ReferenceExpressionCompletionContributor extends ExpressionSmartCom
|
||||
return false;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiElement getQualifier(final PsiElement element) {
|
||||
return element instanceof PsiJavaCodeReferenceElement ? ((PsiJavaCodeReferenceElement)element).getQualifier() : null;
|
||||
}
|
||||
|
||||
private static void addArraysAsListConversions(final PsiElement element, final String prefix, final PsiType itemType, final CompletionResultSet result,
|
||||
@Nullable PsiElement qualifier,
|
||||
final PsiType expectedType) throws IncorrectOperationException {
|
||||
@@ -261,7 +256,7 @@ public class ReferenceExpressionCompletionContributor extends ExpressionSmartCom
|
||||
}
|
||||
|
||||
final String bracketSpace = getSpace(CodeStyleSettingsManager.getSettings(element.getProject()).SPACE_WITHIN_BRACKETS);
|
||||
if (object instanceof PsiVariable && !containsMethodCalls(qualifier)) {
|
||||
if (object instanceof PsiVariable && !JavaCompletionUtil.containsMethodCalls(qualifier)) {
|
||||
final PsiVariable variable = (PsiVariable)object;
|
||||
addToArrayConversion(element, prefix,
|
||||
"new " + componentType.getCanonicalText() +
|
||||
@@ -303,16 +298,10 @@ public class ReferenceExpressionCompletionContributor extends ExpressionSmartCom
|
||||
return qualifier == null ? "" : qualifier.getText() + ".";
|
||||
}
|
||||
|
||||
private static boolean containsMethodCalls(@Nullable final PsiElement qualifier) {
|
||||
if (qualifier == null) return false;
|
||||
if (qualifier instanceof PsiMethodCallExpression) return true;
|
||||
return containsMethodCalls(getQualifier(qualifier));
|
||||
}
|
||||
|
||||
private static void addChainedCallVariants(final PsiElement place, final LookupElement qualifierItem,
|
||||
final CompletionResultSet result,
|
||||
PsiType qualifierType,
|
||||
final PsiType expectedType) throws IncorrectOperationException {
|
||||
final PsiType expectedType, CompletionParameters parameters) throws IncorrectOperationException {
|
||||
final PsiElementFactory elementFactory = JavaPsiFacade.getInstance(place.getProject()).getElementFactory();
|
||||
final String typeText = qualifierType instanceof PsiEllipsisType ? ((PsiEllipsisType)qualifierType).getComponentType().getCanonicalText() + "[]" : qualifierType.getCanonicalText();
|
||||
final JavaCodeFragment block = elementFactory.createCodeBlockCodeFragment(typeText + " xxx;xxx.xxx;", place, false);
|
||||
@@ -324,7 +313,7 @@ public class ReferenceExpressionCompletionContributor extends ExpressionSmartCom
|
||||
final PsiReferenceExpression mockRef = (PsiReferenceExpression) expressionStatement.getExpression();
|
||||
|
||||
final ElementFilter filter = getReferenceFilter(place, false, true);
|
||||
for (final LookupElement item : JavaSmartCompletionContributor.completeReference(place, mockRef, filter, false)) {
|
||||
for (final LookupElement item : JavaSmartCompletionContributor.completeReference(place, mockRef, filter, false, parameters)) {
|
||||
if (shoudChain(place, qualifierType, expectedType, item)) {
|
||||
result.addElement(JavaChainLookupElement.chainElements(qualifierItem, item));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user