mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-94481 Groovy: Don't highlight as warning category methods of Class type invoked on class references
This commit is contained in:
+14
-6
@@ -72,6 +72,7 @@ import org.jetbrains.plugins.groovy.lang.psi.api.statements.typedef.members.*;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.api.types.GrCodeReferenceElement;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GrClosureType;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.GroovyPsiManager;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.PsiImplUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.signatures.GrClosureSignatureUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.GrReferenceResolveUtil;
|
||||
import org.jetbrains.plugins.groovy.lang.psi.impl.statements.expressions.TypesUtil;
|
||||
@@ -816,9 +817,13 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection {
|
||||
if (method instanceof GrGdkMethod && place instanceof GrReferenceExpression) {
|
||||
final PsiMethod staticMethod = ((GrGdkMethod)method).getStaticMethod();
|
||||
final PsiType qualifierType = inferQualifierTypeByPlace((GrReferenceExpression)place);
|
||||
|
||||
final GrExpression qualifier = PsiImplUtil.getRuntimeQualifier((GrReferenceExpression)place);
|
||||
|
||||
//check methods processed by @Category(ClassWhichProcessMethod) annotation
|
||||
if (qualifierType != null &&
|
||||
!GdkMethodUtil.isCategoryMethod(staticMethod, qualifierType, methodResolveResult.getSubstitutor()) &&
|
||||
!checkCategoryQualifier((GrReferenceExpression)place, staticMethod, methodResolveResult.getSubstitutor())) {
|
||||
!GdkMethodUtil.isCategoryMethod(staticMethod, qualifierType, qualifier, methodResolveResult.getSubstitutor()) &&
|
||||
!checkCategoryQualifier((GrReferenceExpression)place, qualifier, staticMethod, methodResolveResult.getSubstitutor())) {
|
||||
registerError(((GrReferenceExpression)place).getReferenceNameElement(), GroovyInspectionBundle
|
||||
.message("category.method.0.cannot.be.applied.to.1", method.getName(), qualifierType.getCanonicalText()));
|
||||
return false;
|
||||
@@ -861,13 +866,16 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean checkCategoryQualifier(GrReferenceExpression place, PsiMethod gdkMethod, PsiSubstitutor substitutor) {
|
||||
PsiClass categoryAnnotationOwner = inferCategoryAnnotationOwner(place, place.getQualifier());
|
||||
private static boolean checkCategoryQualifier(GrReferenceExpression place,
|
||||
GrExpression qualifier,
|
||||
PsiMethod gdkMethod,
|
||||
PsiSubstitutor substitutor) {
|
||||
PsiClass categoryAnnotationOwner = inferCategoryAnnotationOwner(place, qualifier);
|
||||
|
||||
if (categoryAnnotationOwner != null) {
|
||||
PsiClassType categoryType = GdkMethodUtil.getCategoryType(categoryAnnotationOwner);
|
||||
if (categoryType != null) {
|
||||
return GdkMethodUtil.isCategoryMethod(gdkMethod, categoryType, substitutor);
|
||||
return GdkMethodUtil.isCategoryMethod(gdkMethod, categoryType, qualifier, substitutor);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -877,7 +885,7 @@ public class GroovyAssignabilityCheckInspection extends BaseInspection {
|
||||
private static PsiClass inferCategoryAnnotationOwner(GrReferenceExpression place, GrExpression qualifier) {
|
||||
if (qualifier == null) {
|
||||
GrMethod container = PsiTreeUtil.getParentOfType(place, GrMethod.class, true, GrMember.class);
|
||||
if (container != null && !container.hasModifierProperty(PsiModifier.STATIC)) { //only instance classes can be qualified by category class
|
||||
if (container != null && !container.hasModifierProperty(PsiModifier.STATIC)) { //only instance methods can be qualified by category class
|
||||
return container.getContainingClass();
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2009 JetBrains s.r.o.
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -46,7 +46,7 @@ public class AccessorMethodReferencesSearcher extends QueryExecutorBase<PsiRefer
|
||||
final PsiMethod method = queryParameters.getMethod();
|
||||
|
||||
final String propertyName;
|
||||
if (GdkMethodUtil.isCategoryMethod(method, null, PsiSubstitutor.EMPTY)) {
|
||||
if (GdkMethodUtil.isCategoryMethod(method, null, null, PsiSubstitutor.EMPTY)) {
|
||||
final GrGdkMethod cat = GrGdkMethodImpl.createGdkMethod(method, false, null);
|
||||
propertyName = GroovyPropertyUtils.getPropertyName((PsiMethod)cat);
|
||||
}
|
||||
|
||||
@@ -16,15 +16,17 @@
|
||||
package org.jetbrains.plugins.groovy.lang.psi.util;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.NullableComputable;
|
||||
import com.intellij.openapi.util.Pair;
|
||||
import com.intellij.openapi.util.RecursionManager;
|
||||
import com.intellij.openapi.util.Trinity;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.scope.DelegatingScopeProcessor;
|
||||
import com.intellij.psi.scope.PsiScopeProcessor;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
import com.intellij.psi.util.InheritanceUtil;
|
||||
import com.intellij.psi.util.PsiModificationTracker;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
@@ -123,7 +125,7 @@ public class GdkMethodUtil {
|
||||
final DelegatingScopeProcessor delegate = new DelegatingScopeProcessor(processor) {
|
||||
@Override
|
||||
public boolean execute(@NotNull PsiElement element, ResolveState delegateState) {
|
||||
if (isCategoryMethod(element, null, null)) {
|
||||
if (element instanceof PsiMethod && isCategoryMethod((PsiMethod)element, null, null, null)) {
|
||||
PsiMethod method = (PsiMethod)element;
|
||||
return processor.execute(GrGdkMethodImpl.createGdkMethod(method, false, generateOriginInfo(method)), delegateState);
|
||||
}
|
||||
@@ -133,14 +135,6 @@ public class GdkMethodUtil {
|
||||
return categoryClass.processDeclarations(delegate, state, null, place);
|
||||
}
|
||||
|
||||
private static boolean acceptClass(@Nullable PsiType type, @NotNull PsiClass aClass) {
|
||||
if (!(type instanceof PsiClassType)) return false;
|
||||
|
||||
PsiClass resolved = ((PsiClassType)type).resolve();
|
||||
|
||||
return InheritanceUtil.isInheritorOrSelf(aClass, resolved, true);
|
||||
}
|
||||
|
||||
public static boolean withIteration(GrClosableBlock block, final PsiScopeProcessor processor) {
|
||||
GrMethodCall call = checkMethodCall(block, WITH);
|
||||
if (call == null) {
|
||||
@@ -217,16 +211,17 @@ public class GdkMethodUtil {
|
||||
for (GrStatement statement : statements) {
|
||||
if (statement == lastParent) break;
|
||||
|
||||
final Pair<PsiClassType, PsiClass> result = getMixinTypes(statement);
|
||||
final Trinity<PsiClassType, GrReferenceExpression, PsiClass> result = getMixinTypes(statement);
|
||||
|
||||
if (result != null) {
|
||||
final PsiClassType subjectType = result.first;
|
||||
final PsiClass mixin = result.second;
|
||||
final GrReferenceExpression qualifier = result.second;
|
||||
final PsiClass mixin = result.third;
|
||||
|
||||
final DelegatingScopeProcessor delegate = new DelegatingScopeProcessor(processor) {
|
||||
@Override
|
||||
public boolean execute(@NotNull PsiElement element, ResolveState delegateState) {
|
||||
if (isCategoryMethod(element, subjectType, null)) {
|
||||
if (element instanceof PsiMethod && isCategoryMethod((PsiMethod)element, subjectType, qualifier, null)) {
|
||||
PsiMethod method = (PsiMethod)element;
|
||||
return processor.execute(GrGdkMethodImpl.createGdkMethod(method, false, generateOriginInfo(method)), delegateState);
|
||||
}
|
||||
@@ -244,14 +239,14 @@ public class GdkMethodUtil {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Pair<PsiClassType, PsiClass> getMixinTypes(GrStatement statement) {
|
||||
private static Trinity<PsiClassType, GrReferenceExpression, PsiClass> getMixinTypes(GrStatement statement) {
|
||||
if (statement instanceof GrMethodCall) {
|
||||
GrMethodCall call = (GrMethodCall)statement;
|
||||
PsiClassType original = getTypeToMixIn(call);
|
||||
Pair<PsiClassType, GrReferenceExpression> original = getTypeToMixIn(call);
|
||||
PsiClass mix = getTypeToMix(call);
|
||||
|
||||
if (original != null && mix != null) {
|
||||
return new Pair<PsiClassType, PsiClass>(original, mix);
|
||||
return new Trinity<PsiClassType, GrReferenceExpression, PsiClass>(original.first, original.second, mix);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -287,13 +282,13 @@ public class GdkMethodUtil {
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiClassType getTypeToMixIn(GrMethodCall methodCall) {
|
||||
private static Pair<PsiClassType, GrReferenceExpression> getTypeToMixIn(GrMethodCall methodCall) {
|
||||
GrExpression invoked = methodCall.getInvokedExpression();
|
||||
if (invoked instanceof GrReferenceExpression) {
|
||||
PsiElement resolved = ((GrReferenceExpression)invoked).resolve();
|
||||
if (resolved instanceof PsiMethod && isMixinMethod((PsiMethod)resolved)) {
|
||||
GrExpression qualifier = ((GrReferenceExpression)invoked).getQualifier();
|
||||
PsiClassType type = getPsiClassFromReference(qualifier);
|
||||
Pair<PsiClassType, GrReferenceExpression> type = getPsiClassFromReference(qualifier);
|
||||
if (type != null) {
|
||||
return type;
|
||||
}
|
||||
@@ -306,7 +301,7 @@ public class GdkMethodUtil {
|
||||
if (qualifier instanceof GrReferenceExpression) {
|
||||
GrExpression qqualifier = ((GrReferenceExpression)qualifier).getQualifier();
|
||||
if (qqualifier != null) {
|
||||
PsiClassType type1 = getPsiClassFromReference(qqualifier);
|
||||
Pair<PsiClassType, GrReferenceExpression> type1 = getPsiClassFromReference(qqualifier);
|
||||
if (type1 != null) {
|
||||
return type1;
|
||||
}
|
||||
@@ -314,7 +309,7 @@ public class GdkMethodUtil {
|
||||
else {
|
||||
PsiType qtype = GrReferenceResolveUtil.getQualifierType((GrReferenceExpression)qualifier);
|
||||
if (qtype instanceof PsiClassType && ((PsiClassType)qtype).resolve() != null) {
|
||||
return (PsiClassType)qtype;
|
||||
return Pair.create((PsiClassType)qtype, (GrReferenceExpression)qualifier);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -339,22 +334,21 @@ public class GdkMethodUtil {
|
||||
return mixinRef instanceof GrReferenceExpression && "class".equals(((GrReferenceExpression)mixinRef).getReferenceName());
|
||||
}
|
||||
|
||||
private static PsiClassType getPsiClassFromReference(GrExpression ref) {
|
||||
@Nullable
|
||||
private static Pair<PsiClassType, GrReferenceExpression> getPsiClassFromReference(GrExpression ref) {
|
||||
if (isClassRef(ref)) ref = ((GrReferenceExpression)ref).getQualifier();
|
||||
if (ref instanceof GrReferenceExpression) {
|
||||
PsiElement resolved = ((GrReferenceExpression)ref).resolve();
|
||||
if (resolved instanceof PsiClass) {
|
||||
PsiType type = ref.getType();
|
||||
LOG.assertTrue(type instanceof PsiClassType, "reference resolved into PsiClass should have PsiClassType");
|
||||
return ((PsiClassType)type);
|
||||
return Pair.create((PsiClassType)type, (GrReferenceExpression)ref);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean isCategoryMethod(@Nullable PsiElement element, @Nullable PsiType qualifierType, @Nullable PsiSubstitutor substitutor) {
|
||||
if (!(element instanceof PsiMethod)) return false;
|
||||
PsiMethod method = (PsiMethod)element;
|
||||
public static boolean isCategoryMethod(@NotNull PsiMethod method, @Nullable PsiType qualifierType, @Nullable PsiElement place, @Nullable PsiSubstitutor substitutor) {
|
||||
if (!method.hasModifierProperty(PsiModifier.STATIC)) return false;
|
||||
if (!method.hasModifierProperty(PsiModifier.PUBLIC)) return false;
|
||||
|
||||
@@ -369,7 +363,18 @@ public class GdkMethodUtil {
|
||||
if (substitutor != null) {
|
||||
selfType = substitutor.substitute(selfType);
|
||||
}
|
||||
return TypesUtil.isAssignable(selfType, qualifierType, element.getManager(), element.getResolveScope());
|
||||
|
||||
final GlobalSearchScope scope = method.getResolveScope();
|
||||
final Project project = method.getProject();
|
||||
final PsiManager manager = method.getManager();
|
||||
|
||||
if (selfType instanceof PsiClassType &&
|
||||
((PsiClassType)selfType).rawType().equalsToText(CommonClassNames.JAVA_LANG_CLASS) &&
|
||||
place instanceof GrReferenceExpression &&
|
||||
((GrReferenceExpression)place).resolve() instanceof PsiClass) { // ClassType.categoryMethod() where categoryMethod(Class<> cl, ...)
|
||||
return TypesUtil.isAssignable(selfType, TypesUtil.createJavaLangClassType(qualifierType, project, scope), manager, scope);
|
||||
}
|
||||
return TypesUtil.isAssignable(selfType, qualifierType, manager, scope);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
+3
-3
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2011 JetBrains s.r.o.
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -40,7 +40,7 @@ public class MixinMemberContributor extends NonCodeMembersContributor {
|
||||
@Override
|
||||
public void processDynamicElements(@NotNull final PsiType qualifierType,
|
||||
@NotNull PsiScopeProcessor processor,
|
||||
@NotNull GroovyPsiElement place,
|
||||
@NotNull final GroovyPsiElement place,
|
||||
@NotNull ResolveState state) {
|
||||
if (!(qualifierType instanceof PsiClassType)) return;
|
||||
if (isInAnnotation(place)) return;
|
||||
@@ -70,7 +70,7 @@ public class MixinMemberContributor extends NonCodeMembersContributor {
|
||||
if (!mixin.processDeclarations(new DelegatingScopeProcessor(processor) {
|
||||
@Override
|
||||
public boolean execute(@NotNull PsiElement element, ResolveState state) {
|
||||
if (GdkMethodUtil.isCategoryMethod(element, qualifierType, state.get(PsiSubstitutor.KEY))) {
|
||||
if (element instanceof PsiMethod && GdkMethodUtil.isCategoryMethod((PsiMethod)element, qualifierType, place, state.get(PsiSubstitutor.KEY))) {
|
||||
PsiMethod method = (PsiMethod)element;
|
||||
String originInfo = getOriginInfo(method);
|
||||
return super.execute(GrGdkMethodImpl.createGdkMethod(method, false, originInfo), state);
|
||||
|
||||
+15
@@ -411,6 +411,21 @@ class EvenSieve {
|
||||
add<warning descr="'add' in 'java.util.List<E>' cannot be applied to '(java.lang.Integer, java.lang.Integer)'">(2, 3)</warning>
|
||||
}
|
||||
}
|
||||
''')
|
||||
}
|
||||
|
||||
void testAssignabilityOfCategoryMethod() {
|
||||
testHighlighting('''
|
||||
class Cat {
|
||||
static foo(Class c, int x) {}
|
||||
}
|
||||
|
||||
class X {}
|
||||
|
||||
use(Cat) {
|
||||
X.foo(1)
|
||||
}
|
||||
|
||||
''')
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user