/**
* Copyright (c) 2017-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
package com.facebook.litho.specmodels.processor;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.TypeElement;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;
import com.facebook.litho.specmodels.internal.ImmutableList;
import com.facebook.litho.annotations.Prop;
import com.facebook.litho.annotations.State;
import com.facebook.litho.annotations.TreeProp;
import com.facebook.litho.specmodels.model.DelegateMethodModel;
import com.facebook.litho.specmodels.model.MethodParamModel;
import com.squareup.javapoet.TypeName;
import static com.facebook.litho.specmodels.processor.MethodExtractorUtils.getMethodParams;
/**
* Extracts delegate methods from the given input.
*/
public class DelegateMethodExtractor {
private static final List<Class<? extends Annotation>> METHOD_PARAM_ANNOTATIONS =
new ArrayList<>();
static {
METHOD_PARAM_ANNOTATIONS.add(Prop.class);
METHOD_PARAM_ANNOTATIONS.add(State.class);
METHOD_PARAM_ANNOTATIONS.add(TreeProp.class);
}
/**
* Get the delegate methods from the given {@link TypeElement}.
*/
public static ImmutableList<DelegateMethodModel> getDelegateMethods(
TypeElement typeElement,
List<Class<? extends Annotation>> permittedMethodAnnotations,
List<Class<? extends Annotation>> permittedInterStageInputAnnotations) {
final List<DelegateMethodModel> delegateMethods = new ArrayList<>();
for (Element enclosedElement : typeElement.getEnclosedElements()) {
if (enclosedElement.getKind() != ElementKind.METHOD) {
continue;
}
final List<Annotation> methodAnnotations =
getMethodAnnotations(enclosedElement, permittedMethodAnnotations);
if (!methodAnnotations.isEmpty()) {
final ExecutableElement executableElement = (ExecutableElement) enclosedElement;
final List<MethodParamModel> methodParams =
getMethodParams(
executableElement,
getPermittedMethodParamAnnotations(permittedInterStageInputAnnotations),
permittedInterStageInputAnnotations);
final DelegateMethodModel delegateMethod =
new DelegateMethodModel(
ImmutableList.copyOf(methodAnnotations),
ImmutableList.copyOf(new ArrayList<>(executableElement.getModifiers())),
executableElement.getSimpleName(),
TypeName.get(executableElement.getReturnType()),
ImmutableList.copyOf(methodParams),
enclosedElement);
delegateMethods.add(delegateMethod);
}
}
return ImmutableList.copyOf(delegateMethods);
}
private static List<Annotation> getMethodAnnotations(
Element method,
List<Class<? extends Annotation>> permittedMethodAnnotations) {
List<Annotation> methodAnnotations = new ArrayList<>();
for (Class<? extends Annotation> possibleDelegateMethodAnnotation :
permittedMethodAnnotations) {
final Annotation methodAnnotation =
method.getAnnotation(possibleDelegateMethodAnnotation);
if (methodAnnotation != null) {
methodAnnotations.add(methodAnnotation);
}
}
return methodAnnotations;
}
private static List<Class<? extends Annotation>> getPermittedMethodParamAnnotations(
List<Class<? extends Annotation>> permittedInterStageInputAnnotations) {
final List<Class<? extends Annotation>> permittedMethodParamAnnotations =
new ArrayList<>(METHOD_PARAM_ANNOTATIONS);
permittedMethodParamAnnotations.addAll(permittedInterStageInputAnnotations);
return permittedMethodParamAnnotations;
}
}