/* * Copyright (C) 2016 Bradley Campbell. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package paperparcel; import com.google.auto.common.Visibility; import com.google.common.collect.ImmutableList; import java.lang.annotation.Annotation; import javax.lang.model.element.ElementKind; import javax.lang.model.element.ExecutableElement; import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; import javax.lang.model.type.TypeMirror; import javax.lang.model.util.Elements; import javax.lang.model.util.Types; /** A validator for any {@link PaperParcel} annotated {@link TypeElement} */ final class PaperParcelValidator { private final Elements elements; private final Types types; PaperParcelValidator( Elements elements, Types types) { this.elements = elements; this.types = types; } ValidationReport<TypeElement> validate(TypeElement element, OptionsDescriptor options) { ValidationReport.Builder<TypeElement> builder = ValidationReport.about(element); if (element.getKind() != ElementKind.CLASS) { builder.addError(ErrorMessages.PAPERPARCEL_ON_NON_CLASS); } if (element.getModifiers().contains(Modifier.ABSTRACT)) { builder.addError(ErrorMessages.PAPERPARCEL_ON_ABSTRACT_CLASS); } if (!Utils.isParcelable(elements, types, element.asType())) { builder.addError(ErrorMessages.PAPERPARCEL_ON_NON_PARCELABLE); } if (implementsAnnotation(elements, types, element)) { builder.addError(ErrorMessages.PAPERPARCEL_ON_ANNOTATION); } ElementKind enclosingKind = element.getEnclosingElement().getKind(); if (enclosingKind.isClass() || enclosingKind.isInterface()) { if (Visibility.ofElement(element) == Visibility.PRIVATE) { builder.addError(ErrorMessages.PAPERPARCEL_ON_PRIVATE_CLASS); } if (!element.getModifiers().contains(Modifier.STATIC)) { builder.addError(ErrorMessages.PAPERPARCEL_ON_NON_STATIC_INNER_CLASS); } } if (options.excludeNonExposedFields() && options.exposeAnnotationNames().isEmpty()) { builder.addError(ErrorMessages.NO_EXPOSE_ANNOTATIONS_DEFINED, element, options.mirror()); } if (!Utils.isSingleton(types, element)) { ImmutableList<ExecutableElement> constructors = Utils.orderedConstructorsIn(element, options.reflectAnnotations()); if (constructors.size() == 0) { builder.addError(ErrorMessages.PAPERPARCEL_NO_VISIBLE_CONSTRUCTOR); } ImmutableList<VariableElement> fields = Utils.getFieldsToParcel(element, options); for (VariableElement field : fields) { if (Utils.containsWildcards(field.asType())) { builder.addError(ErrorMessages.WILDCARD_IN_FIELD_TYPE, field); } else if (Utils.isRawType(field.asType())) { builder.addError(ErrorMessages.FIELD_MISSING_TYPE_ARGUMENTS, field); } else if (Utils.hasRecursiveTypeParameter(field.asType())) { builder.addError(ErrorMessages.FIELD_TYPE_IS_RECURSIVE, field); } else if (Utils.containsIntersection(field.asType())) { builder.addError(ErrorMessages.FIELD_TYPE_IS_INTERSECTION_TYPE, field); } } } return builder.build(); } private boolean implementsAnnotation(Elements elements, Types types, TypeElement type) { TypeMirror annotationType = elements.getTypeElement(Annotation.class.getName()).asType(); return types.isAssignable(type.asType(), annotationType); } }