/** * Returns whether the given type element has a public default constructor. */ @Pure public static boolean hasPublicDefaultConstructor(@Nonnull TypeElement typeElement) { return getConstructors(typeElement).matchAny(constructor -> constructor.getParameters().isEmpty() && constructor.getModifiers().contains(Modifier.PUBLIC)); }
@Pure @Override public void checkUsage(@Nonnull Element element, @Nonnull AnnotationMirror annotationMirror, @NonCaptured @Modified @Nonnull ErrorLogger errorLogger) { if (element.getKind() == ElementKind.PARAMETER) { final @Nonnull Element enclosingElement = element.getEnclosingElement(); if (!(enclosingElement.getKind() == ElementKind.CONSTRUCTOR && ProcessingUtility.getConstructors(ProcessingUtility.getSurroundingType(element)).isSingle() || ProcessingUtility.hasAnnotation(enclosingElement, Recover.class))) { errorLogger.log("The generation annotation may only be used on parameters of a unique constructor or an executable annotated with '@Recover'.", SourcePosition.of(element, annotationMirror)); } } else if (element.getKind() == ElementKind.METHOD) { final @Nonnull ExecutableElement method = (ExecutableElement) element; if (!method.getModifiers().contains(Modifier.ABSTRACT)/* || !ProcessingUtility.isGetter(method)*/) { // TODO: @Default also has to be allowed on generated properties. errorLogger.log("The generation annotation may only be used on abstract getters.", SourcePosition.of(element, annotationMirror)); } } else { errorLogger.log("The generation annotation may only be used on parameters and methods.", SourcePosition.of(element, annotationMirror)); } }
@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()); } } }
/** * Creates an instantiable type information object. */ protected InstantiableTypeInformation(@Nonnull TypeElement typeElement, @Nonnull DeclaredType containingType) { super(typeElement, containingType); this.methodInformationIterable = InformationFilter.getMethodInformation(typeElement, containingType, this); ProcessingLog.debugging("All methods of type $: $", containingType, methodInformationIterable.join()); this.recoverMethod = methodInformationIterable.findFirst(method -> method.hasAnnotation(Recover.class)); this.directlyAccessibleDeclaredFields = InformationFilter.getDirectlyAccessibleFieldInformation(typeElement); this.nonDirectlyAccessibleDeclaredFields = InformationFilter.getNonDirectlyAccessibleFieldInformation(typeElement, methodInformationIterable); this.nonAccessibleDeclaredFields = InformationFilter.getNonAccessibleFieldInformation(typeElement, methodInformationIterable); this.constructors = ProcessingUtility.getConstructors(typeElement).map((element) -> (ConstructorInformation.of(element, containingType, this))); }