IDEA-122362 'getClass()' should be suggested in smart completion if Class<? extends SomeAncestorOfCurrentClass> is expected

This commit is contained in:
peter
2014-04-21 18:12:35 +02:00
parent 1a34573547
commit 094f040cc5
6 changed files with 63 additions and 25 deletions

View File

@@ -144,10 +144,8 @@ public class PreferByKindWeigher extends LookupElementWeigher {
}
}
if (myCompletionType == CompletionType.SMART) {
if (object instanceof PsiLocalVariable || object instanceof PsiParameter || object instanceof PsiThisExpression) {
return MyResult.localOrParameter;
}
if (object instanceof PsiLocalVariable || object instanceof PsiParameter || object instanceof PsiThisExpression) {
return MyResult.localOrParameter;
}
if (object instanceof String && item.getUserData(JavaCompletionUtil.SUPER_METHOD_PARAMETERS) == Boolean.TRUE) {

View File

@@ -25,6 +25,7 @@ import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.*;
import com.intellij.psi.filters.ElementFilter;
import com.intellij.psi.impl.light.LightMethodBuilder;
import com.intellij.psi.impl.source.resolve.JavaResolveUtil;
import com.intellij.psi.infos.CandidateInfo;
import com.intellij.psi.scope.BaseScopeProcessor;
@@ -100,14 +101,11 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
if (qualifier instanceof PsiSuperExpression) {
final PsiJavaCodeReferenceElement qSuper = ((PsiSuperExpression)qualifier).getQualifier();
if (qSuper == null) {
myQualifierClass = JavaResolveUtil.getContextClass( myElement);
myQualifierClass = JavaResolveUtil.getContextClass(myElement);
} else {
final PsiElement target = qSuper.resolve();
myQualifierClass = target instanceof PsiClass ? (PsiClass)target : null;
}
if (myQualifierClass != null) {
myQualifierType = JavaPsiFacade.getInstance(element.getProject()).getElementFactory().createType(myQualifierClass);
}
}
else if (qualifier != null) {
setQualifierType(qualifier.getType());
@@ -117,8 +115,13 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
myQualifierClass = (PsiClass)target;
}
}
} else {
myQualifierClass = JavaResolveUtil.getContextClass(myElement);
}
}
if (myQualifierClass != null && myQualifierType == null) {
myQualifierType = JavaPsiFacade.getElementFactory(element.getProject()).createType(myQualifierClass);
}
if (myOptions.checkInitialized) {
myNonInitializedFields.addAll(getNonInitializedFields(element));
@@ -219,6 +222,19 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
return true;
}
if (element instanceof PsiMethod) {
PsiMethod method = (PsiMethod)element;
if (PsiTypesUtil.isGetClass(method) && PsiUtil.isLanguageLevel5OrHigher(myElement)) {
PsiType patchedType = PsiTypesUtil.createJavaLangClassType(myElement, myQualifierType, false);
if (patchedType != null) {
element = new LightMethodBuilder(element.getManager(), method.getName()).
addModifier(PsiModifier.PUBLIC).
setMethodReturnType(patchedType).
setContainingClass(method.getContainingClass());
}
}
}
if (satisfies(element, state) && isAccessible(element)) {
CompletionElement element1 = new CompletionElement(element, state.get(PsiSubstitutor.KEY));
if (myResultNames.add(element1.getUniqueId())) {
@@ -288,7 +304,9 @@ public class JavaCompletionProcessor extends BaseScopeProcessor implements Eleme
if (!(element instanceof PsiMember)) return true;
PsiMember member = (PsiMember)element;
return JavaPsiFacade.getInstance(element.getProject()).getResolveHelper().isAccessible(member, member.getModifierList(), myElement, myQualifierClass, myDeclarationHolder);
PsiClass accessObjectClass = member instanceof PsiClass ? null : myQualifierClass;
return JavaPsiFacade.getInstance(element.getProject()).getResolveHelper().isAccessible(member, member.getModifierList(), myElement,
accessObjectClass, myDeclarationHolder);
}
public void setCompletionElements(@NotNull Object[] elements) {

View File

@@ -22,7 +22,6 @@ import com.intellij.openapi.util.Condition;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.containers.HashMap;
import gnu.trove.THashMap;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -151,9 +150,7 @@ public class PsiTypesUtil {
@Nullable Condition<IElementType> condition,
@NotNull LanguageLevel languageLevel) {
//JLS3 15.8.2
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_5) &&
GET_CLASS_METHOD.equals(method.getName()) &&
CommonClassNames.JAVA_LANG_OBJECT.equals(method.getContainingClass().getQualifiedName())) {
if (languageLevel.isAtLeast(LanguageLevel.JDK_1_5) && isGetClass(method)) {
PsiExpression qualifier = methodExpression.getQualifierExpression();
PsiType qualifierType = null;
final Project project = call.getProject();
@@ -169,18 +166,28 @@ public class PsiTypesUtil {
qualifierType = JavaPsiFacade.getInstance(project).getElementFactory().createType((PsiClass)parent.getPsi());
}
}
if (qualifierType != null) {
PsiClass javaLangClass = JavaPsiFacade.getInstance(project).findClass(CommonClassNames.JAVA_LANG_CLASS, call.getResolveScope());
if (javaLangClass != null && javaLangClass.getTypeParameters().length == 1) {
Map<PsiTypeParameter, PsiType> map = new HashMap<PsiTypeParameter, PsiType>();
map.put(javaLangClass.getTypeParameters()[0], PsiWildcardType.createExtends(call.getManager(), qualifierType));
PsiSubstitutor substitutor = JavaPsiFacade.getInstance(project).getElementFactory().createSubstitutor(map);
final PsiClassType classType = JavaPsiFacade.getInstance(project).getElementFactory()
.createType(javaLangClass, substitutor, languageLevel);
final PsiElement parent = call.getParent();
return parent instanceof PsiReferenceExpression && parent.getParent() instanceof PsiMethodCallExpression || parent instanceof PsiExpressionList
? PsiUtil.captureToplevelWildcards(classType, methodExpression) : classType;
}
PsiElement parent = call.getParent();
boolean captureTopLevelWildcards = parent instanceof PsiReferenceExpression && parent.getParent() instanceof PsiMethodCallExpression ||
parent instanceof PsiExpressionList;
return createJavaLangClassType(methodExpression, qualifierType, captureTopLevelWildcards);
}
return null;
}
public static boolean isGetClass(PsiMethod method) {
return GET_CLASS_METHOD.equals(method.getName()) && CommonClassNames.JAVA_LANG_OBJECT.equals(method.getContainingClass().getQualifiedName());
}
@Nullable
public static PsiType createJavaLangClassType(@NotNull PsiElement context, @Nullable PsiType qualifierType, boolean captureTopLevelWildcards) {
if (qualifierType != null) {
JavaPsiFacade facade = JavaPsiFacade.getInstance(context.getProject());
PsiClass javaLangClass = facade.findClass(CommonClassNames.JAVA_LANG_CLASS, context.getResolveScope());
if (javaLangClass != null && javaLangClass.getTypeParameters().length == 1) {
PsiSubstitutor substitutor = PsiSubstitutor.EMPTY.
put(javaLangClass.getTypeParameters()[0], PsiWildcardType.createExtends(context.getManager(), qualifierType));
final PsiClassType classType = facade.getElementFactory().createType(javaLangClass, substitutor, PsiUtil.getLanguageLevel(context));
return captureTopLevelWildcards ? PsiUtil.captureToplevelWildcards(classType, context) : classType;
}
}
return null;

View File

@@ -0,0 +1,7 @@
class A {
}
class B extends A {
void m() {
Class<? extends A> c = getClass();<caret>
}
}

View File

@@ -0,0 +1,7 @@
class A {
}
class B extends A {
void m() {
Class<? extends A> c = g<caret>
}
}

View File

@@ -1022,6 +1022,7 @@ public class SmartTypeCompletionTest extends LightFixtureCompletionTestCase {
public void testDuplicateMembersFromSuperClass() throws Throwable { doTest(); }
public void testInnerAfterNew() throws Throwable { doTest(); }
public void testEverythingInStringConcatenation() throws Throwable { doTest(); }
public void testGetClassWhenClassExpected() { doTest(); }
public void testMemberImportStatically() {
configureByTestName();