private AutoValueExtension.Context createContext(TypeElement type) { String packageName = MoreElements.getPackage(type).getQualifiedName().toString(); Set<ExecutableElement> allMethods = MoreElements.getLocalAndInheritedMethods(type, elements); Set<ExecutableElement> methods = methodsToImplement(type, allMethods); Map<String, ExecutableElement> properties = new LinkedHashMap<String, ExecutableElement>(); for (ExecutableElement e : methods) { properties.put(e.getSimpleName().toString(), e); } return new TestContext(processingEnvironment, packageName, type, properties); }
private static void getLocalAndInheritedMethods( PackageElement pkg, TypeElement type, SetMultimap<String, ExecutableElement> methods) { for (TypeMirror superInterface : type.getInterfaces()) { getLocalAndInheritedMethods(pkg, MoreTypes.asTypeElement(superInterface), methods); } if (type.getSuperclass().getKind() != TypeKind.NONE) { // Visit the superclass after superinterfaces so we will always see the implementation of a // method after any interfaces that declared it. getLocalAndInheritedMethods(pkg, MoreTypes.asTypeElement(type.getSuperclass()), methods); } for (ExecutableElement method : ElementFilter.methodsIn(type.getEnclosedElements())) { if (!method.getModifiers().contains(Modifier.STATIC) && methodVisibleFromPackage(method, pkg)) { methods.put(method.getSimpleName().toString(), method); } } }
/** * Returns the set of all non-private methods from {@code type}, including methods that it * inherits from its ancestors. Inherited methods that are overridden are not included in the * result. So if {@code type} defines {@code public String toString()}, the returned set will * contain that method, but not the {@code toString()} method defined by {@code Object}. * * <p>The returned set may contain more than one method with the same signature, if * {@code type} inherits those methods from different ancestors. For example, if it * inherits from unrelated interfaces {@code One} and {@code Two} which each define * {@code void foo();}, and if it does not itself override the {@code foo()} method, * then both {@code One.foo()} and {@code Two.foo()} will be in the returned set. * * @param type the type whose own and inherited methods are to be returned * @param typeUtils a {@link Types} object, typically returned by * {@link javax.annotation.processing.AbstractProcessor#processingEnv processingEnv}<!-- * -->.{@link javax.annotation.processing.ProcessingEnvironment#getTypeUtils * getTypeUtils()} * @param elementUtils an {@link Elements} object, typically returned by * {@link javax.annotation.processing.AbstractProcessor#processingEnv processingEnv}<!-- * -->.{@link javax.annotation.processing.ProcessingEnvironment#getElementUtils * getElementUtils()} */ public static ImmutableSet<ExecutableElement> getLocalAndInheritedMethods( TypeElement type, Types typeUtils, Elements elementUtils) { // TODO(emcmanus): detect if the Types and Elements are the javac ones, and use // NativeOverrides if so. We may need to adjust the logic further to avoid the bug // tested for by MoreElementsTest.getLocalAndInheritedMethods_DaggerBug. Overrides overrides = new Overrides.ExplicitOverrides(typeUtils); return getLocalAndInheritedMethods(type, overrides); }
/** * Returns the set of all non-private methods from {@code type}, including methods that it * inherits from its ancestors. Inherited methods that are overridden are not included in the * result. So if {@code type} defines {@code public String toString()}, the returned set will * contain that method, but not the {@code toString()} method defined by {@code Object}. * * <p>The returned set may contain more than one method with the same signature, if * {@code type} inherits those methods from different ancestors. For example, if it * inherits from unrelated interfaces {@code One} and {@code Two} which each define * {@code void foo();}, and if it does not itself override the {@code foo()} method, * then both {@code One.foo()} and {@code Two.foo()} will be in the returned set. * * @param type the type whose own and inherited methods are to be returned * @param elementUtils an {@link Elements} object, typically returned by * {@link javax.annotation.processing.AbstractProcessor#processingEnv processingEnv}<!-- * -->.{@link javax.annotation.processing.ProcessingEnvironment#getElementUtils * getElementUtils()} * * @deprecated The method {@link #getLocalAndInheritedMethods(TypeElement, Types, Elements)} * has better consistency between Java compilers. */ @Deprecated public static ImmutableSet<ExecutableElement> getLocalAndInheritedMethods( TypeElement type, Elements elementUtils) { Overrides overrides = new Overrides.NativeOverrides(elementUtils); return getLocalAndInheritedMethods(type, overrides); }
private static ImmutableSet<ExecutableElement> getLocalAndInheritedMethods( TypeElement type, Overrides overrides) { SetMultimap<String, ExecutableElement> methodMap = LinkedHashMultimap.create(); getLocalAndInheritedMethods(getPackage(type), type, methodMap); // Find methods that are overridden. We do this using `Elements.overrides`, which means // that it is inherently a quadratic operation, since we have to compare every method against // every other method. We reduce the performance impact by (a) grouping methods by name, since // a method cannot override another method with a different name, and (b) making sure that // methods in ancestor types precede those in descendant types, which means we only have to // check a method against the ones that follow it in that order. Set<ExecutableElement> overridden = new LinkedHashSet<ExecutableElement>(); for (Collection<ExecutableElement> methods : methodMap.asMap().values()) { List<ExecutableElement> methodList = ImmutableList.copyOf(methods); for (int i = 0; i < methodList.size(); i++) { ExecutableElement methodI = methodList.get(i); for (int j = i + 1; j < methodList.size(); j++) { ExecutableElement methodJ = methodList.get(j); if (overrides.overrides(methodJ, methodI, type)) { overridden.add(methodI); } } } } Set<ExecutableElement> methods = new LinkedHashSet<ExecutableElement>(methodMap.values()); methods.removeAll(overridden); return ImmutableSet.copyOf(methods); }