autoimport not completed generic reference of the kind arraylist<>

This commit is contained in:
Alexey Kudravtsev
2010-10-28 13:12:24 +04:00
parent 6d2e8a3d46
commit 095774c01f
8 changed files with 180 additions and 106 deletions
@@ -1337,12 +1337,11 @@ public class HighlightUtil {
}
@Nullable
public static HighlightInfo checkMemberReferencedBeforeConstructorCalled(PsiElement expression) {
public static HighlightInfo checkMemberReferencedBeforeConstructorCalled(PsiElement expression, PsiElement resolved) {
PsiClass referencedClass;
@NonNls String resolvedName;
PsiType type;
if (expression instanceof PsiJavaCodeReferenceElement) {
PsiElement resolved = ((PsiJavaCodeReferenceElement)expression).advancedResolve(true).getElement();
// redirected ctr
if (PsiKeyword.THIS.equals(((PsiJavaCodeReferenceElement)expression).getReferenceName())
&& resolved instanceof PsiMethod
@@ -1838,7 +1837,7 @@ public class HighlightUtil {
PsiElement refName = ref.getReferenceNameElement();
if (!(refName instanceof PsiIdentifier) && !(refName instanceof PsiKeyword)) return null;
HighlightInfo highlightInfo = checkMemberReferencedBeforeConstructorCalled(ref);
HighlightInfo highlightInfo = checkMemberReferencedBeforeConstructorCalled(ref, resolved);
if (highlightInfo != null) return highlightInfo;
PsiElement refParent = ref.getParent();
@@ -418,9 +418,31 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
}
myHolder.add(HighlightNamesUtil.highlightMethodName(method, identifier, true, colorsScheme));
}
else {
visitParentReference(parent);
}
super.visitIdentifier(identifier);
}
private void visitParentReference(PsiElement parent) {
if (parent instanceof PsiJavaCodeReferenceElement && !(parent.getParent() instanceof PsiJavaCodeReferenceElement) &&
!((PsiJavaCodeReferenceElement)parent).isQualified()) {
PsiJavaCodeReferenceElement ref = (PsiJavaCodeReferenceElement)parent;
JavaResolveResult result;
try {
result = ref.advancedResolve(true);
}
catch (IndexNotReadyException e) {
return;
}
PsiElement resolved = result.getElement();
myHolder.add(HighlightUtil.checkReference(ref, result, resolved));
if (myRefCountHolder != null) {
myRefCountHolder.registerReference(ref, result);
}
}
}
@Override public void visitImportStatement(PsiImportStatement statement) {
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkSingleImportClassConflict(statement, mySingleImportedClasses));
}
@@ -480,28 +502,32 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
@Override public void visitKeyword(PsiKeyword keyword) {
super.visitKeyword(keyword);
PsiElement parent = keyword.getParent();
String text = keyword.getText();
if (parent instanceof PsiModifierList) {
PsiModifierList psiModifierList = (PsiModifierList)parent;
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkNotAllowedModifier(keyword, psiModifierList));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkIllegalModifierCombination(keyword, psiModifierList));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkPublicClassInRightFile(keyword, psiModifierList));
if (PsiModifier.ABSTRACT.equals(keyword.getText()) && psiModifierList.getParent() instanceof PsiMethod) {
if (PsiModifier.ABSTRACT.equals(text) && psiModifierList.getParent() instanceof PsiMethod) {
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightMethodUtil.checkAbstractMethodInConcreteClass((PsiMethod)psiModifierList.getParent(), keyword));
}
}
}
else if (keyword.getText().equals(PsiKeyword.CONTINUE) && parent instanceof PsiContinueStatement) {
else if (PsiKeyword.CONTINUE.equals(text) && parent instanceof PsiContinueStatement) {
PsiContinueStatement statement = (PsiContinueStatement)parent;
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkContinueOutsideLoop(statement));
}
else if (keyword.getText().equals(PsiKeyword.BREAK) && parent instanceof PsiBreakStatement) {
else if (PsiKeyword.BREAK.equals(text) && parent instanceof PsiBreakStatement) {
PsiBreakStatement statement = (PsiBreakStatement)parent;
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkBreakOutsideLoop(statement));
}
else if (PsiKeyword.INTERFACE.equals(keyword.getText()) && parent instanceof PsiClass) {
else if (PsiKeyword.INTERFACE.equals(text) && parent instanceof PsiClass) {
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkInterfaceCannotBeLocal((PsiClass)parent));
}
else {
visitParentReference(parent);
}
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkStaticDeclarationInInnerClass(keyword));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkIllegalVoidType(keyword));
@@ -719,11 +745,13 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
}
PsiElement resolved = result.getElement();
PsiElement parent = ref.getParent();
if (myRefCountHolder != null) {
myRefCountHolder.registerReference(ref, result);
}
myHolder.add(HighlightUtil.checkReference(ref, result, resolved));
if (parent instanceof PsiJavaCodeReferenceElement || ref.isQualified()) {
if (myRefCountHolder != null) {
myRefCountHolder.registerReference(ref, result);
}
myHolder.add(HighlightUtil.checkReference(ref, result, resolved));
}
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkAbstractInstantiation(ref));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightClassUtil.checkExtendsDuplicate(ref, resolved));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkExceptionAlreadyCaught(ref, resolved));
@@ -852,7 +880,9 @@ public class HighlightVisitorImpl extends JavaElementVisitor implements Highligh
@Override public void visitThisExpression(PsiThisExpression expr) {
myHolder.add(HighlightUtil.checkThisOrSuperExpressionInIllegalContext(expr, expr.getQualifier()));
if (!myHolder.hasErrorResults()) myHolder.add(HighlightUtil.checkMemberReferencedBeforeConstructorCalled(expr));
if (!myHolder.hasErrorResults()) {
myHolder.add(HighlightUtil.checkMemberReferencedBeforeConstructorCalled(expr, null));
}
if (!myHolder.hasErrorResults()) {
visitExpression(expr);
}
@@ -31,7 +31,6 @@ import com.intellij.psi.util.ClassUtil;
import org.jetbrains.annotations.NotNull;
public class ImportClassFix extends ImportClassFixBase<PsiJavaCodeReferenceElement> {
public ImportClassFix(@NotNull PsiJavaCodeReferenceElement element) {
super(element);
}
@@ -42,7 +41,12 @@ public class ImportClassFix extends ImportClassFixBase<PsiJavaCodeReferenceEleme
}
@Override
protected void bindReference(PsiJavaCodeReferenceElement ref, PsiClass targetClass) {
protected PsiElement getReferenceNameElement(PsiJavaCodeReferenceElement reference) {
return reference.getReferenceNameElement();
}
@Override
protected void bindReference(PsiReference ref, PsiClass targetClass) {
if (ref instanceof PsiImportStaticReferenceElement) {
((PsiImportStaticReferenceElement)ref).bindToTargetClass(targetClass);
}
@@ -64,6 +64,7 @@ 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);
@@ -208,8 +209,10 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
}
}
private static boolean isCaretNearRef(Editor editor, PsiElement ref) {
TextRange range = ref.getTextRange();
private boolean isCaretNearRef(Editor editor, T ref) {
PsiElement nameElement = getReferenceNameElement(ref);
if (nameElement == null) return false;
TextRange range = nameElement.getTextRange();
int offset = editor.getCaretModel().getOffset();
return offset == range.getEndOffset();
@@ -230,7 +233,7 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
});
}
protected void bindReference(T reference, PsiClass targetClass) {
protected void bindReference(PsiReference reference, PsiClass targetClass) {
reference.bindToElement(targetClass);
}
@@ -238,7 +241,7 @@ public abstract class ImportClassFixBase<T extends PsiElement & PsiReference> im
return new AddImportAction(project, myRef, editor, classes) {
@Override
protected void bindReference(PsiReference ref, PsiClass targetClass) {
ImportClassFixBase.this.bindReference((T)ref, targetClass);
ImportClassFixBase.this.bindReference(ref, targetClass);
}
};
}
@@ -2,45 +2,49 @@
import java.io.*;
import java.net.*;
class a {
a(int i) {}
a(a a) {}
class A {
A(int i) {}
A(A a) {}
int f() { return 0; }
int fi;
}
class b extends a {
class B extends A {
int bi;
b(int h) {
super(<error descr="Cannot reference 'b.bi' before supertype constructor has been called">bi</error>);
B(int h) {
super(<error descr="Cannot reference 'B.bi' before supertype constructor has been called">bi</error>);
}
b() {
this(<error descr="Cannot reference 'b.bi' before supertype constructor has been called">bi</error>);
B() {
this(<error descr="Cannot reference 'B.bi' before supertype constructor has been called">bi</error>);
}
b(String s) {
super(<error descr="Cannot reference 'b.db' before supertype constructor has been called">db</error>(1) );
B(String s) {
super(<error descr="Cannot reference 'B.db' before supertype constructor has been called">db</error>(1) );
}
b(int i, int j) {
super(<error descr="Cannot reference 'a.f' before supertype constructor has been called">f</error>());
B(int i, int j) {
super(<error descr="Cannot reference 'A.f' before supertype constructor has been called">f</error>());
}
b(int i, int j, int k) {
super(<error descr="Cannot reference 'a.f' before supertype constructor has been called">super.f</error>());
B(int i, int j, int k) {
super(<error descr="Cannot reference 'A.f' before supertype constructor has been called">super.f</error>());
}
b(String s, int i) {
B(String s, int i) {
super(s.length());
}
b(int s, int i, char j) {
super(<error descr="Cannot reference 'a.fi' before supertype constructor has been called">super.fi</error> );
B(int s, int i, char j) {
super(<error descr="Cannot reference 'A.fi' before supertype constructor has been called">super.fi</error> );
}
b(double d) {
super(new <error descr="Cannot reference 'inner' before supertype constructor has been called">inner</error>() );
B(double d) {
super(new <error descr="Cannot reference 'Inner' before supertype constructor has been called">Inner</error>() );
}
class Inner extends A {
Inner(){
super(1);
}
}
class inner extends a {inner(){super(1);}}
int db(int j) {
return 0;
@@ -48,54 +52,51 @@ class b extends a {
}
class enc {
class Enc {
int ienc;
class bb extends a {
class Bb extends A {
int ibb;
bb() { super(ienc); }
bb(int i) {
Bb() { super(ienc); }
Bb(int i) {
super(i);
}
bb(int i, int j) {
super(<error descr="Cannot reference 'bb.this' before supertype constructor has been called">enc.bb.this</error>.ibb );
Bb(int i, int j) {
super(<error descr="Cannot reference 'Bb.this' before supertype constructor has been called">Enc.Bb.this</error>.ibb );
}
bb(int i, String s) {
super(enc.this.ienc);
Bb(int i, String s) {
super(Enc.this.ienc);
}
bb(int i, char j) {
Bb(int i, char j) {
super(<error descr="Cannot reference 'this' before supertype constructor has been called">this</error> );
}
}
enc() {
this(new <error descr="Cannot reference 'bb' before supertype constructor has been called">bb</error>());
Enc() {
this(new <error descr="Cannot reference 'Bb' before supertype constructor has been called">Bb</error>());
}
enc(bb b) {}
Enc(Bb b) {}
}
// static are OK
class c2 extends a {
class C2 extends A {
static final int fi = 4;
c2() {
C2() {
super(fi);
}
c2(int i) {
C2(int i) {
super(sf());
}
static int sf() { return 0; }
c2(int i, int j) {
super(new sc().i);
C2(int i, int j) {
super(new Sc().i);
}
static class sc {
static class Sc {
int i;
}
}
interface Callback {
@@ -111,7 +112,6 @@ class Base {
}
class YellinBug extends Base {
public YellinBug() {
super(new Callback() {
@@ -12,6 +12,7 @@ import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.command.impl.UndoManagerImpl;
import com.intellij.openapi.command.undo.UndoManager;
import com.intellij.openapi.fileEditor.impl.LoadTextUtil;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.projectRoots.Sdk;
@@ -99,44 +100,44 @@ public class ImportHelperTest extends DaemonAnalyzerTestCase {
assertEmpty(filter(doHighlighting(), HighlightSeverity.ERROR));
CommandProcessor.getInstance().executeCommand(
getProject(), new Runnable() {
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
try {
CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()).clone();
settings.LAYOUT_STATIC_IMPORTS_SEPARATELY = true;
PackageEntryTable table = new PackageEntryTable();
table.addEntry(PackageEntry.ALL_OTHER_IMPORTS_ENTRY);
table.addEntry(PackageEntry.BLANK_LINE_ENTRY);
table.addEntry(new PackageEntry(false, "javax", true));
table.addEntry(new PackageEntry(false, "java", true));
table.addEntry(PackageEntry.BLANK_LINE_ENTRY);
table.addEntry(new PackageEntry(true, "java", true));
table.addEntry(PackageEntry.BLANK_LINE_ENTRY);
table.addEntry(PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY);
settings.IMPORT_LAYOUT_TABLE.copyFrom(table);
CodeStyleSettingsManager.getInstance(getProject()).setTemporarySettings(settings);
@Override
public void run() {
ApplicationManager.getApplication().runWriteAction(new Runnable() {
@Override
public void run() {
try {
JavaCodeStyleManager.getInstance(getProject()).optimizeImports(file);
}
finally {
CodeStyleSettingsManager.getInstance(getProject()).dropTemporarySettings();
}
assertOrder(file, "java.awt.*", "java.util.Map", "static java.lang.Math.max", "static java.lang.Math.min", "static javax.swing.SwingConstants.CENTER");
CodeStyleSettings settings = CodeStyleSettingsManager.getSettings(getProject()).clone();
settings.LAYOUT_STATIC_IMPORTS_SEPARATELY = true;
PackageEntryTable table = new PackageEntryTable();
table.addEntry(PackageEntry.ALL_OTHER_IMPORTS_ENTRY);
table.addEntry(PackageEntry.BLANK_LINE_ENTRY);
table.addEntry(new PackageEntry(false, "javax", true));
table.addEntry(new PackageEntry(false, "java", true));
table.addEntry(PackageEntry.BLANK_LINE_ENTRY);
table.addEntry(new PackageEntry(true, "java", true));
table.addEntry(PackageEntry.BLANK_LINE_ENTRY);
table.addEntry(PackageEntry.ALL_OTHER_STATIC_IMPORTS_ENTRY);
settings.IMPORT_LAYOUT_TABLE.copyFrom(table);
CodeStyleSettingsManager.getInstance(getProject()).setTemporarySettings(settings);
try {
JavaCodeStyleManager.getInstance(getProject()).optimizeImports(file);
}
finally {
CodeStyleSettingsManager.getInstance(getProject()).dropTemporarySettings();
}
assertOrder(file, "java.awt.*", "java.util.Map", "static java.lang.Math.max", "static java.lang.Math.min", "static javax.swing.SwingConstants.CENTER");
}
catch (Throwable e) {
LOG.error(e);
}
}
catch (Throwable e) {
LOG.error(e);
}
}
});
}
}, "", "");
});
}
}, "", "");
}
@Override
@@ -149,8 +150,8 @@ public class ImportHelperTest extends DaemonAnalyzerTestCase {
ImportHelper importHelper = new ImportHelper(settings);
PsiClass psiClass = JavaPsiFacade.getInstance(getProject()).findClass(fqn, GlobalSearchScope.allScope(getProject()));
boolean b = importHelper.addImport(file, psiClass);
assertTrue(b);
boolean b = importHelper.addImport(file, psiClass);
assertTrue(b);
assertOrder(file, expectedOrder);
}
@@ -199,8 +200,8 @@ public class ImportHelperTest extends DaemonAnalyzerTestCase {
try {
CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = true;
configureByText(StdFileTypes.JAVA, "class X { ArrayList<caret> c; }");
((UndoManagerImpl)UndoManagerImpl.getInstance(getProject())).flushCurrentCommandMerger();
((UndoManagerImpl)UndoManagerImpl.getInstance(getProject())).clearUndoRedoQueueInTests(getFile().getVirtualFile());
((UndoManagerImpl)UndoManager.getInstance(getProject())).flushCurrentCommandMerger();
((UndoManagerImpl)UndoManager.getInstance(getProject())).clearUndoRedoQueueInTests(getFile().getVirtualFile());
type(" ");
backspace();
@@ -232,8 +233,8 @@ public class ImportHelperTest extends DaemonAnalyzerTestCase {
try {
CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = true;
configureByText(StdFileTypes.JAVA, "class X { <caret>ArrayList c = new ArrayList(); }");
((UndoManagerImpl)UndoManagerImpl.getInstance(getProject())).flushCurrentCommandMerger();
((UndoManagerImpl)UndoManagerImpl.getInstance(getProject())).clearUndoRedoQueueInTests(getFile().getVirtualFile());
((UndoManagerImpl)UndoManager.getInstance(getProject())).flushCurrentCommandMerger();
((UndoManagerImpl)UndoManager.getInstance(getProject())).clearUndoRedoQueueInTests(getFile().getVirtualFile());
type(" ");
backspace();
@@ -290,8 +291,8 @@ public class ImportHelperTest extends DaemonAnalyzerTestCase {
public void testAutoImportWorks() throws Throwable {
@NonNls final String text = "class S { JFrame x; <caret> }";
configureByText(StdFileTypes.JAVA, text);
((UndoManagerImpl)UndoManagerImpl.getInstance(getProject())).flushCurrentCommandMerger();
((UndoManagerImpl)UndoManagerImpl.getInstance(getProject())).clearUndoRedoQueueInTests(getFile().getVirtualFile());
((UndoManagerImpl)UndoManager.getInstance(getProject())).flushCurrentCommandMerger();
((UndoManagerImpl)UndoManager.getInstance(getProject())).clearUndoRedoQueueInTests(getFile().getVirtualFile());
assertFalse(((DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(getProject())).canChangeFileSilently(getFile()));
@@ -306,6 +307,36 @@ public class ImportHelperTest extends DaemonAnalyzerTestCase {
assertFalse(((DaemonCodeAnalyzerImpl)DaemonCodeAnalyzer.getInstance(getProject())).canChangeFileSilently(getFile()));//CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = old;
}
@CanChangeDocumentDuringHighlighting
@DoNotWrapInCommand
public void testAutoImportOfGenericReference() throws Throwable {
@NonNls final String text = "class S {{ new ArrayList<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);
((UndoManagerImpl)UndoManager.getInstance(getProject())).flushCurrentCommandMerger();
((UndoManagerImpl)UndoManager.getInstance(getProject())).clearUndoRedoQueueInTests(getFile().getVirtualFile());
type(" ");
backspace();
try {
doHighlighting();
//caret is too close
assertEmpty(((PsiJavaFile)getFile()).getImportList().getAllImportStatements());
caretRight();
doHighlighting();
assertNotSame(0, ((PsiJavaFile)getFile()).getImportList().getAllImportStatements().length);
}
finally {
CodeInsightSettings.getInstance().ADD_UNAMBIGIOUS_IMPORTS_ON_THE_FLY = old;
}
}
@CanChangeDocumentDuringHighlighting
@DoNotWrapInCommand
public void testAutoOptimizeUnresolvedImports() throws Throwable {
@@ -628,6 +628,12 @@ public abstract class CodeInsightTestCase extends PsiTestCase {
action.actionPerformed(getEditor(), c, DataManager.getInstance().getDataContext());
}
protected void caretRight() {
EditorActionManager actionManager = EditorActionManager.getInstance();
EditorActionHandler action = actionManager.getActionHandler(IdeActions.ACTION_EDITOR_MOVE_CARET_RIGHT);
action.execute(getEditor(), DataManager.getInstance().getDataContext());
}
protected void type(@NonNls String s) {
for (char c : s.toCharArray()) {
type(c);
@@ -19,6 +19,7 @@ package org.jetbrains.plugins.groovy.annotator.intentions;
import com.intellij.codeInsight.daemon.impl.quickfix.ImportClassFixBase;
import com.intellij.openapi.util.Comparing;
import com.intellij.psi.PsiClass;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.plugins.groovy.lang.psi.GrReferenceElement;
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile;
@@ -34,13 +35,13 @@ public class GroovyAddImportAction extends ImportClassFixBase<GrReferenceElement
}
@Override
protected void bindReference(GrReferenceElement ref, PsiClass targetClass) {
ref.bindToElement(targetClass);
protected String getReferenceName(GrReferenceElement reference) {
return reference.getReferenceName();
}
@Override
protected String getReferenceName(GrReferenceElement reference) {
return reference.getReferenceName();
protected PsiElement getReferenceNameElement(GrReferenceElement reference) {
return reference.getReferenceNameElement();
}
@Override