Annotation applicability highlighting reworked

This commit is contained in:
Roman Shevchenko
2013-03-06 21:11:38 +01:00
parent bb11ce13c7
commit 2ab88505d2
21 changed files with 545 additions and 352 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -22,8 +22,8 @@ import com.intellij.openapi.util.Condition;
import com.intellij.patterns.ElementPattern;
import com.intellij.psi.*;
import com.intellij.psi.filters.getters.MembersGetter;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.impl.source.tree.java.PsiAnnotationImpl;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PropertyUtil;
import com.intellij.psi.util.PsiTreeUtil;
@@ -92,27 +92,15 @@ public class PreferByKindWeigher extends LookupElementWeigher {
if (psiElement().withParents(PsiJavaCodeReferenceElement.class, PsiAnnotation.class).accepts(position)) {
final PsiAnnotation annotation = PsiTreeUtil.getParentOfType(position, PsiAnnotation.class);
assert annotation != null;
PsiAnnotationOwner owner = annotation.getOwner();
if (owner instanceof PsiModifierList || owner instanceof PsiTypeElement || owner instanceof PsiTypeParameter) {
PsiElement member = (PsiElement)owner;
if (member instanceof PsiModifierList) {
member = member.getParent();
final PsiAnnotation.TargetType[] targets = PsiImplUtil.getApplicableTargets(annotation.getOwner());
return new Condition<PsiClass>() {
@Override
public boolean value(PsiClass psiClass) {
return psiClass.isAnnotationType() && PsiImplUtil.isAnnotationApplicable(psiClass, false, targets);
}
if (member instanceof PsiTypeElement && member.getParent() instanceof PsiMethod) {
member = member.getParent();
}
final String[] elementTypeFields = PsiAnnotationImpl.getApplicableElementTypeFields(member);
return new Condition<PsiClass>() {
@Override
public boolean value(PsiClass psiClass) {
if (!psiClass.isAnnotationType()) {
return false;
}
return PsiAnnotationImpl.isAnnotationApplicable(false, psiClass, elementTypeFields, position.getResolveScope());
}
};
}
};
}
//noinspection unchecked
return Condition.FALSE;
}
@@ -179,7 +167,7 @@ public class PreferByKindWeigher extends LookupElementWeigher {
return MyResult.qualifiedWithGetter;
}
}
return MyResult.normal;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -27,14 +27,13 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.Comparing;
import com.intellij.patterns.ElementPattern;
import com.intellij.patterns.PatternCondition;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.tree.java.PsiAnnotationImpl;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.psi.util.TypeConversionUtil;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.ProcessingContext;
import com.intellij.util.containers.HashSet;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -161,17 +160,14 @@ public class AnnotationsHighlightUtil {
@Nullable
public static HighlightInfo checkDuplicateAnnotations(PsiAnnotation annotationToCheck) {
PsiAnnotationOwner owner = annotationToCheck.getOwner();
if (owner == null) {
return null;
}
if (owner == null) return null;
PsiJavaCodeReferenceElement element = annotationToCheck.getNameReferenceElement();
if (element == null) return null;
PsiElement resolved = element.resolve();
if (!(resolved instanceof PsiClass)) return null;
PsiAnnotation[] annotations = owner.getApplicableAnnotations();
for (PsiAnnotation annotation : annotations) {
for (PsiAnnotation annotation : owner.getAnnotations()) {
if (annotation == annotationToCheck) continue;
PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement();
if (nameRef == null) continue;
@@ -254,50 +250,117 @@ public class AnnotationsHighlightUtil {
return HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(typeElement).descriptionAndTooltip(description).create();
}
private static final ElementPattern<PsiElement> ANNOTATION_ALLOWED = psiElement().andOr(
psiElement().with(new PatternCondition<PsiElement>("annotationOwner") {
@Override
public boolean accepts(@NotNull PsiElement element, ProcessingContext context) {
return element instanceof PsiAnnotationOwner;
}
}),
private static final ElementPattern<PsiElement> ANY_ANNOTATION_ALLOWED = psiElement().andOr(
psiElement().withParent(PsiNameValuePair.class),
psiElement().withParents(PsiArrayInitializerMemberValue.class, PsiNameValuePair.class),
psiElement().withParent(PsiAnnotationMethod.class).afterLeaf(PsiKeyword.DEFAULT)
);
@Nullable
public static HighlightInfo checkApplicability(final PsiAnnotation annotation) {
PsiAnnotationOwner owner = annotation.getOwner();
if (owner instanceof PsiModifierList || owner instanceof PsiTypeElement || owner instanceof PsiTypeParameter) {
PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement();
if (nameRef == null) {
return null;
}
PsiElement member = owner instanceof PsiModifierList ? ((PsiElement)owner).getParent() : (PsiElement)owner;
String[] elementTypeFields = PsiAnnotationImpl.getApplicableElementTypeFields(member);
if (elementTypeFields == null || PsiAnnotationImpl.isAnnotationApplicableTo(annotation, false, elementTypeFields)) {
return null;
}
String target = JavaErrorMessages.message("annotation.target." + elementTypeFields[0]);
String description = JavaErrorMessages.message("annotation.not.applicable", nameRef.getText(), target);
HighlightInfo highlightInfo =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(nameRef).descriptionAndTooltip(description).create();
QuickFixAction.registerQuickFixAction(highlightInfo, new DeleteNotApplicableAnnotationAction(annotation));
return highlightInfo;
public static HighlightInfo checkApplicability(@NotNull PsiAnnotation annotation) {
if (ANY_ANNOTATION_ALLOWED.accepts(annotation)) {
return null;
}
if (!ANNOTATION_ALLOWED.accepts(annotation)) {
PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement();
if (nameRef == null) return null;
PsiElement annotationType = nameRef.resolve();
if (!(annotationType instanceof PsiClass)) return null;
PsiAnnotationOwner owner = annotation.getOwner();
PsiAnnotation.TargetType[] targets = PsiImplUtil.getApplicableTargets(owner);
if (owner == null || targets == null) {
String message = JavaErrorMessages.message("annotation.not.allowed.here");
HighlightInfo highlightInfo =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(annotation).descriptionAndTooltip(message).create();
QuickFixAction.registerQuickFixAction(highlightInfo, new DeleteNotApplicableAnnotationAction(annotation));
return highlightInfo;
return annotationError(annotation, message);
}
if (!(owner instanceof PsiModifierList)) {
HighlightInfo info = HighlightUtil.checkTypeAnnotationFeature(annotation);
if (info != null) return info;
}
PsiAnnotation.TargetType applicable = PsiImplUtil.findApplicableTarget((PsiClass)annotationType, targets);
if (applicable == null) {
String target = JavaErrorMessages.message("annotation.target." + targets[0]);
String message = JavaErrorMessages.message("annotation.not.applicable", nameRef.getText(), target);
return annotationError(annotation, message);
}
if (applicable == PsiAnnotation.TargetType.TYPE_USE) {
if (owner instanceof PsiClassReferenceType) {
PsiJavaCodeReferenceElement ref = ((PsiClassReferenceType)owner).getReference();
HighlightInfo info = checkReferenceTarget(annotation, ref);
if (info != null) return info;
}
else if (owner instanceof PsiModifierList) {
PsiElement nextElement = PsiTreeUtil.skipSiblingsForward((PsiModifierList)owner,
PsiComment.class, PsiWhiteSpace.class, PsiTypeParameterList.class);
if (nextElement instanceof PsiTypeElement) {
PsiTypeElement typeElement = (PsiTypeElement)nextElement;
PsiType type = typeElement.getType();
if (PsiType.VOID.equals(type)) {
String message = JavaErrorMessages.message("annotation.not.allowed.void");
return annotationError(annotation, message);
}
if (!(type instanceof PsiPrimitiveType)) {
PsiJavaCodeReferenceElement ref = getOutermostReferenceElement(typeElement.getInnermostComponentReferenceElement());
HighlightInfo info = checkReferenceTarget(annotation, ref);
if (info != null) return info;
}
}
}
else if (owner instanceof PsiTypeElement) {
PsiElement context = PsiTreeUtil.skipParentsOfType((PsiTypeElement)owner, PsiTypeElement.class);
if (context instanceof PsiClassObjectAccessExpression) {
String message = JavaErrorMessages.message("annotation.not.allowed.class");
return annotationError(annotation, message);
}
}
}
return null;
}
private static HighlightInfo annotationError(PsiAnnotation annotation, String message) {
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(annotation).descriptionAndTooltip(message).create();
QuickFixAction.registerQuickFixAction(info, new DeleteAnnotationAction(annotation));
return info;
}
@Nullable
private static HighlightInfo checkReferenceTarget(PsiAnnotation annotation, @Nullable PsiJavaCodeReferenceElement ref) {
if (ref == null) return null;
PsiElement refTarget = ref.resolve();
if (refTarget == null) return null;
String message = null;
if (!(refTarget instanceof PsiClass)) {
message = JavaErrorMessages.message("annotation.not.allowed.ref");
}
else {
PsiElement parent = ref.getParent();
if (parent instanceof PsiJavaCodeReferenceElement) {
PsiElement qualified = ((PsiJavaCodeReferenceElement)parent).resolve();
if (qualified instanceof PsiMember && ((PsiMember)qualified).hasModifierProperty(PsiModifier.STATIC)) {
message = JavaErrorMessages.message("annotation.not.allowed.static");
}
}
}
return message != null ? annotationError(annotation, message) : null;
}
@Nullable
private static PsiJavaCodeReferenceElement getOutermostReferenceElement(@Nullable PsiJavaCodeReferenceElement ref) {
if (ref == null) return null;
PsiElement qualifier;
while ((qualifier = ref.getQualifier()) instanceof PsiJavaCodeReferenceElement) {
ref = (PsiJavaCodeReferenceElement)qualifier;
}
return ref;
}
public static HighlightInfo checkForeignInnerClassesUsed(final PsiAnnotation annotation) {
final HighlightInfo[] infos = new HighlightInfo[1];
final PsiAnnotationOwner owner = annotation.getOwner();
@@ -463,10 +526,10 @@ public class AnnotationsHighlightUtil {
}
}
private static class DeleteNotApplicableAnnotationAction implements IntentionAction {
private static class DeleteAnnotationAction implements IntentionAction {
private final PsiAnnotation myAnnotation;
public DeleteNotApplicableAnnotationAction(PsiAnnotation annotation) {
public DeleteAnnotationAction(PsiAnnotation annotation) {
myAnnotation = annotation;
}

View File

@@ -1383,7 +1383,7 @@ public class HighlightUtil extends HighlightUtilBase {
if (aClass.isInterface()) {
return thisNotFoundInInterfaceInfo(expr);
}
if (aClass instanceof PsiAnonymousClass && PsiTreeUtil.isAncestor(((PsiAnonymousClass)aClass).getArgumentList(), expr, true)) {
final PsiClass parentClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class, true);
if (parentClass != null && parentClass.isInterface()) {
@@ -2630,7 +2630,7 @@ public class HighlightUtil extends HighlightUtilBase {
return null;
}
private static enum Feature {
private enum Feature {
GENERICS(LanguageLevel.JDK_1_5, "feature.generics"),
ANNOTATIONS(LanguageLevel.JDK_1_5, "feature.annotations"),
STATIC_IMPORTS(LanguageLevel.JDK_1_5, "feature.static.imports"),
@@ -2644,12 +2644,13 @@ public class HighlightUtil extends HighlightUtilBase {
UNDERSCORES(LanguageLevel.JDK_1_7, "feature.underscores.in.literals"),
EXTENSION_METHODS(LanguageLevel.JDK_1_8, "feature.extension.methods"),
METHOD_REFERENCES(LanguageLevel.JDK_1_8, "feature.method.references"),
LAMBDA_EXPRESSIONS(LanguageLevel.JDK_1_8, "feature.lambda.expressions");
LAMBDA_EXPRESSIONS(LanguageLevel.JDK_1_8, "feature.lambda.expressions"),
TYPE_ANNOTATIONS(LanguageLevel.JDK_1_8, "feature.type.annotations");
private final LanguageLevel level;
private final String key;
private Feature(final LanguageLevel level, @PropertyKey(resourceBundle = JavaErrorMessages.BUNDLE) final String key) {
Feature(final LanguageLevel level, @PropertyKey(resourceBundle = JavaErrorMessages.BUNDLE) final String key) {
this.level = level;
this.key = key;
}
@@ -2658,9 +2659,8 @@ public class HighlightUtil extends HighlightUtilBase {
@Nullable
private static HighlightInfo checkFeature(@Nullable final PsiElement element, @NotNull final Feature feature) {
if (element != null && element.getManager().isInProject(element) && !PsiUtil.getLanguageLevel(element).isAtLeast(feature.level)) {
final String message = JavaErrorMessages.message("insufficient.language.level", JavaErrorMessages.message(feature.key));
final HighlightInfo info =
HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(message).create();
String message = JavaErrorMessages.message("insufficient.language.level", JavaErrorMessages.message(feature.key));
HighlightInfo info = HighlightInfo.newHighlightInfo(HighlightInfoType.ERROR).range(element).descriptionAndTooltip(message).create();
QuickFixAction.registerQuickFixAction(info, new IncreaseLanguageLevelFix(feature.level));
QuickFixAction.registerQuickFixAction(info, new ShowModulePropertiesFix(element));
return info;
@@ -2670,57 +2670,62 @@ public class HighlightUtil extends HighlightUtilBase {
}
@Nullable
public static HighlightInfo checkGenericsFeature(final PsiElement parameterList, final int listSize) {
public static HighlightInfo checkGenericsFeature(PsiElement parameterList, int listSize) {
return listSize > 0 ? checkFeature(parameterList, Feature.GENERICS) : null;
}
@Nullable
public static HighlightInfo checkAnnotationFeature(final PsiElement element) {
public static HighlightInfo checkAnnotationFeature(PsiElement element) {
return checkFeature(element, Feature.ANNOTATIONS);
}
@Nullable
public static HighlightInfo checkForEachFeature(final PsiForeachStatement statement) {
public static HighlightInfo checkForEachFeature(PsiForeachStatement statement) {
return checkFeature(statement, Feature.FOR_EACH);
}
@Nullable
public static HighlightInfo checkStaticImportFeature(final PsiImportStaticStatement statement) {
public static HighlightInfo checkStaticImportFeature(PsiImportStaticStatement statement) {
return checkFeature(statement, Feature.STATIC_IMPORTS);
}
@Nullable
public static HighlightInfo checkVarargFeature(final PsiParameter parameter) {
public static HighlightInfo checkVarargFeature(PsiParameter parameter) {
return checkFeature(parameter, Feature.VARARGS);
}
@Nullable
public static HighlightInfo checkDiamondFeature(@NotNull final PsiTypeElement typeElement) {
public static HighlightInfo checkDiamondFeature(PsiTypeElement typeElement) {
return typeElement.getType() instanceof PsiDiamondType ? checkFeature(typeElement.getParent(), Feature.DIAMOND_TYPES) : null;
}
@Nullable
public static HighlightInfo checkMultiCatchFeature(@NotNull final PsiParameter parameter) {
public static HighlightInfo checkMultiCatchFeature(PsiParameter parameter) {
return parameter.getType() instanceof PsiDisjunctionType ? checkFeature(parameter, Feature.MULTI_CATCH) : null;
}
@Nullable
public static HighlightInfo checkTryWithResourcesFeature(@NotNull final PsiResourceVariable resourceVariable) {
public static HighlightInfo checkTryWithResourcesFeature(PsiResourceVariable resourceVariable) {
return checkFeature(resourceVariable.getParent(), Feature.TRY_WITH_RESOURCES);
}
@Nullable
public static HighlightInfo checkExtensionMethodsFeature(final PsiMethod method) {
public static HighlightInfo checkExtensionMethodsFeature(PsiMethod method) {
return checkFeature(method, Feature.EXTENSION_METHODS);
}
@Nullable
public static HighlightInfo checkMethodReferencesFeature(final PsiMethodReferenceExpression expression) {
public static HighlightInfo checkMethodReferencesFeature(PsiMethodReferenceExpression expression) {
return checkFeature(expression, Feature.METHOD_REFERENCES);
}
@Nullable
public static HighlightInfo checkLambdaFeature(final PsiLambdaExpression expression) {
public static HighlightInfo checkLambdaFeature(PsiLambdaExpression expression) {
return checkFeature(expression, Feature.LAMBDA_EXPRESSIONS);
}
@Nullable
public static HighlightInfo checkTypeAnnotationFeature(PsiAnnotation annotation) {
return checkFeature(annotation, Feature.TYPE_ANNOTATIONS);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -41,6 +41,13 @@ public interface PsiAnnotation extends PsiAnnotationMemberValue, PsiMetaOwner {
@NonNls String DEFAULT_REFERENCED_METHOD_NAME = "value";
/**
* Kinds of element to which an annotation type is applicable (see {@link java.lang.annotation.ElementType}).
*/
enum TargetType {
TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, TYPE_USE, TYPE_PARAMETER
}
/**
* Returns the list of parameters for the annotation.
*

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 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,18 +46,35 @@ import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.PairFunction;
import com.intellij.util.SmartList;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.Arrays;
import java.util.List;
import java.util.*;
import static com.intellij.psi.PsiAnnotation.TargetType;
public class PsiImplUtil {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.PsiImplUtil");
private PsiImplUtil() {
}
private static final Set<TargetType> DEFAULT_TARGETS = 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
public static PsiMethod[] getConstructors(@NotNull PsiClass aClass) {
@@ -142,7 +159,7 @@ public class PsiImplUtil {
int i;
for (i = parameters.length - 1; i >= 0; i--) {
PsiParameter paramInList = parameters[i];
if (name.equals(paramInList.getName())) {
if (Comparing.equal(name, paramInList.getName())) {
suspect = paramInList;
break;
}
@@ -298,17 +315,152 @@ public class PsiImplUtil {
return new PsiImmediateClassType(classClass, substitutor);
}
@Nullable public static PsiAnnotation findAnnotation(@NotNull PsiAnnotationOwner modifierList, @NotNull String qualifiedName) {
PsiAnnotation[] annotations = modifierList.getAnnotations();
@Nullable
public static PsiAnnotation findAnnotation(@NotNull PsiAnnotationOwner annotationOwner, @NotNull String qualifiedName) {
PsiAnnotation[] annotations = annotationOwner.getAnnotations();
if (annotations.length == 0) {
return null;
}
final String shortName = StringUtil.getShortName(qualifiedName);
String shortName = StringUtil.getShortName(qualifiedName);
for (PsiAnnotation annotation : annotations) {
final PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement();
PsiJavaCodeReferenceElement referenceElement = annotation.getNameReferenceElement();
if (referenceElement != null && shortName.equals(referenceElement.getReferenceName())) {
if (qualifiedName.equals(annotation.getQualifiedName())) return annotation;
if (qualifiedName.equals(annotation.getQualifiedName())) {
return annotation;
}
}
}
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;
}
public static boolean isAnnotationApplicable(@NotNull PsiAnnotation annotation, boolean strict, @Nullable TargetType... types) {
if (types != null && types.length != 0) {
PsiJavaCodeReferenceElement ref = annotation.getNameReferenceElement();
if (ref != null) {
PsiElement annotationType = ref.resolve();
if (annotationType instanceof PsiClass) {
return findApplicableTarget((PsiClass)annotationType, types) != null;
}
}
}
return !strict;
}
public static boolean isAnnotationApplicable(@NotNull PsiClass annotationType, boolean strict, @Nullable TargetType... types) {
return types == null || types.length == 0 ? !strict : findApplicableTarget(annotationType, types) != null;
}
@Nullable
public static TargetType findApplicableTarget(@NotNull PsiClass annotationType, @NotNull TargetType... types) {
Set<TargetType> targets = getAnnotationTargets(annotationType);
if (targets != null) {
for (TargetType type : types) {
if (targets.contains(type)) {
return type;
}
}
}
return null;
}
@Nullable
private static Set<TargetType> getAnnotationTargets(PsiClass annotationType) {
if (!annotationType.isAnnotationType()) return null;
PsiModifierList modifierList = annotationType.getModifierList();
if (modifierList == null) return null;
// todo[r.sh] cache?
PsiAnnotation target = modifierList.findAnnotation(CommonClassNames.TARGET_ANNOTATION_FQ_NAME);
if (target == null) return DEFAULT_TARGETS; // if omitted it is applicable to all but Java 8 TYPE_USE/TYPE_PARAMETERS targets
PsiNameValuePair[] values = target.getParameterList().getAttributes();
if (values.length == 0) return Collections.emptySet();
PsiAnnotationMemberValue value = values[0].getValue();
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
public static TargetType[] getApplicableTargets(@Nullable PsiAnnotationOwner owner) {
if (owner == null) {
return null;
}
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;
}
}

View File

@@ -20,14 +20,15 @@ import com.intellij.lang.LighterASTNode;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.CommonClassNames;
import com.intellij.psi.JavaTokenType;
import com.intellij.psi.PsiAnnotation;
import com.intellij.psi.PsiNameHelper;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
import com.intellij.psi.impl.java.stubs.PsiAnnotationStub;
import com.intellij.psi.impl.java.stubs.PsiClassStub;
import com.intellij.psi.impl.java.stubs.PsiModifierListStub;
import com.intellij.psi.impl.source.tree.JavaElementType;
import com.intellij.psi.impl.source.tree.LightTreeUtil;
import com.intellij.psi.impl.source.tree.java.PsiAnnotationImpl;
import com.intellij.psi.stubs.StubBase;
import com.intellij.psi.stubs.StubElement;
import com.intellij.psi.stubs.StubInputStream;
@@ -94,8 +95,7 @@ public class TypeInfo {
for (StubElement child : modifierList.getChildrenStubs()) {
if (!(child instanceof PsiAnnotationStub)) continue;
PsiAnnotationStub annotationStub = (PsiAnnotationStub)child;
PsiAnnotationImpl annotation = (PsiAnnotationImpl)annotationStub.getPsiElement();
if (PsiAnnotationImpl.isAnnotationApplicableTo(annotation, true, "TYPE_USE")) {
if (PsiImplUtil.isAnnotationApplicable(annotationStub.getPsiElement(), true, PsiAnnotation.TargetType.TYPE_USE)) {
annotationStubs.add(annotationStub);
}
}

View File

@@ -207,42 +207,24 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme
@Override
public final ASTNode findChildByRole(final int role) {
LOG.assertTrue(ChildRole.isUnique(role));
switch (role) {
default:
return null;
case ChildRole.REFERENCE_NAME:
return TreeUtil.findChildBackward(this, JavaTokenType.IDENTIFIER);
case ChildRole.REFERENCE_NAME:
if (getLastChildNode().getElementType() == JavaTokenType.IDENTIFIER) {
return getLastChildNode();
}
else {
if (getLastChildNode().getElementType() == JavaElementType.REFERENCE_PARAMETER_LIST) {
ASTNode current = getLastChildNode().getTreePrev();
while (current != null && (current.getPsi() instanceof PsiWhiteSpace || current.getPsi() instanceof PsiComment)) {
current = current.getTreePrev();
}
if (current != null && current.getElementType() == JavaTokenType.IDENTIFIER) {
return current;
}
}
return null;
}
case ChildRole.REFERENCE_PARAMETER_LIST:
if (getLastChildNode().getElementType() == JavaElementType.REFERENCE_PARAMETER_LIST) {
return getLastChildNode();
case ChildRole.REFERENCE_PARAMETER_LIST: {
TreeElement lastChild = getLastChildNode();
return lastChild.getElementType() == JavaElementType.REFERENCE_PARAMETER_LIST ? lastChild : null;
}
return null;
case ChildRole.QUALIFIER:
if (getFirstChildNode().getElementType() == JavaElementType.JAVA_CODE_REFERENCE) {
return getFirstChildNode();
}
return null;
return findChildByType(JavaElementType.JAVA_CODE_REFERENCE);
case ChildRole.DOT:
return findChildByType(JavaTokenType.DOT);
return findChildByType(JavaTokenType.DOT);
}
return null;
}
@Override
@@ -712,7 +694,7 @@ public class PsiJavaCodeReferenceElementImpl extends CompositePsiElement impleme
@Override
public boolean isQualified() {
return getChildRole(getFirstChildNode()) != ChildRole.REFERENCE_NAME;
return getQualifier() != null;
}
@Override

View File

@@ -28,7 +28,6 @@ import com.intellij.psi.impl.source.codeStyle.CodeEditUtil;
import com.intellij.psi.impl.source.tree.CompositeElement;
import com.intellij.psi.impl.source.tree.Factory;
import com.intellij.psi.impl.source.tree.TreeElement;
import com.intellij.psi.impl.source.tree.java.PsiAnnotationImpl;
import com.intellij.psi.tree.IElementType;
import com.intellij.util.ArrayUtil;
import com.intellij.util.IncorrectOperationException;
@@ -259,11 +258,11 @@ public class PsiModifierListImpl extends JavaStubPsiElement<PsiModifierListStub>
@Override
@NotNull
public PsiAnnotation[] getApplicableAnnotations() {
final String[] fields = PsiAnnotationImpl.getApplicableElementTypeFields(this);
final PsiAnnotation.TargetType[] targets = PsiImplUtil.getApplicableTargets(this);
List<PsiAnnotation> filtered = ContainerUtil.findAll(getAnnotations(), new Condition<PsiAnnotation>() {
@Override
public boolean value(PsiAnnotation annotation) {
return PsiAnnotationImpl.isAnnotationApplicableTo(annotation, true, fields);
return PsiImplUtil.isAnnotationApplicable(annotation, true, targets);
}
});

View File

@@ -23,7 +23,6 @@ import com.intellij.psi.impl.DebugUtil;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.source.codeStyle.CodeEditUtil;
import com.intellij.psi.impl.source.tree.*;
import com.intellij.psi.impl.source.tree.java.PsiAnnotationImpl;
import com.intellij.psi.scope.PsiScopeProcessor;
import com.intellij.psi.tree.IElementType;
import com.intellij.psi.util.PsiTreeUtil;
@@ -159,10 +158,10 @@ public class PsiTypeElementImpl extends CompositePsiElement implements PsiTypeEl
public static void addTypeUseAnnotationsFromModifierList(PsiElement member, List<PsiAnnotation> typeAnnotations) {
if (!(member instanceof PsiModifierListOwner)) return;
PsiModifierList list = ((PsiModifierListOwner)member).getModifierList();
PsiAnnotation[] gluedAnnotations = list == null ? PsiAnnotation.EMPTY_ARRAY : list.getAnnotations();
for (PsiAnnotation anno : gluedAnnotations) {
if (PsiAnnotationImpl.isAnnotationApplicableTo(anno, true, "TYPE_USE")) {
typeAnnotations.add(anno);
PsiAnnotation[] annotations = list == null ? PsiAnnotation.EMPTY_ARRAY : list.getAnnotations();
for (PsiAnnotation annotation : annotations) {
if (PsiImplUtil.isAnnotationApplicable(annotation, true, PsiAnnotation.TargetType.TYPE_USE)) {
typeAnnotations.add(annotation);
}
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -16,7 +16,6 @@
package com.intellij.psi.impl.source.tree.java;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiImplUtil;
@@ -24,10 +23,9 @@ import com.intellij.psi.impl.java.stubs.JavaStubElementTypes;
import com.intellij.psi.impl.java.stubs.PsiAnnotationStub;
import com.intellij.psi.impl.meta.MetaRegistry;
import com.intellij.psi.impl.source.JavaStubPsiElement;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.intellij.psi.meta.PsiMetaData;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.util.PsiUtil;
import com.intellij.util.PairFunction;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -37,8 +35,6 @@ import org.jetbrains.annotations.Nullable;
* @author ven
*/
public class PsiAnnotationImpl extends JavaStubPsiElement<PsiAnnotationStub> implements PsiAnnotation {
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.source.tree.java.PsiAnnotationImpl");
private static final PairFunction<Project, String, PsiAnnotation> ANNOTATION_CREATOR = new PairFunction<Project, String, PsiAnnotation>() {
@Override
public PsiAnnotation fun(Project project, String text) {
@@ -56,16 +52,12 @@ public class PsiAnnotationImpl extends JavaStubPsiElement<PsiAnnotationStub> imp
@Override
public PsiJavaCodeReferenceElement getNameReferenceElement() {
final PsiAnnotationStub stub = getStub();
PsiAnnotationStub stub = getStub();
if (stub != null) {
return PsiTreeUtil.getRequiredChildOfType(stub.getPsiElement(), PsiJavaCodeReferenceElement.class);
}
final Object result = PsiTreeUtil.getChildOfType(this, PsiJavaCodeReferenceElement.class);
if (result != null && !(result instanceof PsiJavaCodeReferenceElement)) {
throw new AssertionError("getChildOfType returned rubbish: " + result);
}
return (PsiJavaCodeReferenceElement)result;
return PsiTreeUtil.getChildOfType(this, PsiJavaCodeReferenceElement.class);
}
@Override
@@ -122,149 +114,24 @@ public class PsiAnnotationImpl extends JavaStubPsiElement<PsiAnnotationStub> imp
@Override
public PsiAnnotationOwner getOwner() {
PsiElement parent = getParent();
if (!PsiUtil.isLanguageLevel8OrHigher(this)) {
return parent instanceof PsiModifierList ? (PsiAnnotationOwner)parent : null;
}
if (parent instanceof PsiTypeElement) {
return ((PsiTypeElement)parent).getOwner(this);
}
if (parent instanceof PsiTypeParameter) {
if (parent instanceof PsiAnnotationOwner) {
return (PsiAnnotationOwner)parent;
}
PsiElement member = parent.getParent();
String[] elementTypeFields = getApplicableElementTypeFields(member);
if (elementTypeFields == null) return null;
if (parent instanceof PsiAnnotationOwner
&& isAnnotationApplicableTo(this, true, elementTypeFields)) return (PsiAnnotationOwner)parent;
PsiAnnotationOwner typeElement;
if (member instanceof PsiVariable) {
if (member instanceof PsiEnumConstant && parent instanceof PsiAnnotationOwner){
return (PsiAnnotationOwner)parent;
}
typeElement = ((PsiVariable)member).getTypeElement();
}
else if (member instanceof PsiMethod && !((PsiMethod)member).isConstructor()) {
typeElement = ((PsiMethod)member).getReturnTypeElement();
}
else if (parent instanceof PsiAnnotationOwner) {
typeElement = (PsiAnnotationOwner)parent;
}
else {
typeElement = null;
}
return typeElement;
}
public static boolean isAnnotationApplicableTo(PsiAnnotation annotation, boolean strict, String... elementTypeFields) {
if (elementTypeFields == null) return true;
PsiJavaCodeReferenceElement nameRef = annotation.getNameReferenceElement();
if (nameRef == null) {
return !strict;
}
PsiElement resolved = nameRef.resolve();
if (!(resolved instanceof PsiClass) || !((PsiClass)resolved).isAnnotationType()) {
return !strict;
}
PsiClass annotationType = (PsiClass)resolved;
return isAnnotationApplicable(strict, annotationType, elementTypeFields, annotation.getResolveScope());
}
public static boolean isAnnotationApplicable(boolean strict,
@NotNull PsiClass annotationType,
@Nullable String[] elementTypeFields,
GlobalSearchScope resolveScope) {
if (elementTypeFields == null) {
return !strict;
}
PsiAnnotation target = annotationType.getModifierList().findAnnotation(CommonClassNames.TARGET_ANNOTATION_FQ_NAME);
if (target == null) {
//todo hack: ambiguity in spec
return !strict;
//return !ArrayUtil.contains("TYPE_USE", elementTypeFields);
}
PsiNameValuePair[] attributes = target.getParameterList().getAttributes();
if (attributes.length == 0) {
return !strict;
}
LOG.assertTrue(elementTypeFields.length > 0);
PsiClass elementTypeClass =
JavaPsiFacade.getInstance(annotationType.getProject()).findClass("java.lang.annotation.ElementType", resolveScope);
if (elementTypeClass == null) {
//todo hack
return !strict;
//return !ArrayUtil.contains("TYPE_USE", elementTypeFields);
}
PsiAnnotationMemberValue value = null;
for (String fieldName : elementTypeFields) {
PsiField field = elementTypeClass.findFieldByName(fieldName, false);
if (field == null) {
continue;
}
if (value == null) {
value = attributes[0].getValue();
}
if (value instanceof PsiArrayInitializerMemberValue) {
PsiAnnotationMemberValue[] initializers = ((PsiArrayInitializerMemberValue)value).getInitializers();
for (PsiAnnotationMemberValue initializer : initializers) {
if (initializer instanceof PsiReference) {
if (((PsiReference)initializer).isReferenceTo(field)) {
return true;
}
}
}
}
else if (value instanceof PsiReference) {
if (((PsiReference)value).isReferenceTo(field)) {
return true;
}
if (parent instanceof PsiReferenceExpression) {
PsiElement ctx = parent.getParent();
if (ctx instanceof PsiMethodReferenceExpression) {
return new PsiClassReferenceType((PsiJavaCodeReferenceElement)parent, null);
}
}
return false;
}
@Nullable
public static String[] getApplicableElementTypeFields(PsiElement owner) {
if (owner instanceof PsiClass) {
PsiClass aClass = (PsiClass)owner;
if (aClass.isAnnotationType()) {
return new String[]{"ANNOTATION_TYPE", "TYPE"};
else if (parent instanceof PsiJavaCodeReferenceElement) {
PsiElement ctx = PsiTreeUtil.skipParentsOfType(parent, PsiJavaCodeReferenceElement.class);
if (ctx instanceof PsiReferenceList || ctx instanceof PsiNewExpression || ctx instanceof PsiTypeElement) {
return new PsiClassReferenceType((PsiJavaCodeReferenceElement)parent, null);
}
else if (aClass instanceof PsiTypeParameter) {
return new String[]{"TYPE_PARAMETER"};
}
else {
return new String[]{"TYPE"};
}
}
if (owner instanceof PsiMethod) {
if (((PsiMethod)owner).isConstructor()) {
return new String[]{"CONSTRUCTOR"};
}
else {
return new String[]{"METHOD"};
}
}
if (owner instanceof PsiField) {
return new String[]{"FIELD"};
}
if (owner instanceof PsiParameter) {
return new String[]{"PARAMETER"};
}
if (owner instanceof PsiLocalVariable) {
return new String[]{"LOCAL_VARIABLE"};
}
if (owner instanceof PsiPackageStatement) {
return new String[]{"PACKAGE"};
}
if (owner instanceof PsiTypeElement) {
return new String[]{"TYPE_USE"};
}
return null;
}
}
}

View File

@@ -16,6 +16,10 @@ annotation.annotation.type.expected=Annotation type expected
annotation.members.may.not.have.throws.list=@interface members may not have throws list
annotation.may.not.have.extends.list=@interface may not have extends list
annotation.name.is.missing=Annotation attribute must be of the form 'name=value'
annotation.not.allowed.ref=Annotation not applicable to this kind of reference
annotation.not.allowed.static=Static member qualifying type may not be annotated
annotation.not.allowed.void='void' type may not be annotated
annotation.not.allowed.class=Class literal type may not be annotated
# These aren't unused.
# suppress inspection "UnusedProperty"
@@ -364,4 +368,5 @@ feature.underscores.in.literals=Underscores in literals
feature.extension.methods=Extension methods
feature.method.references=Method references
feature.lambda.expressions=Lambda expressions
feature.type.annotations=Type annotations
insufficient.language.level={0} are not supported at this language level

View File

@@ -1,6 +1,6 @@
import java.util.List;
@<error descr="'@SafeVarargs' not applicable to type">SafeVarargs</error>
<error descr="'@SafeVarargs' not applicable to type">@SafeVarargs</error>
public class SafeVarargsTests {
//fixed arity
<error descr="@SafeVarargs is not allowed on methods with fixed arity">@SafeVarargs</error>

View File

@@ -5,4 +5,4 @@ import java.lang.annotation.*;
@Expose @interface Expose {}
@Target({ElementType.FIELD})
@<error descr="'@Expose1' not applicable to annotation type">Expose1</error>@interface Expose1 {}
<error descr="'@Expose1' not applicable to annotation type">@Expose1</error>@interface Expose1 {}

View File

@@ -1 +1 @@
@<error descr="'@SuppressWarnings' not applicable to package">SuppressWarnings</error>("all") package annotations.invalidPackageAnnotationTarget;
<error descr="'@SuppressWarnings' not applicable to package">@SuppressWarnings("all")</error> package annotations.invalidPackageAnnotationTarget;

View File

@@ -1,33 +1,141 @@
import java.lang.annotation.Target;
import java.lang.annotation.ElementType;
import java.lang.annotation.*;
import java.io.*;
import java.util.*;
import java.io.<error descr="Annotations are not allowed here">@SuppressWarnings</error> Reader;
import <error descr="Annotations are not allowed here">@SuppressWarnings</error> java.io.Writer;
import static java.lang.annotation.ElementType.*;
@Target({ElementType.TYPE_USE/*, ElementType.TYPE*/})
@interface TA {
}
/*@Target({CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})*/ @interface A { }
@Target({TYPE_USE}) @interface TA { }
@Target({TYPE_PARAMETER}) @interface TPA { }
@<error descr="'@TA' not applicable to type">TA</error>
class X0<@<error descr="'@TA' not applicable to type parameter">TA</error> T> {
@TA
protected
void f() @<error descr="'@TA' not applicable to parameter">TA</error> {
@TA String p=new @TA String();
@A @TA <error descr="'@TPA' not applicable to type">@TPA</error>
class Outer {
private Map<@TA String, @TA List<@TA <error descr="'@A' not applicable to type use">@A</error> String>> m;
if (this instanceof @TA Object) return;
String o = p;
List<@TA String> l;
Class c = @TA String.class;
interface I { void m(int i); }
private I i = (@TA <error descr="'@Override' not applicable to parameter">@Override</error> final int k) -> { };
<error descr="'void' type may not be annotated">@TA</error> <T> void m(T t) { }
<error descr="'void' type may not be annotated">@TA</error> void test1() {
this.<@TA <error descr="'@TPA' not applicable to type use">@TPA</error> String>m("...");
}
class FF<F extends @TA String> { }
Collection<? super @TA String> cs;
interface BI<T> { }
class BII<T> implements @TA BI<@TA T> { }
class BIII extends @TA BII<Object> { }
void tm() throws @TA RuntimeException { }
class Middle {
class Inner {
void test() {
@TA Inner v1;
@TA Middle.@TA Inner v2;
@TA Outer.@TA Middle.@TA Inner v3;
@TA Outer v4;
@TA Outer.@TA Middle v5;
@TA Outer.@TA Middle.@TA Inner v6;
List<@TA Outer.@TA Middle.@TA Inner> l;
}
}
}
@TA int @TA[] methodf() throws @TA Exception {
boolean a = this instanceof @TA X0;
X0<@<error descr="Duplicate annotation">TA</error> @<error descr="Duplicate annotation">TA</error> X0> c = new @TA X0<@TA X0>();
Object o = (@TA Object) c;
@TA X0.field = null;
return null;
static class StaticMiddle {
static class StaticInner {
void test() {
@TA StaticInner v1;
<error descr="Static member qualifying type may not be annotated">@TA</error> StaticMiddle.@TA StaticInner v2;
<error descr="Static member qualifying type may not be annotated">@TA</error> Outer.<error descr="Static member qualifying type may not be annotated">@TA</error> StaticMiddle.@TA StaticInner v3;
List<@TA Outer.<error descr="Static member qualifying type may not be annotated">@TA</error> StaticMiddle.@TA StaticInner> l;
}
}
}
@TA() int @TA[] p;
static @TA Object field;
@TA List<String> disambiguateBetweenBinaryExpr;
{
new @TA Object();
new @TA ArrayList<String>();
ArrayList<String> var = new <String> @TA ArrayList();
new @TA Outer().new @TA Middle();
@A Map.@TA Entry e1;
@A <error descr="Static member qualifying type may not be annotated">@TA</error> Map.@TA Entry e2;
@A java.<error descr="Annotation not applicable to this kind of reference">@TA</error> util.Map.@TA Entry e3;
@A List<java.<error descr="Annotation not applicable to this kind of reference">@TA</error> lang.@TA String> l1;
Object obj = "str";
@TA String str = (@TA String)obj;
boolean b = str instanceof @TA String;
<error descr="Annotations are not allowed here">@TA</error> tm();
try (@TA Reader r = new @TA FileReader("/dev/zero"); @TA Writer w = new @TA FileWriter("/dev/null")) { }
catch (@TA IllegalArgumentException | @TA IOException e) { }
@A @TA <error descr="Cannot resolve symbol 'Unknown'">Unknown</error>.@TA Unknown uu;
Class<?> c1 = <error descr="Class literal type may not be annotated">@TA</error> String.class;
Class<?> c2 = int <error descr="Class literal type may not be annotated">@TA</error> [].class;
}
interface IntFunction<T> { int apply(T t); }
interface Sorter<T> { void sort(T[] a, Comparator<? super T> c); }
void m1(IntFunction<Date> f) { }
void m2(IntFunction<List<String>> f) { }
void m3(Sorter<Integer> s) { }
void lambdas() {
m1(@TA Date::getDay);
m1(<error descr="Annotations are not allowed here">@TA</error> java.util.@TA Date::getDay);
m2(List<@TA String>::size);
m3(Arrays::<@TA Integer>sort);
Comparator<Object> cmp = (@TA Object x, @TA Object y) -> { System.out.println("x=" + x + " y=" + y); return 0; };
}
void m(List<@TA ? extends Comparable<Object>> p) { }
void arrays(String @TA ... docs) {
//todo[r.sh]
//@TA String @TA [] @TA [] docs1 = new @TA String @TA [2] @TA [2];
}
@TA Outer() { }
class MyClass<@TA @TPA T> { }
interface MyInterface<@TA @TPA E> { }
static class Super {
protected int aField;
int getField() { return aField; }
}
static class This extends Super {
void superField() {
Outer.<error descr="Annotations are not allowed here">@TA</error> This.super.aField = 0;
IntFunction<Super> f = Outer.<error descr="Annotations are not allowed here">@TA</error> This.super::getField;
}
}
//todo[r.sh]
/*public String toString(@TA C this) { return ""; }
public boolean equals(@TA C this, @TA C other) { return false; }
C(@TA C this, boolean b) { }
class Outer {
class Middle {
class Inner {
void innerMethod(@TA Outer.@TA Middle.@TA Inner this) { }
}
}
}*/
List<@<error descr="Duplicate annotation">TA</error> @<error descr="Duplicate annotation">TA</error> String> c = null;
}

View File

@@ -15,14 +15,14 @@ abstract class C {
void notWrong() { }
}
class B extends <error descr="Annotations are not allowed here">@Deprecated</error> Object { }
class B extends <error descr="Type annotations are not supported at this language level">@Deprecated</error> Object { }
enum E {
@Anno E1
}
interface I {
@<error descr="Duplicate annotation">Anno</error> public @<error descr="Duplicate annotation">Anno</error> Collection<<error descr="Annotations are not allowed here">@Anno</error> String> method(@<error descr="Duplicate annotation">Anno</error> @<error descr="Duplicate annotation">Anno</error> Object o);
@<error descr="Duplicate annotation">Anno</error> public @<error descr="Duplicate annotation">Anno</error> Collection<<error descr="Type annotations are not supported at this language level">@Anno</error> String> method(@<error descr="Duplicate annotation">Anno</error> @<error descr="Duplicate annotation">Anno</error> Object o);
}
@interface Caller {

View File

@@ -3,10 +3,10 @@ interface I {
}
class Foo {
I ii = (@<error descr="'@Override' not applicable to type use">Override</error> final int k)->{
I ii = (<error descr="'@Override' not applicable to parameter">@Override</error> final int k) -> {
int j = k;
};
I ii1 = (final int k)->{
I ii1 = (final int k) -> {
<error descr="Incompatible types. Found: 'int', required: 'java.lang.String'">String s = k;</error>
};
@@ -14,24 +14,24 @@ class Foo {
bar((<error descr="Incompatible parameter types in lambda expression">String s</error>) -> {
System.out.println(s);});
bar((int i) -> {System.out.println(i);});
}
void bar(I i){}
}
void bar(I i) { }
}
class ReturnTypeCompatibility {
interface I1<L> {
L m(L x);
}
interface I1<L> {
L m(L x);
}
static <P> void call(I1<P> i2) {
i2.m(null);
}
static <P> void call(I1<P> i2) {
i2.m(null);
}
public static void main(String[] args) {
call((String i)->{ return i;});
call(<error descr="Cyclic inference">i->{ return i;}</error>);
call(<error descr="Cyclic inference">i->""</error>);
call<error descr="'call(ReturnTypeCompatibility.I1<java.lang.Integer>)' in 'ReturnTypeCompatibility' cannot be applied to '(<lambda expression>)'">((int i)->{ return i;})</error>;
}
public static void main(String[] args) {
call((String i)->{ return i;});
call(<error descr="Cyclic inference">i->{ return i;}</error>);
call(<error descr="Cyclic inference">i->""</error>);
call<error descr="'call(ReturnTypeCompatibility.I1<java.lang.Integer>)' in 'ReturnTypeCompatibility' cannot be applied to '(<lambda expression>)'">((int i)->{ return i;})</error>;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -22,13 +22,7 @@ import org.jetbrains.annotations.NonNls;
* @author ven
*/
public class AnnotationsHighlightingTest extends LightDaemonAnalyzerTestCase {
@NonNls
private static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/annotations";
private void doTest(boolean checkWarnings) {
setLanguageLevel(LanguageLevel.JDK_1_7);
doTest(BASE_PATH + "/" + getTestName(true) + ".java", checkWarnings, false);
}
@NonNls private static final String BASE_PATH = "/codeInsight/daemonCodeAnalyzer/annotations";
public void testWrongPlace() { doTest(false); }
public void testNotValueNameOmitted() { doTest(false); }
@@ -49,5 +43,15 @@ public class AnnotationsHighlightingTest extends LightDaemonAnalyzerTestCase {
public void testInvalidPackageAnnotationTarget() { doTest(BASE_PATH + "/" + getTestName(true) + "/package-info.java", false, false); }
public void testPackageAnnotationNotInPackageInfo() { doTest(BASE_PATH + "/" + getTestName(true) + "/notPackageInfo.java", false, false); }
//public void testTypeAnnotations() { doTest(false); } // todo[r.sh] make separate test with correct language level
public void testTypeAnnotations() { doTest8(false); }
private void doTest(boolean checkWarnings) {
setLanguageLevel(LanguageLevel.JDK_1_7);
doTest(BASE_PATH + "/" + getTestName(true) + ".java", checkWarnings, false);
}
private void doTest8(boolean checkWarnings) {
setLanguageLevel(LanguageLevel.JDK_1_8);
doTest(BASE_PATH + "/" + getTestName(true) + ".java", checkWarnings, false);
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -114,8 +114,8 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase {
}
private void setupCustomAnnotations() {
myFixture.addClass("package foo; public @interface Nullable {}");
myFixture.addClass("package foo; public @interface NotNull {}");
myFixture.addClass("package foo;\n\nimport java.lang.annotation.*;\n\n@Target({ElementType.TYPE_USE}) public @interface Nullable { }");
myFixture.addClass("package foo;\n\nimport java.lang.annotation.*;\n\n@Target({ElementType.TYPE_USE}) public @interface NotNull { }");
final NullableNotNullManager nnnManager = NullableNotNullManager.getInstance(getProject());
nnnManager.setNotNulls("foo.NotNull");
nnnManager.setNullables("foo.Nullable");
@@ -140,7 +140,7 @@ public class DataFlowInspectionTest extends LightCodeInsightFixtureTestCase {
}
public void testConstantDoubleComparisons() { doTest(); }
public void testMutableNullableFieldsTreatment() { doTest(); }
public void testMutableVolatileNullableFieldsTreatment() { doTest(); }
public void testMutableNotAnnotatedFieldsTreatment() { doTest(); }

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2000-2012 JetBrains s.r.o.
* Copyright 2000-2013 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.
@@ -20,8 +20,8 @@ import com.intellij.codeInsight.completion.CompletionWeigher;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.PsiTypeLookupItem;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.light.LightElement;
import com.intellij.psi.impl.source.tree.java.PsiAnnotationImpl;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.util.containers.ContainerUtil;
@@ -98,7 +98,7 @@ public class GrKindWeigher extends CompletionWeigher {
PsiElement annoParent = annotation.getParent();
PsiElement owner = annoParent.getParent();
String[] elementTypeFields = GrAnnotationImpl.getApplicableElementTypeFields(annoParent instanceof PsiModifierList ? owner : annoParent);
if (PsiAnnotationImpl.isAnnotationApplicable(false, (PsiClass)o, elementTypeFields, position.getResolveScope())) {
if (PsiImplUtil.isAnnotationApplicable((PsiClass)o, false, GrAnnotationImpl.translate(elementTypeFields))) {
return NotQualifiedKind.restrictedClass;
}
}
@@ -149,11 +149,11 @@ public class GrKindWeigher extends CompletionWeigher {
final PsiClass containingClass = o.getContainingClass();
return containingClass != null && TRASH_CLASSES.contains(containingClass.getQualifiedName());
}
private static boolean isAccessor(PsiMember member) {
return member instanceof PsiMethod && (GroovyPropertyUtils.isSimplePropertyAccessor((PsiMethod)member) || "setProperty".equals(((PsiMethod)member).getName()));
}
private static boolean isQualifierClassMember(PsiMember member, PsiElement qualifier) {
if (!(qualifier instanceof GrExpression)) return false;

View File

@@ -17,13 +17,14 @@
package org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation;
import com.intellij.lang.ASTNode;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiImplUtil;
import com.intellij.psi.impl.light.LightClassReference;
import com.intellij.psi.impl.source.tree.java.PsiAnnotationImpl;
import com.intellij.psi.meta.PsiMetaData;
import com.intellij.util.PairFunction;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -46,11 +47,15 @@ import org.jetbrains.plugins.groovy.lang.psi.impl.GrStubElementBase;
import org.jetbrains.plugins.groovy.lang.psi.stubs.GrAnnotationStub;
import org.jetbrains.plugins.groovy.lang.resolve.ResolveUtil;
import java.util.List;
/**
* @author: Dmitry.Krasilschikov
* @date: 04.04.2007
*/
public class GrAnnotationImpl extends GrStubElementBase<GrAnnotationStub> implements GrAnnotation, StubBasedPsiElement<GrAnnotationStub> {
private static final Logger LOG = Logger.getInstance("#org.jetbrains.plugins.groovy.lang.psi.impl.auxiliary.annotation.GrAnnotationImpl");
private static final PairFunction<Project, String, PsiAnnotation> ANNOTATION_CREATOR = new PairFunction<Project, String, PsiAnnotation>() {
public PsiAnnotation fun(Project project, String text) {
return GroovyPsiElementFactory.getInstance(project).createAnnotationFromText(text);
@@ -188,14 +193,23 @@ public class GrAnnotationImpl extends GrStubElementBase<GrAnnotationStub> implem
return null;
}
@Nullable
public static TargetType[] translate(@Nullable String... types) {
if (types == null) return null;
List<TargetType> targets = ContainerUtil.newArrayListWithExpectedSize(types.length);
for (String type : types) {
try {
targets.add(TargetType.valueOf(type));
}
catch (IllegalArgumentException e) {
LOG.error("Unknown target: " + type);
}
}
return targets.toArray(new TargetType[targets.size()]);
}
public static boolean isAnnotationApplicableTo(GrAnnotation annotation, boolean strict, String... elementTypeFields) {
if (elementTypeFields == null) return true;
GrCodeReferenceElement nameRef = annotation.getClassReference();
PsiElement resolved = nameRef.resolve();
if (resolved instanceof PsiClass && ((PsiClass)resolved).isAnnotationType()) {
return PsiAnnotationImpl.isAnnotationApplicable(strict, (PsiClass)resolved, elementTypeFields, annotation.getResolveScope());
}
return !strict;
return elementTypeFields == null || PsiImplUtil.isAnnotationApplicable(annotation, strict, translate(elementTypeFields));
}
}