{
// Suggest remove applies to
String message = message(
"applies.to.annotation.declared.correctly.error.annotation.must.be.declared.on.class"
);
ProblemDescriptor problemDescriptor = createRemoveAppliesToFilterProblemDescriptor(
manager, message, appliesToAnnotation );
return new ProblemDescriptor[]{ problemDescriptor };
}
// If @AppliesTo annotation is empty, ignore
List<PsiAnnotationMemberValue> appliesToAnnotationValues = getAppliesToAnnotationValue( appliesToAnnotation );
if( appliesToAnnotationValues.isEmpty() )
{
return null;
}
// If AppliesToFilter is not resolved, ignore
Project project = psiClass.getProject();
GlobalSearchScope searchScope = determineSearchScope( psiClass );
PsiClass appliesToFilterClass = getAppliesToFilterClass( project, searchScope );
if( appliesToFilterClass == null )
{
return null;
}
boolean classIsAConcern = isAConcern( psiClass );
boolean classIsASideEffect = isASideEffect( psiClass );
boolean classIsAGenericConcern = classIsAConcern && isAGenericConcern( psiClass );
boolean classIsAGenericSideEffect = classIsASideEffect && isAGenericSideEffect( psiClass );
boolean classIsAMixin = !classIsAConcern && !classIsASideEffect;
boolean classIsAGenericMixin = classIsAMixin && isImplementsInvocationHandler( psiClass );
List<ProblemDescriptor> problems = new LinkedList<ProblemDescriptor>();
for( PsiAnnotationMemberValue appliesToAnnotationValue : appliesToAnnotationValues )
{
PsiJavaCodeReferenceElement appliesToValueClassReference =
getAppliesToValueClassReference( appliesToAnnotationValue );
// If it's not a class reference, ignore
if( appliesToValueClassReference == null )
{
continue;
}
// If class reference can't be resolved, ignore
PsiClass appliesToValueClass = (PsiClass) appliesToValueClassReference.resolve();
if( appliesToValueClass == null )
{
continue;
}
String appliesToValueQualifiedName = appliesToValueClass.getQualifiedName();
boolean appliesToValueIsAnAnnotation = appliesToValueClass.isAnnotationType();
boolean appliesToValueIsImplementingAppliesToFilter =
appliesToValueClass.isInheritor( appliesToFilterClass, true );
String message = null;
if( appliesToValueIsAnAnnotation && classIsAMixin )
{
// If Class is a mixin and appliesToValueClass is an annotation
message = message(
"applies.to.annotation.declared.correctly.error.value.is.invalid.for.mixin",
appliesToValueQualifiedName
);
}
else if( appliesToValueIsAnAnnotation || appliesToValueIsImplementingAppliesToFilter )
{
if( classIsAConcern && !classIsAGenericConcern )
{
// If psiClass is a concern but not generic concern
message = message(
"applies.to.annotation.declared.correctly.error.value.requires.class.to.extends.GenericConcern",
appliesToValueQualifiedName, classQualifiedName
);
}
else if( classIsASideEffect && !classIsAGenericSideEffect )
{
// If psiClass a side effect but not a generic side effect
message = message(
"applies.to.annotation.declared.correctly.error.value.requires.class.to.extends.GenericSideEffect",
appliesToValueQualifiedName, classQualifiedName
);
}
else if( appliesToValueIsImplementingAppliesToFilter && !classIsAGenericMixin )
{
message = message(
"applies.to.annotation.declared.correctly.error.value.requires.class.to.implements.InvocationHandler",
appliesToValueQualifiedName, classQualifiedName
);
}
}
else if( appliesToValueClass.isInterface() )
{
if( !psiClass.isInheritor( appliesToValueClass, true ) &&
!( classIsAGenericConcern || classIsAGenericSideEffect ) )
{
// If psiClass does not implement that interface and it's not a generic concern or generic side effect
if( classIsAConcern )
{
message = message(
"applies.to.annotation.declared.correctly.error.value.requires.class.to.implement.interface.or.extends.GenericConcern",
appliesToValueQualifiedName, classQualifiedName );
}
else if( classIsASideEffect )
{
message = message(
"applies.to.annotation.declared.correctly.error.value.requires.class.to.implement.interface.or.extends.GenericSideEffect",
appliesToValueQualifiedName, classQualifiedName );
}
else
{
message = message(
"applies.to.annotation.declared.correctly.error.value.requires.class.to.implement.value.interface.or.implements.InvocationHandler",
appliesToValueQualifiedName, classQualifiedName );
}
}
}
else
{
if( classIsAMixin )
{
message = message(
"applies.to.annotation.declared.correctly.error.value.is.invalid.for.mixin",
appliesToValueQualifiedName
);
}
else
{
message = message(
"applies.to.annotation.declared.correctly.error.annotation.value.is.invalid.for.non.mixin",
appliesToValueQualifiedName
);
}
}
if( message != null )
{
ProblemDescriptor problemDescriptor = manager.createProblemDescriptor(
appliesToAnnotationValue,
message,
new RemoveAnnotationValueFix( appliesToAnnotationValue, appliesToValueClassReference ),
GENERIC_ERROR_OR_WARNING );
problems.add( problemDescriptor );