@Pure @Override public void checkUsage(@Nonnull Element element, @Nonnull AnnotationMirror annotationMirror, @NonCaptured @Modified @Nonnull ErrorLogger errorLogger) { final @Nonnull TypeElement surroundingType = ProcessingUtility.getSurroundingType(element); if (element.getKind() == ElementKind.METHOD) { final @Nonnull ExecutableElement method = (ExecutableElement) element; final @Nonnull Types typeUtils = StaticProcessingEnvironment.getTypeUtils(); if (!element.getModifiers().contains(Modifier.STATIC) || !typeUtils.isSubtype(method.getReturnType(), typeUtils.erasure(surroundingType.asType()))) { errorLogger.log("The annotation $ may only be used on static methods whose return type is a subtype of the surrounding type.", SourcePosition.of(element, annotationMirror), getAnnotationNameWithLeadingAt()); } } else if (element.getKind() == ElementKind.CONSTRUCTOR) { if (ProcessingUtility.getConstructors(surroundingType).isSingle()) { errorLogger.log("The annotation $ may only be used on constructors if there are also other constructors in the same class.", SourcePosition.of(element, annotationMirror), getAnnotationNameWithLeadingAt()); } } else { errorLogger.log("The annotation $ may only be used on methods and constructors.", SourcePosition.of(element, annotationMirror), getAnnotationNameWithLeadingAt()); } for (@Nonnull ExecutableElement executableElement : ProcessingUtility.getConstructors(surroundingType).combine(ProcessingUtility.getMethods(surroundingType))) { if (ProcessingUtility.hasAnnotation(executableElement, Recover.class) && !executableElement.equals(element)) { errorLogger.log("The annotation $ may only be used on at most one executable in the same type.", SourcePosition.of(element, annotationMirror), getAnnotationNameWithLeadingAt()); } } }