mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
support @TypeQualifierNickname usages without its declaration (IDEA-182842)
This commit is contained in:
@@ -9,7 +9,9 @@ import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.util.DefaultJDOMExternalizer;
|
||||
import com.intellij.openapi.util.InvalidDataException;
|
||||
import com.intellij.openapi.util.WriteExternalException;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.psi.impl.java.stubs.index.JavaAnnotationIndex;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.psi.util.CachedValueProvider;
|
||||
import com.intellij.psi.util.CachedValuesManager;
|
||||
@@ -21,6 +23,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.jps.model.serialization.java.compiler.JpsJavaCompilerNotNullableSerializer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@@ -87,17 +90,39 @@ public class NullableNotNullManagerImpl extends NullableNotNullManager implement
|
||||
return CachedValuesManager.getManager(myProject).getCachedValue(myProject, () -> {
|
||||
List<PsiClass> result = new ArrayList<>();
|
||||
GlobalSearchScope scope = GlobalSearchScope.allScope(myProject);
|
||||
for (PsiClass tqNick : JavaPsiFacade.getInstance(myProject).findClasses(TYPE_QUALIFIER_NICKNAME, scope)) {
|
||||
result.addAll(ContainerUtil.findAll(MetaAnnotationUtil.getChildren(tqNick, scope), candidate -> {
|
||||
String qname = candidate.getQualifiedName();
|
||||
if (qname == null || qname.startsWith("javax.annotation.")) return false;
|
||||
return getNickNamedNullability(candidate) != Nullness.UNKNOWN;
|
||||
}));
|
||||
PsiClass[] nickDeclarations = JavaPsiFacade.getInstance(myProject).findClasses(TYPE_QUALIFIER_NICKNAME, scope);
|
||||
for (PsiClass tqNick : nickDeclarations) {
|
||||
result.addAll(ContainerUtil.findAll(MetaAnnotationUtil.getChildren(tqNick, scope), NullableNotNullManagerImpl::isNullabilityNickName));
|
||||
}
|
||||
if (nickDeclarations.length == 0) {
|
||||
result.addAll(getUnresolvedNicknameUsages());
|
||||
}
|
||||
return CachedValueProvider.Result.create(result, PsiModificationTracker.MODIFICATION_COUNT);
|
||||
});
|
||||
}
|
||||
|
||||
// some frameworks use jsr305 annotations but don't have them in classpath
|
||||
private List<PsiClass> getUnresolvedNicknameUsages() {
|
||||
List<PsiClass> result = new ArrayList<>();
|
||||
Collection<PsiAnnotation> annotations = JavaAnnotationIndex.getInstance().get(StringUtil.getShortName(TYPE_QUALIFIER_NICKNAME), myProject, GlobalSearchScope.allScope(myProject));
|
||||
for (PsiAnnotation annotation : annotations) {
|
||||
PsiElement context = annotation.getContext();
|
||||
if (context instanceof PsiModifierList && context.getContext() instanceof PsiClass) {
|
||||
PsiClass ownerClass = (PsiClass)context.getContext();
|
||||
if (ownerClass.isAnnotationType() && isNullabilityNickName(ownerClass)) {
|
||||
result.add(ownerClass);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static boolean isNullabilityNickName(@NotNull PsiClass candidate) {
|
||||
String qname = candidate.getQualifiedName();
|
||||
if (qname == null || qname.startsWith("javax.annotation.")) return false;
|
||||
return getNickNamedNullability(candidate) != Nullness.UNKNOWN;
|
||||
}
|
||||
|
||||
private static Nullness getNickNamedNullability(@NotNull PsiClass psiClass) {
|
||||
if (AnnotationUtil.findAnnotation(psiClass, TYPE_QUALIFIER_NICKNAME) == null) return Nullness.UNKNOWN;
|
||||
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
import javax.annotation.meta.*;
|
||||
|
||||
@TypeQualifierNickname()
|
||||
@javax.annotation.Nonnull(when = When.MAYBE)
|
||||
@interface NullableNick {}
|
||||
|
||||
interface UnknownInterface {
|
||||
void foo(String s);
|
||||
}
|
||||
|
||||
class ImplWithNotNull implements UnknownInterface {
|
||||
public void foo(@NullableNick String s) {
|
||||
public void foo(@bar.NullableNick String s) {
|
||||
System.out.println(s.<warning descr="Method invocation 'hashCode' may produce 'java.lang.NullPointerException'">hashCode</warning>());
|
||||
}
|
||||
}
|
||||
+17
-7
@@ -369,16 +369,28 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase {
|
||||
}
|
||||
|
||||
public void testTypeQualifierNickname() {
|
||||
myFixture.addClass("package javax.annotation.meta; public @interface TypeQualifierNickname {}");
|
||||
addJavaxNullabilityAnnotations(myFixture);
|
||||
addNullableNick();
|
||||
|
||||
myFixture.addClass("package bar;" +
|
||||
"import javax.annotation.meta.*;" +
|
||||
"@TypeQualifierNickname() @javax.annotation.NonNull(when = Maybe.MAYBE) " +
|
||||
"public @interface NullableNick {}");
|
||||
|
||||
doTest();
|
||||
}
|
||||
|
||||
public void testTypeQualifierNicknameWithoutDeclarations() {
|
||||
addJavaxNullabilityAnnotations(myFixture);
|
||||
addNullableNick();
|
||||
|
||||
myFixture.enableInspections(new DataFlowInspection());
|
||||
myFixture.testHighlighting(true, false, true, "TypeQualifierNickname.java");
|
||||
}
|
||||
|
||||
private void addNullableNick() {
|
||||
myFixture.addClass("package bar;" +
|
||||
"@javax.annotation.meta.TypeQualifierNickname() " +
|
||||
"@javax.annotation.Nonnull(when = javax.annotation.meta.When.MAYBE) " +
|
||||
"public @interface NullableNick {}");
|
||||
}
|
||||
|
||||
public static void addJavaxDefaultNullabilityAnnotations(final JavaCodeInsightTestFixture fixture) {
|
||||
fixture.addClass("package javax.annotation;" +
|
||||
"@javax.annotation.meta.TypeQualifierDefault(java.lang.annotation.ElementType.PARAMETER) @javax.annotation.Nonnull " +
|
||||
@@ -393,8 +405,6 @@ public class DataFlowInspectionTest extends DataFlowInspectionTestCase {
|
||||
"public @interface TypeQualifierDefault { java.lang.annotation.ElementType[] value() default {};}");
|
||||
fixture.addClass("package javax.annotation.meta;" +
|
||||
"public enum When { ALWAYS, UNKNOWN, MAYBE, NEVER }");
|
||||
fixture.addClass("package javax.annotation.meta;" +
|
||||
"public @interface TypeQualifierNickname {}");
|
||||
|
||||
fixture.addClass("package javax.annotation;" +
|
||||
"import javax.annotation.meta.*;" +
|
||||
|
||||
Reference in New Issue
Block a user