// Path: src/main/java/org/spongepowered/eventimplgen/AnnotationUtils.java
// public final class AnnotationUtils {
// 
//     private AnnotationUtils() {
//     }
// 
//     @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"})
//     public static <T> T getValue(final AnnotationMirror anno, final String key) {
//         if (anno == null) {
//             return null;
//         }
// 
//         for (final Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> element : anno.getElementValues().entrySet()) {
//             if (element.getKey().getSimpleName().contentEquals(key)) {
//                 return (T) element.getValue().getValue();
//             }
//         }
//         return null;
//     }
// 
//     public static @Nullable AnnotationMirror getAnnotation(final AnnotatedConstruct type, final Class<? extends Annotation> clazz) {
//         return AnnotationUtils.getAnnotation(type, clazz.getName());
//     }
// 
//     public static @Nullable AnnotationMirror getAnnotation(final AnnotatedConstruct type, final String name) {
//         for (final AnnotationMirror annotation : type.getAnnotationMirrors()) {
//             if (((TypeElement) annotation.getAnnotationType().asElement()).getQualifiedName().toString().equals(name)) {
//                 return annotation;
//             }
//         }
//         return null;
//     }
// 
//     public static boolean containsAnnotation(final AnnotatedConstruct type, final Set<String> looking) {
//         for (final AnnotationMirror annotation : type.getAnnotationMirrors()) {
//             if (looking.contains(((TypeElement) annotation.getAnnotationType().asElement()).getQualifiedName().toString())) {
//                 return true;
//             }
//         }
//         return false;
//     }
// }
// 
// Path: src/main/java/org/spongepowered/eventimplgen/eventgencore/PropertySearchStrategy.java
// public interface PropertySearchStrategy {
// 
//     /**
//      * Enumerate a list of properties on a class, considering super types
//      * and implemented interfaces.
//      *
//      * <p>The returned list is sorted lexographically by property name</p>
//      *
//      * @param type The class
//      * @return A set of properties
//      */
//     List<Property> findProperties(final TypeElement type);
// 
// }


import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.api.util.annotation.eventgen.FactoryMethod;
import org.spongepowered.api.util.annotation.eventgen.internal.GeneratedEvent;
import org.spongepowered.eventimplgen.AnnotationUtils;
import org.spongepowered.eventimplgen.eventgencore.PropertySearchStrategy;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Queue;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
import javax.inject.Inject;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.QualifiedNameable;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;
                            this.messager.printMessage(Diagnostic.Kind.NOTE, "Generating for event " + event.getSimpleName());
                        }
                        final Set<Element> extraOriginating;
                        if (pointer.parent == null) {
                            extraOriginating = Collections.emptySet();
                        } else {
                            extraOriginating = new HashSet<>();
                            OriginatedElement collector = pointer.parent;
                            do {
                                extraOriginating.add(collector.element);
                            } while ((collector = collector.parent) != null);
                        }
                        consumer.propertyFound(event, this.strategy.findProperties(event), extraOriginating);
                        consumer.forwardedMethods(this.findForwardedMethods(event));
                    }
                }
            } else if (active.getKind() == ElementKind.CLASS
                && active.getAnnotation(GeneratedEvent.class) != null) {
                continue; // these implementation classes are indirectly annotated, but because we generated them we can ignore them.
            } else if (active.getKind() != ElementKind.ENUM) { // implicitly exclude enums, they are commonly declared nested in event interfaces
                this.messager.printMessage(Diagnostic.Kind.ERROR, "This element (" + active.getKind() + " " + active.getSimpleName() + ")  was "
                    + "annotated directly or transitively, but it is not a package or interface", active);
                failed = true;
            }
        }

        return !failed;
    }

    public boolean hasExclusiveAnnotation(final Element candidate) {
// Path: src/main/java/org/spongepowered/eventimplgen/AnnotationUtils.java
// public final class AnnotationUtils {
// 
//     private AnnotationUtils() {
//     }
// 
//     @SuppressWarnings({"unchecked", "TypeParameterUnusedInFormals"})
//     public static <T> T getValue(final AnnotationMirror anno, final String key) {
//         if (anno == null) {
//             return null;
//         }
// 
//         for (final Map.Entry<? extends ExecutableElement, ? extends AnnotationValue> element : anno.getElementValues().entrySet()) {
//             if (element.getKey().getSimpleName().contentEquals(key)) {
//                 return (T) element.getValue().getValue();
//             }
//         }
//         return null;
//     }
// 
//     public static @Nullable AnnotationMirror getAnnotation(final AnnotatedConstruct type, final Class<? extends Annotation> clazz) {
//         return AnnotationUtils.getAnnotation(type, clazz.getName());
//     }
// 
//     public static @Nullable AnnotationMirror getAnnotation(final AnnotatedConstruct type, final String name) {
//         for (final AnnotationMirror annotation : type.getAnnotationMirrors()) {
//             if (((TypeElement) annotation.getAnnotationType().asElement()).getQualifiedName().toString().equals(name)) {
//                 return annotation;
//             }
//         }
//         return null;
//     }
// 
//     public static boolean containsAnnotation(final AnnotatedConstruct type, final Set<String> looking) {
//         for (final AnnotationMirror annotation : type.getAnnotationMirrors()) {
//             if (looking.contains(((TypeElement) annotation.getAnnotationType().asElement()).getQualifiedName().toString())) {
//                 return true;
//             }
//         }
//         return false;
//     }
// }
// 
// Path: src/main/java/org/spongepowered/eventimplgen/eventgencore/PropertySearchStrategy.java
// public interface PropertySearchStrategy {
// 
//     /**
//      * Enumerate a list of properties on a class, considering super types
//      * and implemented interfaces.
//      *
//      * <p>The returned list is sorted lexographically by property name</p>
//      *
//      * @param type The class
//      * @return A set of properties
//      */
//     List<Property> findProperties(final TypeElement type);
// 
// }


// Path: src/main/java/org/spongepowered/eventimplgen/processor/EventScanner.java
import org.checkerframework.checker.nullness.qual.Nullable;
import org.spongepowered.api.util.annotation.eventgen.FactoryMethod;
import org.spongepowered.api.util.annotation.eventgen.internal.GeneratedEvent;
import org.spongepowered.eventimplgen.AnnotationUtils;
import org.spongepowered.eventimplgen.eventgencore.PropertySearchStrategy;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Queue;
import java.util.Set;
import java.util.regex.Pattern;
import java.util.stream.Stream;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
import javax.inject.Inject;
import javax.lang.model.element.AnnotationMirror;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.PackageElement;
import javax.lang.model.element.QualifiedNameable;
import javax.lang.model.element.TypeElement;
import javax.lang.model.type.DeclaredType;
import javax.lang.model.type.TypeKind;
import javax.lang.model.type.TypeMirror;
import javax.lang.model.util.ElementFilter;
import javax.lang.model.util.Elements;
import javax.lang.model.util.Types;
import javax.tools.Diagnostic;

                            this.messager.printMessage(Diagnostic.Kind.NOTE, "Generating for event " + event.getSimpleName());
                        }
                        final Set<Element> extraOriginating;
                        if (pointer.parent == null) {
                            extraOriginating = Collections.emptySet();
                        } else {
                            extraOriginating = new HashSet<>();
                            OriginatedElement collector = pointer.parent;
                            do {
                                extraOriginating.add(collector.element);
                            } while ((collector = collector.parent) != null);
                        }
                        consumer.propertyFound(event, this.strategy.findProperties(event), extraOriginating);
                        consumer.forwardedMethods(this.findForwardedMethods(event));
                    }
                }
            } else if (active.getKind() == ElementKind.CLASS
                && active.getAnnotation(GeneratedEvent.class) != null) {
                continue; // these implementation classes are indirectly annotated, but because we generated them we can ignore them.
            } else if (active.getKind() != ElementKind.ENUM) { // implicitly exclude enums, they are commonly declared nested in event interfaces
                this.messager.printMessage(Diagnostic.Kind.ERROR, "This element (" + active.getKind() + " " + active.getSimpleName() + ")  was "
                    + "annotated directly or transitively, but it is not a package or interface", active);
                failed = true;
            }
        }

        return !failed;
    }

    public boolean hasExclusiveAnnotation(final Element candidate) {
        return AnnotationUtils.containsAnnotation(candidate, this.exclusiveAnnotations);