1/*
2 * Copyright (c) 2013, 2015, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23package org.graalvm.compiler.replacements.verifier;
24
25import java.lang.annotation.Annotation;
26import java.util.ArrayList;
27import java.util.HashSet;
28import java.util.List;
29import java.util.Set;
30
31import javax.annotation.processing.AbstractProcessor;
32import javax.annotation.processing.ProcessingEnvironment;
33import javax.annotation.processing.RoundEnvironment;
34import javax.lang.model.SourceVersion;
35import javax.lang.model.element.AnnotationMirror;
36import javax.lang.model.element.Element;
37import javax.lang.model.element.TypeElement;
38import javax.lang.model.type.DeclaredType;
39
40public class VerifierAnnotationProcessor extends AbstractProcessor {
41
42    private List<AbstractVerifier> verifiers;
43
44    @Override
45    public SourceVersion getSupportedSourceVersion() {
46        return SourceVersion.latest();
47    }
48
49    @Override
50    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
51        if (!roundEnv.processingOver()) {
52            PluginGenerator generator = new PluginGenerator();
53            for (AbstractVerifier verifier : getVerifiers()) {
54                Class<? extends Annotation> annotationClass = verifier.getAnnotationClass();
55                for (Element e : roundEnv.getElementsAnnotatedWith(annotationClass)) {
56                    AnnotationMirror annotationMirror = findAnnotationMirror(processingEnv, e.getAnnotationMirrors(), annotationClass);
57                    if (annotationMirror == null) {
58                        assert false : "Annotation mirror always expected.";
59                        continue;
60                    }
61                    verifier.verify(e, annotationMirror, generator);
62                }
63            }
64
65            generator.generateAll(processingEnv);
66        }
67        return false;
68    }
69
70    public static AnnotationMirror findAnnotationMirror(ProcessingEnvironment processingEnv, List<? extends AnnotationMirror> mirrors, Class<?> annotationClass) {
71        TypeElement expectedAnnotationType = processingEnv.getElementUtils().getTypeElement(annotationClass.getCanonicalName());
72        for (AnnotationMirror mirror : mirrors) {
73            DeclaredType annotationType = mirror.getAnnotationType();
74            TypeElement actualAnnotationType = (TypeElement) annotationType.asElement();
75            if (actualAnnotationType.equals(expectedAnnotationType)) {
76                return mirror;
77            }
78        }
79        return null;
80    }
81
82    public List<AbstractVerifier> getVerifiers() {
83        /*
84         * Initialized lazily to fail(CNE) when the processor is invoked and not when it is created.
85         */
86        if (verifiers == null) {
87            assert this.processingEnv != null : "ProcessingEnv must be initialized before calling getVerifiers.";
88            verifiers = new ArrayList<>();
89            verifiers.add(new ClassSubstitutionVerifier(this.processingEnv));
90            verifiers.add(new MethodSubstitutionVerifier(this.processingEnv));
91            verifiers.add(new NodeIntrinsicVerifier(this.processingEnv));
92            verifiers.add(new FoldVerifier(this.processingEnv));
93        }
94        return verifiers;
95    }
96
97    @Override
98    public Set<String> getSupportedAnnotationTypes() {
99        Set<String> annotationTypes = new HashSet<>();
100        for (AbstractVerifier verifier : getVerifiers()) {
101            annotationTypes.add(verifier.getAnnotationClass().getCanonicalName());
102        }
103        return annotationTypes;
104    }
105
106}
107