mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-125281 Support @TypeQualifierDefault for nullable/notnull warnings
This commit is contained in:
+2
-2
@@ -187,12 +187,12 @@ public final class FieldFromParameterUtils {
|
||||
modifierList.setModifierProperty(PsiModifier.FINAL, isFinal);
|
||||
|
||||
final NullableNotNullManager manager = NullableNotNullManager.getInstance(project);
|
||||
final String nullable = manager.getNullable(parameter);
|
||||
final PsiAnnotation nullable = manager.getNullableAnnotation(parameter, false);
|
||||
if (nullable != null && !manager.isContainerAnnotation(nullable)) {
|
||||
modifierList.addAfter(factory.createAnnotationFromText("@" + nullable, field), null);
|
||||
}
|
||||
else if (isFinal) {
|
||||
final String notNull = manager.getNotNull(parameter);
|
||||
final PsiAnnotation notNull = manager.getNotNullAnnotation(parameter, false);
|
||||
if (notNull != null && !manager.isContainerAnnotation(notNull)) {
|
||||
modifierList.addAfter(factory.createAnnotationFromText("@" + notNull, field), null);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,136 @@
|
||||
/*
|
||||
* Copyright 2000-2014 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.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.codeInsight;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.psi.*;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class AnnotationTargetUtil {
|
||||
public static final Set<PsiAnnotation.TargetType> DEFAULT_TARGETS = Collections.unmodifiableSet(ContainerUtil.newHashSet(
|
||||
PsiAnnotation.TargetType.PACKAGE, PsiAnnotation.TargetType.TYPE, PsiAnnotation.TargetType.ANNOTATION_TYPE,
|
||||
PsiAnnotation.TargetType.FIELD, PsiAnnotation.TargetType.METHOD, PsiAnnotation.TargetType.CONSTRUCTOR,
|
||||
PsiAnnotation.TargetType.PARAMETER, PsiAnnotation.TargetType.LOCAL_VARIABLE));
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.codeInsight.AnnotationUtil");
|
||||
private static final PsiAnnotation.TargetType[] PACKAGE_TARGETS = {PsiAnnotation.TargetType.PACKAGE};
|
||||
private static final PsiAnnotation.TargetType[] TYPE_USE_TARGETS = {PsiAnnotation.TargetType.TYPE_USE};
|
||||
private static final PsiAnnotation.TargetType[] ANNOTATION_TARGETS = {PsiAnnotation.TargetType.ANNOTATION_TYPE, PsiAnnotation.TargetType.TYPE, PsiAnnotation.TargetType.TYPE_USE};
|
||||
private static final PsiAnnotation.TargetType[] TYPE_TARGETS = {PsiAnnotation.TargetType.TYPE, PsiAnnotation.TargetType.TYPE_USE};
|
||||
private static final PsiAnnotation.TargetType[] TYPE_PARAMETER_TARGETS = {
|
||||
PsiAnnotation.TargetType.TYPE_PARAMETER, PsiAnnotation.TargetType.TYPE_USE};
|
||||
private static final PsiAnnotation.TargetType[] CONSTRUCTOR_TARGETS = {PsiAnnotation.TargetType.CONSTRUCTOR, PsiAnnotation.TargetType.TYPE_USE};
|
||||
private static final PsiAnnotation.TargetType[] METHOD_TARGETS = {PsiAnnotation.TargetType.METHOD, PsiAnnotation.TargetType.TYPE_USE};
|
||||
private static final PsiAnnotation.TargetType[] FIELD_TARGETS = {PsiAnnotation.TargetType.FIELD, PsiAnnotation.TargetType.TYPE_USE};
|
||||
private static final PsiAnnotation.TargetType[] PARAMETER_TARGETS = {PsiAnnotation.TargetType.PARAMETER, PsiAnnotation.TargetType.TYPE_USE};
|
||||
private static final PsiAnnotation.TargetType[] LOCAL_VARIABLE_TARGETS ={
|
||||
PsiAnnotation.TargetType.LOCAL_VARIABLE, PsiAnnotation.TargetType.TYPE_USE};
|
||||
|
||||
@NotNull
|
||||
public static PsiAnnotation.TargetType[] getTargetsForLocation(@Nullable PsiAnnotationOwner owner) {
|
||||
if (owner == null) {
|
||||
return PsiAnnotation.TargetType.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
if (owner instanceof PsiType || owner instanceof PsiTypeElement) {
|
||||
return TYPE_USE_TARGETS;
|
||||
}
|
||||
|
||||
if (owner instanceof PsiTypeParameter) {
|
||||
return TYPE_PARAMETER_TARGETS;
|
||||
}
|
||||
|
||||
if (owner instanceof PsiModifierList) {
|
||||
PsiElement element = ((PsiModifierList)owner).getParent();
|
||||
if (element instanceof PsiPackageStatement) {
|
||||
return PACKAGE_TARGETS;
|
||||
}
|
||||
if (element instanceof PsiClass) {
|
||||
if (((PsiClass)element).isAnnotationType()) {
|
||||
return ANNOTATION_TARGETS;
|
||||
}
|
||||
else {
|
||||
return TYPE_TARGETS;
|
||||
}
|
||||
}
|
||||
if (element instanceof PsiMethod) {
|
||||
if (((PsiMethod)element).isConstructor()) {
|
||||
return CONSTRUCTOR_TARGETS;
|
||||
}
|
||||
else {
|
||||
return METHOD_TARGETS;
|
||||
}
|
||||
}
|
||||
if (element instanceof PsiField) {
|
||||
return FIELD_TARGETS;
|
||||
}
|
||||
if (element instanceof PsiParameter) {
|
||||
return PARAMETER_TARGETS;
|
||||
}
|
||||
if (element instanceof PsiLocalVariable) {
|
||||
return LOCAL_VARIABLE_TARGETS;
|
||||
}
|
||||
}
|
||||
|
||||
return PsiAnnotation.TargetType.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Set<PsiAnnotation.TargetType> extractRequiredAnnotationTargets(@Nullable PsiAnnotationMemberValue value) {
|
||||
if (value instanceof PsiReference) {
|
||||
PsiAnnotation.TargetType targetType = translateTargetRef((PsiReference)value);
|
||||
if (targetType != null) {
|
||||
return Collections.singleton(targetType);
|
||||
}
|
||||
}
|
||||
else if (value instanceof PsiArrayInitializerMemberValue) {
|
||||
Set <PsiAnnotation.TargetType> targets = ContainerUtil.newHashSet();
|
||||
for (PsiAnnotationMemberValue initializer : ((PsiArrayInitializerMemberValue)value).getInitializers()) {
|
||||
if (initializer instanceof PsiReference) {
|
||||
PsiAnnotation.TargetType targetType = translateTargetRef((PsiReference)initializer);
|
||||
if (targetType != null) {
|
||||
targets.add(targetType);
|
||||
}
|
||||
}
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiAnnotation.TargetType translateTargetRef(@NotNull PsiReference reference) {
|
||||
PsiElement field = reference.resolve();
|
||||
if (field instanceof PsiEnumConstant) {
|
||||
String name = ((PsiEnumConstant)field).getName();
|
||||
try {
|
||||
return PsiAnnotation.TargetType.valueOf(name);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
LOG.warn("Unknown target: " + name);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -379,14 +379,14 @@ public class AnnotationUtil {
|
||||
@NotNull
|
||||
public static PsiAnnotation[] getAllAnnotations(@NotNull PsiModifierListOwner owner,
|
||||
boolean inHierarchy,
|
||||
Set<PsiModifierListOwner> visited) {
|
||||
@Nullable Set<PsiModifierListOwner> visited) {
|
||||
return getAllAnnotations(owner, inHierarchy, visited, true);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static PsiAnnotation[] getAllAnnotations(@NotNull PsiModifierListOwner owner,
|
||||
boolean inHierarchy,
|
||||
Set<PsiModifierListOwner> visited, boolean withInferred) {
|
||||
@Nullable Set<PsiModifierListOwner> visited, boolean withInferred) {
|
||||
final PsiModifierList list = owner.getModifierList();
|
||||
PsiAnnotation[] annotations = PsiAnnotation.EMPTY_ARRAY;
|
||||
if (list != null) {
|
||||
|
||||
@@ -27,7 +27,6 @@ import com.intellij.psi.*;
|
||||
import com.intellij.psi.util.TypeConversionUtil;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import org.jdom.Element;
|
||||
import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -39,18 +38,19 @@ import java.util.*;
|
||||
*/
|
||||
public class NullableNotNullManager implements PersistentStateComponent<Element> {
|
||||
private static final Logger LOG = Logger.getInstance("#" + NullableNotNullManager.class.getName());
|
||||
@NonNls private static final String NULLABLE_CONTAINER_ANNOTATION = "javax.annotation.ParametersAreNullableByDefault";
|
||||
@NonNls private static final String NONNULL_CONTAINER_ANNOTATION = "javax.annotation.ParametersAreNonnullByDefault";
|
||||
|
||||
public String myDefaultNullable = AnnotationUtil.NULLABLE;
|
||||
public String myDefaultNotNull = AnnotationUtil.NOT_NULL;
|
||||
public final JDOMExternalizableStringList myNullables = new JDOMExternalizableStringList();
|
||||
public final JDOMExternalizableStringList myNotNulls = new JDOMExternalizableStringList();
|
||||
|
||||
public static final String[] DEFAULT_NULLABLES = {AnnotationUtil.NULLABLE, "javax.annotation.Nullable",
|
||||
private static final String JAVAX_ANNOTATION_NULLABLE = "javax.annotation.Nullable";
|
||||
private static final String JAVAX_ANNOTATION_NONNULL = "javax.annotation.Nonnull";
|
||||
|
||||
public static final String[] DEFAULT_NULLABLES = {AnnotationUtil.NULLABLE, JAVAX_ANNOTATION_NULLABLE,
|
||||
"edu.umd.cs.findbugs.annotations.Nullable", "android.support.annotation.Nullable"
|
||||
};
|
||||
public static final String[] DEFAULT_NOT_NULLS = {AnnotationUtil.NOT_NULL, "javax.annotation.Nonnull",
|
||||
public static final String[] DEFAULT_NOT_NULLS = {AnnotationUtil.NOT_NULL, JAVAX_ANNOTATION_NONNULL,
|
||||
"edu.umd.cs.findbugs.annotations.NonNull", "android.support.annotation.NonNull"
|
||||
};
|
||||
|
||||
@@ -106,8 +106,9 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
|
||||
return findNullabilityAnnotation(owner, checkBases, true);
|
||||
}
|
||||
|
||||
public boolean isContainerAnnotation(String anno) {
|
||||
return NULLABLE_CONTAINER_ANNOTATION.equals(anno) || NONNULL_CONTAINER_ANNOTATION.equals(anno);
|
||||
public boolean isContainerAnnotation(@NotNull PsiAnnotation anno) {
|
||||
PsiAnnotation.TargetType[] acceptAnyTarget = PsiAnnotation.TargetType.values();
|
||||
return isNullabilityDefault(anno, true, acceptAnyTarget) || isNullabilityDefault(anno, false, acceptAnyTarget);
|
||||
}
|
||||
|
||||
public void setDefaultNullable(@NotNull String defaultNullable) {
|
||||
@@ -145,15 +146,20 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
|
||||
return annotation;
|
||||
}
|
||||
|
||||
if (owner instanceof PsiParameter && !TypeConversionUtil.isPrimitiveAndNotNull(((PsiParameter)owner).getType())) {
|
||||
// even if javax.annotation.Nullable is not configured, it should still take precedence over ByDefault annotations
|
||||
if (AnnotationUtil.isAnnotated(owner, nullable ? Arrays.asList(DEFAULT_NOT_NULLS) : Arrays.asList(DEFAULT_NULLABLES), checkBases, false)) {
|
||||
return null;
|
||||
}
|
||||
return findContainerAnnotation(owner, nullable
|
||||
? NULLABLE_CONTAINER_ANNOTATION
|
||||
: NONNULL_CONTAINER_ANNOTATION);
|
||||
PsiType type = getOwnerType(owner);
|
||||
if (type == null || TypeConversionUtil.isPrimitiveAndNotNull(type)) return null;
|
||||
|
||||
// even if javax.annotation.Nullable is not configured, it should still take precedence over ByDefault annotations
|
||||
if (AnnotationUtil.isAnnotated(owner, nullable ? Arrays.asList(DEFAULT_NOT_NULLS) : Arrays.asList(DEFAULT_NULLABLES), checkBases, false)) {
|
||||
return null;
|
||||
}
|
||||
return findNullabilityDefaultInHierarchy(owner, nullable);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiType getOwnerType(PsiModifierListOwner owner) {
|
||||
if (owner instanceof PsiVariable) return ((PsiVariable)owner).getType();
|
||||
if (owner instanceof PsiMethod) return ((PsiMethod)owner).getReturnType();
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -166,11 +172,13 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static PsiAnnotation findContainerAnnotation(PsiModifierListOwner owner, String annotationFQN) {
|
||||
private static PsiAnnotation findNullabilityDefaultInHierarchy(PsiModifierListOwner owner, boolean nullable) {
|
||||
PsiAnnotation.TargetType[] placeTargetTypes = AnnotationTargetUtil.getTargetsForLocation(owner.getModifierList());
|
||||
|
||||
PsiElement element = owner.getParent();
|
||||
while (element != null) {
|
||||
if (element instanceof PsiModifierListOwner) {
|
||||
PsiAnnotation annotation = AnnotationUtil.findAnnotation((PsiModifierListOwner)element, annotationFQN);
|
||||
PsiAnnotation annotation = getNullabilityDefault((PsiModifierListOwner)element, nullable, placeTargetTypes);
|
||||
if (annotation != null) {
|
||||
return annotation;
|
||||
}
|
||||
@@ -179,7 +187,7 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
|
||||
if (element instanceof PsiClassOwner) {
|
||||
String packageName = ((PsiClassOwner)element).getPackageName();
|
||||
PsiPackage psiPackage = JavaPsiFacade.getInstance(element.getProject()).findPackage(packageName);
|
||||
return AnnotationUtil.findAnnotation(psiPackage, annotationFQN);
|
||||
return psiPackage == null ? null : getNullabilityDefault(psiPackage, nullable, placeTargetTypes);
|
||||
}
|
||||
|
||||
element = element.getContext();
|
||||
@@ -187,6 +195,37 @@ public class NullableNotNullManager implements PersistentStateComponent<Element>
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PsiAnnotation getNullabilityDefault(@NotNull PsiModifierListOwner container, boolean nullable, PsiAnnotation.TargetType[] placeTargetTypes) {
|
||||
PsiModifierList modifierList = container.getModifierList();
|
||||
if (modifierList == null) return null;
|
||||
for (PsiAnnotation annotation : modifierList.getAnnotations()) {
|
||||
if (isNullabilityDefault(annotation, nullable, placeTargetTypes)) {
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static boolean isNullabilityDefault(@NotNull PsiAnnotation annotation, boolean nullable, PsiAnnotation.TargetType[] placeTargetTypes) {
|
||||
PsiJavaCodeReferenceElement element = annotation.getNameReferenceElement();
|
||||
PsiElement declaration = element == null ? null : element.resolve();
|
||||
if (!(declaration instanceof PsiClass)) return false;
|
||||
|
||||
if (!AnnotationUtil.isAnnotated((PsiClass)declaration,
|
||||
nullable ? JAVAX_ANNOTATION_NULLABLE : JAVAX_ANNOTATION_NONNULL,
|
||||
false,
|
||||
true)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PsiAnnotation tqDefault = AnnotationUtil.findAnnotation((PsiClass)declaration, true, "javax.annotation.meta.TypeQualifierDefault");
|
||||
if (tqDefault == null) return false;
|
||||
|
||||
Set<PsiAnnotation.TargetType> required = AnnotationTargetUtil.extractRequiredAnnotationTargets(tqDefault.findAttributeValue(null));
|
||||
if (required == null) return false;
|
||||
return required.isEmpty() || ContainerUtil.intersects(required, Arrays.asList(placeTargetTypes));
|
||||
}
|
||||
|
||||
public List<String> getNullables() {
|
||||
return myNullables;
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.psi.impl;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationTargetUtil;
|
||||
import com.intellij.lang.ASTNode;
|
||||
import com.intellij.openapi.application.ApplicationManager;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
@@ -51,7 +52,6 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -60,22 +60,6 @@ import static com.intellij.psi.PsiAnnotation.TargetType;
|
||||
public class PsiImplUtil {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.PsiImplUtil");
|
||||
|
||||
private static final Set<TargetType> DEFAULT_TARGETS = Collections.unmodifiableSet(ContainerUtil.newHashSet(
|
||||
TargetType.PACKAGE, TargetType.TYPE, TargetType.ANNOTATION_TYPE,
|
||||
TargetType.FIELD, TargetType.METHOD, TargetType.CONSTRUCTOR,
|
||||
TargetType.PARAMETER, TargetType.LOCAL_VARIABLE));
|
||||
|
||||
private static final TargetType[] PACKAGE_TARGETS = {TargetType.PACKAGE};
|
||||
private static final TargetType[] TYPE_USE_TARGETS = {TargetType.TYPE_USE};
|
||||
private static final TargetType[] ANNOTATION_TARGETS = {TargetType.ANNOTATION_TYPE, TargetType.TYPE, TargetType.TYPE_USE};
|
||||
private static final TargetType[] TYPE_TARGETS = {TargetType.TYPE, TargetType.TYPE_USE};
|
||||
private static final TargetType[] TYPE_PARAMETER_TARGETS = {TargetType.TYPE_PARAMETER, TargetType.TYPE_USE};
|
||||
private static final TargetType[] CONSTRUCTOR_TARGETS = {TargetType.CONSTRUCTOR, TargetType.TYPE_USE};
|
||||
private static final TargetType[] METHOD_TARGETS = {TargetType.METHOD, TargetType.TYPE_USE};
|
||||
private static final TargetType[] FIELD_TARGETS = {TargetType.FIELD, TargetType.TYPE_USE};
|
||||
private static final TargetType[] PARAMETER_TARGETS = {TargetType.PARAMETER, TargetType.TYPE_USE};
|
||||
private static final TargetType[] LOCAL_VARIABLE_TARGETS ={TargetType.LOCAL_VARIABLE, TargetType.TYPE_USE};
|
||||
|
||||
private PsiImplUtil() { }
|
||||
|
||||
@NotNull
|
||||
@@ -376,93 +360,14 @@ public class PsiImplUtil {
|
||||
PsiModifierList modifierList = annotationType.getModifierList();
|
||||
if (modifierList == null) return null;
|
||||
PsiAnnotation target = modifierList.findAnnotation(CommonClassNames.JAVA_LANG_ANNOTATION_TARGET);
|
||||
if (target == null) return DEFAULT_TARGETS; // if omitted it is applicable to all but Java 8 TYPE_USE/TYPE_PARAMETERS targets
|
||||
if (target == null) return AnnotationTargetUtil.DEFAULT_TARGETS; // if omitted it is applicable to all but Java 8 TYPE_USE/TYPE_PARAMETERS targets
|
||||
|
||||
PsiAnnotationMemberValue value = target.findAttributeValue(null);
|
||||
if (value instanceof PsiReference) {
|
||||
TargetType targetType = translateTargetRef((PsiReference)value);
|
||||
if (targetType != null) {
|
||||
return Collections.singleton(targetType);
|
||||
}
|
||||
}
|
||||
else if (value instanceof PsiArrayInitializerMemberValue) {
|
||||
Set <TargetType> targets = ContainerUtil.newHashSet();
|
||||
for (PsiAnnotationMemberValue initializer : ((PsiArrayInitializerMemberValue)value).getInitializers()) {
|
||||
if (initializer instanceof PsiReference) {
|
||||
TargetType targetType = translateTargetRef((PsiReference)initializer);
|
||||
if (targetType != null) {
|
||||
targets.add(targetType);
|
||||
}
|
||||
}
|
||||
}
|
||||
return targets;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TargetType translateTargetRef(PsiReference reference) {
|
||||
PsiElement field = reference.resolve();
|
||||
if (field instanceof PsiEnumConstant) {
|
||||
String name = ((PsiEnumConstant)field).getName();
|
||||
try {
|
||||
return TargetType.valueOf(name);
|
||||
}
|
||||
catch (IllegalArgumentException e) {
|
||||
LOG.warn("Unknown target: " + name);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return AnnotationTargetUtil.extractRequiredAnnotationTargets(target.findAttributeValue(null));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static TargetType[] getTargetsForLocation(@Nullable PsiAnnotationOwner owner) {
|
||||
if (owner == null) {
|
||||
return TargetType.EMPTY_ARRAY;
|
||||
}
|
||||
|
||||
if (owner instanceof PsiType || owner instanceof PsiTypeElement) {
|
||||
return TYPE_USE_TARGETS;
|
||||
}
|
||||
|
||||
if (owner instanceof PsiTypeParameter) {
|
||||
return TYPE_PARAMETER_TARGETS;
|
||||
}
|
||||
|
||||
if (owner instanceof PsiModifierList) {
|
||||
PsiElement element = ((PsiModifierList)owner).getParent();
|
||||
if (element instanceof PsiPackageStatement) {
|
||||
return PACKAGE_TARGETS;
|
||||
}
|
||||
if (element instanceof PsiClass) {
|
||||
if (((PsiClass)element).isAnnotationType()) {
|
||||
return ANNOTATION_TARGETS;
|
||||
}
|
||||
else {
|
||||
return TYPE_TARGETS;
|
||||
}
|
||||
}
|
||||
if (element instanceof PsiMethod) {
|
||||
if (((PsiMethod)element).isConstructor()) {
|
||||
return CONSTRUCTOR_TARGETS;
|
||||
}
|
||||
else {
|
||||
return METHOD_TARGETS;
|
||||
}
|
||||
}
|
||||
if (element instanceof PsiField) {
|
||||
return FIELD_TARGETS;
|
||||
}
|
||||
if (element instanceof PsiParameter) {
|
||||
return PARAMETER_TARGETS;
|
||||
}
|
||||
if (element instanceof PsiLocalVariable) {
|
||||
return LOCAL_VARIABLE_TARGETS;
|
||||
}
|
||||
}
|
||||
|
||||
return TargetType.EMPTY_ARRAY;
|
||||
return AnnotationTargetUtil.getTargetsForLocation(owner);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import foo.*;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class Some {
|
||||
void foo(@NotNull String s) {
|
||||
NotNullClass.foo(null);
|
||||
if (<warning descr="Condition 'NotNullClass.foo(s) == null' is always 'false'">NotNullClass.foo(s) == null</warning>) {}
|
||||
|
||||
NullableClass.foo(null);
|
||||
if (NullableClass.foo("a") == null) {}
|
||||
|
||||
AnotherPackageNotNull.foo(null);
|
||||
if (<warning descr="Condition 'AnotherPackageNotNull.foo(s) == null' is always 'false'">AnotherPackageNotNull.foo(s) == null</warning>) {}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@bar.MethodsAreNotNullByDefault
|
||||
class NotNullClass {
|
||||
static native Object foo(String s);
|
||||
|
||||
}
|
||||
class NullableClass {
|
||||
static native Object foo(String s);
|
||||
}
|
||||
@@ -258,8 +258,14 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase {
|
||||
public void testAccessingSameArrayElements() { doTest(); }
|
||||
|
||||
public void testParametersAreNonnullByDefault() {
|
||||
myFixture.addClass("package javax.annotation; public @interface ParametersAreNonnullByDefault {}");
|
||||
myFixture.addClass("package javax.annotation; public @interface ParametersAreNullableByDefault {}");
|
||||
addJavaxNullabilityAnnotations();
|
||||
|
||||
myFixture.addClass("package javax.annotation;" +
|
||||
"@javax.annotation.meta.TypeQualifierDefault(java.lang.annotation.ElementType.PARAMETER) @javax.annotation.Nonnull " +
|
||||
"public @interface ParametersAreNonnullByDefault {}");
|
||||
myFixture.addClass("package javax.annotation;" +
|
||||
"@javax.annotation.meta.TypeQualifierDefault(java.lang.annotation.ElementType.PARAMETER) @javax.annotation.Nullable " +
|
||||
"public @interface ParametersAreNullableByDefault {}");
|
||||
|
||||
myFixture.addClass("package foo; public class AnotherPackageNotNull { public static void foo(String s) {}}");
|
||||
myFixture.addFileToProject("foo/package-info.java", "@javax.annotation.ParametersAreNonnullByDefault package foo;");
|
||||
@@ -267,6 +273,28 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase {
|
||||
doTest();
|
||||
}
|
||||
|
||||
private void addJavaxNullabilityAnnotations() {
|
||||
myFixture.addClass("package javax.annotation;" +
|
||||
"public @interface Nonnull {}");
|
||||
myFixture.addClass("package javax.annotation.meta;" +
|
||||
"public @interface TypeQualifier {}");
|
||||
myFixture.addClass("package javax.annotation.meta;" +
|
||||
"public @interface TypeQualifierDefault { java.lang.annotation.ElementType[] value() default {};}");
|
||||
}
|
||||
|
||||
public void testCustomTypeQualifierDefault() {
|
||||
addJavaxNullabilityAnnotations();
|
||||
myFixture.addClass("package bar;" +
|
||||
"@javax.annotation.meta.TypeQualifierDefault(java.lang.annotation.ElementType.METHOD) @javax.annotation.Nonnull " +
|
||||
"public @interface MethodsAreNotNullByDefault {}");
|
||||
|
||||
myFixture.addClass("package foo; public class AnotherPackageNotNull { public static native Object foo(String s); }");
|
||||
myFixture.addFileToProject("foo/package-info.java", "@bar.MethodsAreNotNullByDefault package foo;");
|
||||
|
||||
myFixture.enableInspections(new DataFlowInspection());
|
||||
myFixture.testHighlighting(true, false, true, getTestName(false) + ".java");
|
||||
}
|
||||
|
||||
public void testTrueOrEqualsSomething() {
|
||||
doTest();
|
||||
myFixture.launchAction(myFixture.findSingleIntention("Remove redundant assignment"));
|
||||
|
||||
Reference in New Issue
Block a user