/** * Returns whether the given surrounding type has a (static) method (with the given suffix) to check the validity of an instance of the given element type. */ @Pure protected static boolean hasMethodToCheckValidity(@Nonnull DeclaredType declaredType, @Nonnull TypeMirror elementType, boolean onlyStatic, @Nonnull String suffix) { for (@Nonnull ExecutableElement inheritedMethod : ProcessingUtility.getAllMethods((TypeElement) declaredType.asElement())) { if (inheritedMethod.getThrownTypes().isEmpty() && inheritedMethod.getSimpleName().contentEquals("isValid" + suffix) && !inheritedMethod.getModifiers().contains(Modifier.PRIVATE) && (!onlyStatic || inheritedMethod.getModifiers().contains(Modifier.STATIC)) && inheritedMethod.getReturnType().getKind() == TypeKind.BOOLEAN) { final @Nonnull ExecutableType methodType = (ExecutableType) StaticProcessingEnvironment.getTypeUtils().asMemberOf(declaredType, inheritedMethod); if (methodType.getParameterTypes().size() == 1 && StaticProcessingEnvironment.getTypeUtils().isAssignable(elementType, methodType.getParameterTypes().get(0))) { return true; } } } return false; }
/** * Returns the non-private method with the given name, return type, parameter types and no thrown types in the given type element or null if no such method is found. */ @Pure public static @Nullable ExecutableElement getNonPrivateMethod(@Nonnull TypeElement typeElement, @Nonnull String methodName, @Nonnull Class<?> returnType, @Nonnull @NonNullableElements Class<?>... parameterTypes) { final @Nonnull DeclaredType surroundingType = (DeclaredType) typeElement.asType(); for (@Nonnull ExecutableElement inheritedMethod : getAllMethods(typeElement)) { if (!inheritedMethod.getModifiers().contains(Modifier.PRIVATE) && inheritedMethod.getSimpleName().contentEquals(methodName) && inheritedMethod.getThrownTypes().isEmpty()) { final @Nonnull ExecutableType methodType = (ExecutableType) StaticProcessingEnvironment.getTypeUtils().asMemberOf(surroundingType, inheritedMethod); if (isRawSubtype(methodType.getReturnType(), returnType)) { if (methodType.getParameterTypes().size() == parameterTypes.length) { boolean isAssignable = true; for (int i = 0; i < parameterTypes.length; i++) { final @Nonnull TypeMirror parameterType = methodType.getParameterTypes().get(i); if (parameterType.getKind() == TypeKind.TYPEVAR || !correspond(parameterType, parameterTypes[i])) { isAssignable = false; } } if (isAssignable) { return inheritedMethod; } } } } } return null; }
@Pure @Override public void checkUsage(@Nonnull Element element, @Nonnull AnnotationMirror annotationMirror, @NonCaptured @Modified @Nonnull ErrorLogger errorLogger) { if (element.getKind() != ElementKind.INTERFACE) { errorLogger.log("Only an interface can be functional.", SourcePosition.of(element, annotationMirror)); } else { boolean found = false; for (@Nonnull ExecutableElement method : ProcessingUtility.getAllMethods((TypeElement) element)) { if (method.getModifiers().contains(Modifier.ABSTRACT)) { if (found) { errorLogger.log("The functional interface $ may have only one abstract method.", SourcePosition.of(method), element); } else { found = true; } } } if (!found) { errorLogger.log("The functional interface $ has to have an abstract method.", SourcePosition.of(element), element); } } }
@Pure @Override public void checkUsage(@Nonnull Element element, @Nonnull AnnotationMirror annotationMirror, @NonCaptured @Modified @Nonnull ErrorLogger errorLogger) { for (@Nonnull ExecutableElement method : ProcessingUtility.getAllMethods((TypeElement) element).filter(ProcessingUtility::isDeclaredInDigitalIDLibrary).filterNot(method -> method.getModifiers().contains(Modifier.STATIC))) { if (!ProcessingUtility.hasAnnotation(method, Pure.class) && !ProcessingUtility.hasAnnotation(method, PureWithSideEffects.class)) { errorLogger.log("The read-only type $ may only contain pure non-static methods.", SourcePosition.of(method), element); } } for (@Nonnull VariableElement field : ProcessingUtility.getAllFields((TypeElement) element).filter(ProcessingUtility::isDeclaredInDigitalIDLibrary).filterNot(field -> field.getModifiers().contains(Modifier.STATIC))) { if (!field.getModifiers().contains(Modifier.FINAL)) { errorLogger.log("The read-only type $ may only contain final non-static fields.", SourcePosition.of(field), element); } } }
@Pure @Override public void checkUsage(@Nonnull Element element, @Nonnull AnnotationMirror annotationMirror, @NonCaptured @Modified @Nonnull ErrorLogger errorLogger) { for (@Nonnull ExecutableElement method : ProcessingUtility.getAllMethods((TypeElement) element).filter(ProcessingUtility::isDeclaredInDigitalIDLibrary).filterNot(method -> method.getModifiers().contains(Modifier.STATIC))) { if (!ProcessingUtility.hasAnnotation(method, Pure.class) && !ProcessingUtility.hasAnnotation(method, PureWithSideEffects.class)) { errorLogger.log("The immutable type $ may only contain pure non-static methods.", SourcePosition.of(method), element); } } for (@Nonnull VariableElement field : ProcessingUtility.getAllFields((TypeElement) element).filter(ProcessingUtility::isDeclaredInDigitalIDLibrary).filterNot(field -> field.getModifiers().contains(Modifier.STATIC))) { if (!field.getModifiers().contains(Modifier.FINAL)) { errorLogger.log("The immutable type $ may only contain final non-static fields.", SourcePosition.of(field), element); } } }