IDEA-87003

This commit is contained in:
Alexey Kudravtsev
2012-06-19 13:02:05 +04:00
parent 0d421564e3
commit 6ed387d394
7 changed files with 94 additions and 16 deletions
@@ -23,6 +23,7 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiJavaCodeReferenceElement;
import com.intellij.psi.PsiReference;
import org.jetbrains.annotations.NotNull;
import java.util.List;
@@ -56,4 +57,19 @@ public class JavaReferenceImporter implements ReferenceImporter {
}
return false;
}
@Override
public boolean autoImportReferenceAt(@NotNull Editor editor, @NotNull PsiFile file, int offset) {
if (!file.getViewProvider().getLanguages().contains(StdLanguages.JAVA)) return false;
PsiReference element = file.findReferenceAt(offset);
if (element instanceof PsiJavaCodeReferenceElement) {
PsiJavaCodeReferenceElement ref = (PsiJavaCodeReferenceElement)element;
if (ref.multiResolve(true).length == 0) {
new ImportClassFix(ref).doFix(editor, false, true);
return true;
}
}
return false;
}
}
@@ -36,12 +36,12 @@ public class ImportClassFix extends ImportClassFixBase<PsiJavaCodeReferenceEleme
}
@Override
protected String getReferenceName(PsiJavaCodeReferenceElement reference) {
protected String getReferenceName(@NotNull PsiJavaCodeReferenceElement reference) {
return reference.getReferenceName();
}
@Override
protected PsiElement getReferenceNameElement(PsiJavaCodeReferenceElement reference) {
protected PsiElement getReferenceNameElement(@NotNull PsiJavaCodeReferenceElement reference) {
return reference.getReferenceNameElement();
}
@@ -56,7 +56,7 @@ public class ImportClassFix extends ImportClassFixBase<PsiJavaCodeReferenceEleme
}
@Override
protected boolean hasTypeParameters(PsiJavaCodeReferenceElement reference) {
protected boolean hasTypeParameters(@NotNull PsiJavaCodeReferenceElement reference) {
final PsiReferenceParameterList refParameters = reference.getParameterList();
return refParameters != null && refParameters.getTypeParameterElements().length > 0;
}
@@ -97,8 +97,9 @@ public class ImportClassFix extends ImportClassFixBase<PsiJavaCodeReferenceEleme
@Override
protected String getRequiredMemberName(PsiJavaCodeReferenceElement reference) {
if (reference.getParent() instanceof PsiJavaCodeReferenceElement) {
return ((PsiJavaCodeReferenceElement)reference.getParent()).getReferenceName();
PsiElement parent = reference.getParent();
if (parent instanceof PsiJavaCodeReferenceElement) {
return ((PsiJavaCodeReferenceElement)parent).getReferenceName();
}
return super.getRequiredMemberName(reference);
@@ -72,10 +72,9 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
}
@Nullable
protected abstract String getReferenceName(T reference);
protected abstract PsiElement getReferenceNameElement(T reference);
protected abstract boolean hasTypeParameters(T reference);
protected abstract String getReferenceName(@NotNull T reference);
protected abstract PsiElement getReferenceNameElement(@NotNull T reference);
protected abstract boolean hasTypeParameters(@NotNull T reference);
@NotNull
public List<PsiClass> getClassesToImport() {
@@ -145,7 +144,7 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
POPUP_NOT_SHOWN
}
public Result doFix(@NotNull final Editor editor, boolean doShow, final boolean allowCaretNearRef) {
public Result doFix(@NotNull final Editor editor, boolean allowPopup, final boolean allowCaretNearRef) {
List<PsiClass> classesToImport = getClassesToImport();
if (classesToImport.isEmpty()) return Result.POPUP_NOT_SHOWN;
@@ -194,7 +193,7 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
return Result.CLASS_AUTO_IMPORTED;
}
if (doShow && canImportHere) {
if (allowPopup && canImportHere) {
String hintText = ShowAutoImportPass.getMessage(classes.length > 1, classes[0].getQualifiedName());
if (!ApplicationManager.getApplication().isUnitTestMode() && !HintManager.getInstance().hasShownHintsThatWillHideByOtherHint(true)) {
HintManager.getInstance().showQuestionHint(editor, hintText, myRef.getTextOffset(),
@@ -261,7 +260,7 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
}
}
private boolean isCaretNearRef(Editor editor, T ref) {
private boolean isCaretNearRef(@NotNull Editor editor, @NotNull T ref) {
PsiElement nameElement = getReferenceNameElement(ref);
if (nameElement == null) return false;
TextRange range = nameElement.getTextRange();
@@ -5,6 +5,7 @@ import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl;
import com.intellij.codeInsight.daemon.impl.HighlightInfo;
import com.intellij.codeInsight.daemon.impl.quickfix.ImportClassFix;
import com.intellij.codeInsight.daemon.impl.quickfix.ImportClassFixBase;
import com.intellij.codeInsight.generation.actions.CommentByBlockCommentAction;
import com.intellij.codeInspection.LocalInspectionTool;
import com.intellij.codeInspection.unusedImport.UnusedImportLocalInspection;
import com.intellij.openapi.application.ApplicationManager;
@@ -306,6 +307,31 @@ public class ImportHelperTest extends DaemonAnalyzerTestCase {
}
}
public void testAutoImportAfterUncomment() throws Throwable {
@NonNls String text = "class S { /*ArrayList l; HashMap h; <caret>*/ }";
configureByText(StdFileTypes.JAVA, text);
boolean old = CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY;
CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = true;
DaemonCodeAnalyzerSettings.getInstance().setImportHintEnabled(true);
try {
doHighlighting();
assertEmpty(((PsiJavaFile)getFile()).getImportList().getAllImportStatements());
CommentByBlockCommentAction action = new CommentByBlockCommentAction();
action.actionPerformedImpl(getProject(), getEditor());
assertEmpty(highlightErrors());
assertNotSame(0, ((PsiJavaFile)getFile()).getImportList().getAllImportStatements().length);
}
finally {
CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = old;
}
}
public void testAutoImportWorks() throws Throwable {
@NonNls final String text = "class S { JFrame x; <caret> }";
configureByText(StdFileTypes.JAVA, text);
@@ -325,6 +351,7 @@ public class ImportHelperTest extends DaemonAnalyzerTestCase {
assertFalse(((DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(getProject())).canChangeFileSilently(getFile()));//CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = old;
}
public void testAutoImportOfGenericReference() throws Throwable {
@NonNls final String text = "class S {{ new ArrayList<caret><> }}";
configureByText(StdFileTypes.JAVA, text);
@@ -28,4 +28,5 @@ public interface ReferenceImporter {
ExtensionPointName<ReferenceImporter> EP_NAME = ExtensionPointName.create("com.intellij.referenceImporter");
boolean autoImportReferenceAtCursor(@NotNull Editor editor, @NotNull PsiFile file);
boolean autoImportReferenceAt(@NotNull Editor editor, @NotNull PsiFile file, int offset);
}
@@ -17,16 +17,21 @@
package com.intellij.codeInsight.daemon.impl;
import com.intellij.codeHighlighting.TextEditorHighlightingPass;
import com.intellij.codeInsight.CodeInsightSettings;
import com.intellij.codeInsight.daemon.DaemonBundle;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzer;
import com.intellij.codeInsight.daemon.DaemonCodeAnalyzerSettings;
import com.intellij.codeInsight.daemon.ReferenceImporter;
import com.intellij.codeInsight.intention.IntentionAction;
import com.intellij.codeInspection.HintAction;
import com.intellij.lang.annotation.HighlightSeverity;
import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.keymap.KeymapUtil;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.project.Project;
@@ -70,9 +75,10 @@ public class ShowAutoImportPass extends TextEditorHighlightingPass {
Application application = ApplicationManager.getApplication();
application.assertIsDispatchThread();
if (!application.isUnitTestMode() && !myEditor.getContentComponent().hasFocus()) return;
int caretOffset = myEditor.getCaretModel().getOffset();
importUnambiguousImports(caretOffset);
List<HighlightInfo> visibleHighlights = getVisibleHighlights(myStartOffset, myEndOffset, myProject, myEditor);
int caretOffset = myEditor.getCaretModel().getOffset();
for (int i = visibleHighlights.size() - 1; i >= 0; i--) {
HighlightInfo info = visibleHighlights.get(i);
if (info.startOffset <= caretOffset && showAddImportHint(info)) return;
@@ -83,6 +89,33 @@ public class ShowAutoImportPass extends TextEditorHighlightingPass {
}
}
private void importUnambiguousImports(final int caretOffset) {
if (!DaemonCodeAnalyzerSettings.getInstance().isImportHintEnabled()) return;
if (!DaemonCodeAnalyzer.getInstance(myProject).isImportHintsEnabled(myFile)) return;
if (!CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY) return;
Document document = getDocument();
final List<HighlightInfo> infos = new ArrayList<HighlightInfo>();
DaemonCodeAnalyzerImpl.processHighlights(document, myProject, null, 0, document.getTextLength(), new Processor<HighlightInfo>() {
@Override
public boolean process(HighlightInfo info) {
if (!info.hasHint() || info.getSeverity() != HighlightSeverity.ERROR) {
return true;
}
if (TextRange.create(info.getActualStartOffset(), info.getActualEndOffset()).containsOffset(caretOffset)) return true;
infos.add(info);
return true;
}
});
ReferenceImporter[] importers = Extensions.getExtensions(ReferenceImporter.EP_NAME);
for (HighlightInfo info : infos) {
for(ReferenceImporter importer: importers) {
if (importer.autoImportReferenceAt(myEditor, myFile, info.getActualStartOffset())) break;
}
}
}
@NotNull
private static List<HighlightInfo> getVisibleHighlights(final int startOffset, final int endOffset, Project project, final Editor editor) {
final List<HighlightInfo> highlights = new ArrayList<HighlightInfo>();
@@ -21,6 +21,7 @@ import com.intellij.openapi.util.Comparing;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.PsiMember;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
import org.jetbrains.plugins.groovy.lang.psi.api.toplevel.imports.GrImportStatement;
@@ -35,17 +36,17 @@ public class GroovyAddImportAction extends ImportClassFixBase<GrReferenceElement
}
@Override
protected String getReferenceName(GrReferenceElement reference) {
protected String getReferenceName(@NotNull GrReferenceElement reference) {
return reference.getReferenceName();
}
@Override
protected PsiElement getReferenceNameElement(GrReferenceElement reference) {
protected PsiElement getReferenceNameElement(@NotNull GrReferenceElement reference) {
return reference.getReferenceNameElement();
}
@Override
protected boolean hasTypeParameters(GrReferenceElement reference) {
protected boolean hasTypeParameters(@NotNull GrReferenceElement reference) {
return reference.getTypeArguments().length > 0;
}