private static void findAnnotatedElements(
      Element element,
      ImmutableSet<TypeElement> annotationTypes,
      ImmutableSetMultimap.Builder<TypeElement, Element> annotatedElements) {
    for (Element enclosedElement : element.getEnclosedElements()) {
      if (!enclosedElement.getKind().isClass() && !enclosedElement.getKind().isInterface()) {
        findAnnotatedElements(enclosedElement, annotationTypes, annotatedElements);
      }
    }

    // element.getEnclosedElements() does NOT return parameter or type parameter elements

    Parameterizable parameterizable = null;
    if (isType(element)) {
      parameterizable = asType(element);
    } else if (isExecutable(element)) {
      ExecutableElement executableElement = asExecutable(element);
      parameterizable = executableElement;
      for (VariableElement parameterElement : executableElement.getParameters()) {
        findAnnotatedElements(parameterElement, annotationTypes, annotatedElements);
      }
    }
    if (parameterizable != null) {
      for (TypeParameterElement parameterElement : parameterizable.getTypeParameters()) {
        findAnnotatedElements(parameterElement, annotationTypes, annotatedElements);
      }
    }

    for (TypeElement annotationType : annotationTypes) {
      if (isAnnotationPresent(element, annotationType)) {
        annotatedElements.put(annotationType, element);
      }
    }
  }
Adds {@code element} and its enclosed elements to {@code annotatedElements} if they are
annotated with any annotations in {@code annotationTypes}. Does not traverse to member types of
{@code element}, so that if {@code Outer} is passed in the example below, looking for
{@code @X}, then {@code Outer}, {@code Outer.foo}, and {@code Outer.foo()} will be added to the
multimap, but neither {@code Inner} nor its members will.

<pre>{@code
@X class Outer {
  @X Object foo;
  @X void foo() {}
  @X static class Inner {
    @X Object bar;
    @X void bar() {}
  }
}
}</pre>
common/src/main/java/com/google/auto/common/BasicAnnotationProcessor.java