43972
|
1 |
/*
|
50330
|
2 |
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
|
43972
|
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 |
*/
|
50858
|
23 |
|
|
24 |
|
43972
|
25 |
package org.graalvm.compiler.nodeinfo.processor;
|
|
26 |
|
|
27 |
import static java.util.Collections.reverse;
|
|
28 |
|
|
29 |
import java.io.PrintWriter;
|
|
30 |
import java.io.StringWriter;
|
|
31 |
import java.util.ArrayList;
|
|
32 |
import java.util.List;
|
|
33 |
import java.util.Set;
|
|
34 |
import java.util.stream.Collectors;
|
|
35 |
|
|
36 |
import javax.annotation.processing.FilerException;
|
|
37 |
import javax.annotation.processing.RoundEnvironment;
|
|
38 |
import javax.annotation.processing.SupportedAnnotationTypes;
|
|
39 |
import javax.annotation.processing.SupportedSourceVersion;
|
|
40 |
import javax.lang.model.SourceVersion;
|
50330
|
41 |
import javax.lang.model.element.AnnotationMirror;
|
43972
|
42 |
import javax.lang.model.element.Element;
|
|
43 |
import javax.lang.model.element.ElementKind;
|
|
44 |
import javax.lang.model.element.Modifier;
|
|
45 |
import javax.lang.model.element.TypeElement;
|
|
46 |
import javax.lang.model.util.Types;
|
|
47 |
import javax.tools.Diagnostic.Kind;
|
|
48 |
|
50330
|
49 |
import org.graalvm.compiler.processor.AbstractProcessor;
|
43972
|
50 |
|
50330
|
51 |
/**
|
|
52 |
* Processor for {@value #NODE_INFO_CLASS_NAME} annotation.
|
|
53 |
*/
|
43972
|
54 |
@SupportedSourceVersion(SourceVersion.RELEASE_8)
|
|
55 |
@SupportedAnnotationTypes({"org.graalvm.compiler.nodeinfo.NodeInfo"})
|
|
56 |
public class GraphNodeProcessor extends AbstractProcessor {
|
50330
|
57 |
private static final String NODE_INFO_CLASS_NAME = "org.graalvm.compiler.nodeinfo.NodeInfo";
|
|
58 |
|
43972
|
59 |
@Override
|
|
60 |
public SourceVersion getSupportedSourceVersion() {
|
|
61 |
return SourceVersion.latest();
|
|
62 |
}
|
|
63 |
|
|
64 |
/**
|
|
65 |
* Node class currently being processed.
|
|
66 |
*/
|
|
67 |
private Element scope;
|
|
68 |
|
|
69 |
public static boolean isEnclosedIn(Element e, Element scopeElement) {
|
|
70 |
List<Element> elementHierarchy = getElementHierarchy(e);
|
|
71 |
return elementHierarchy.contains(scopeElement);
|
|
72 |
}
|
|
73 |
|
|
74 |
void errorMessage(Element element, String format, Object... args) {
|
|
75 |
message(Kind.ERROR, element, format, args);
|
|
76 |
}
|
|
77 |
|
|
78 |
void message(Kind kind, Element element, String format, Object... args) {
|
|
79 |
if (scope != null && !isEnclosedIn(element, scope)) {
|
|
80 |
// See https://bugs.eclipse.org/bugs/show_bug.cgi?id=428357#c1
|
|
81 |
List<Element> elementHierarchy = getElementHierarchy(element);
|
|
82 |
reverse(elementHierarchy);
|
|
83 |
String loc = elementHierarchy.stream().filter(e -> e.getKind() != ElementKind.PACKAGE).map(Object::toString).collect(Collectors.joining("."));
|
|
84 |
processingEnv.getMessager().printMessage(kind, String.format(loc + ": " + format, args), scope);
|
|
85 |
} else {
|
|
86 |
processingEnv.getMessager().printMessage(kind, String.format(format, args), element);
|
|
87 |
}
|
|
88 |
}
|
|
89 |
|
|
90 |
private static List<Element> getElementHierarchy(Element e) {
|
|
91 |
List<Element> elements = new ArrayList<>();
|
|
92 |
elements.add(e);
|
|
93 |
|
|
94 |
Element enclosing = e.getEnclosingElement();
|
|
95 |
while (enclosing != null && enclosing.getKind() != ElementKind.PACKAGE) {
|
|
96 |
elements.add(enclosing);
|
|
97 |
enclosing = enclosing.getEnclosingElement();
|
|
98 |
}
|
|
99 |
if (enclosing != null) {
|
|
100 |
elements.add(enclosing);
|
|
101 |
}
|
|
102 |
return elements;
|
|
103 |
}
|
|
104 |
|
|
105 |
/**
|
|
106 |
* Bugs in an annotation processor can cause silent failure so try to report any exception
|
|
107 |
* throws as errors.
|
|
108 |
*/
|
|
109 |
private void reportException(Kind kind, Element element, Throwable t) {
|
|
110 |
StringWriter buf = new StringWriter();
|
|
111 |
t.printStackTrace(new PrintWriter(buf));
|
|
112 |
message(kind, element, "Exception thrown during processing: %s", buf.toString());
|
|
113 |
}
|
|
114 |
|
|
115 |
boolean isNodeType(Element element) {
|
|
116 |
if (element.getKind() != ElementKind.CLASS) {
|
|
117 |
return false;
|
|
118 |
}
|
|
119 |
TypeElement type = (TypeElement) element;
|
|
120 |
Types types = processingEnv.getTypeUtils();
|
|
121 |
|
|
122 |
while (type != null) {
|
|
123 |
if (type.toString().equals("org.graalvm.compiler.graph.Node")) {
|
|
124 |
return true;
|
|
125 |
}
|
|
126 |
type = (TypeElement) types.asElement(type.getSuperclass());
|
|
127 |
}
|
|
128 |
return false;
|
|
129 |
}
|
|
130 |
|
|
131 |
@Override
|
52578
|
132 |
public boolean doProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
|
43972
|
133 |
if (roundEnv.processingOver()) {
|
|
134 |
return false;
|
|
135 |
}
|
|
136 |
|
|
137 |
GraphNodeVerifier verifier = new GraphNodeVerifier(this);
|
|
138 |
|
50330
|
139 |
for (Element element : roundEnv.getElementsAnnotatedWith(getTypeElement(NODE_INFO_CLASS_NAME))) {
|
43972
|
140 |
scope = element;
|
|
141 |
try {
|
|
142 |
if (!isNodeType(element)) {
|
50330
|
143 |
errorMessage(element, "%s can only be applied to Node subclasses", getSimpleName(NODE_INFO_CLASS_NAME));
|
43972
|
144 |
continue;
|
|
145 |
}
|
|
146 |
|
50330
|
147 |
AnnotationMirror nodeInfo = getAnnotation(element, getType(NODE_INFO_CLASS_NAME));
|
43972
|
148 |
if (nodeInfo == null) {
|
50330
|
149 |
errorMessage(element, "Cannot get %s annotation from annotated element", getSimpleName(NODE_INFO_CLASS_NAME));
|
43972
|
150 |
continue;
|
|
151 |
}
|
|
152 |
|
|
153 |
TypeElement typeElement = (TypeElement) element;
|
|
154 |
|
|
155 |
Set<Modifier> modifiers = typeElement.getModifiers();
|
|
156 |
if (!modifiers.contains(Modifier.FINAL) && !modifiers.contains(Modifier.ABSTRACT)) {
|
|
157 |
// TODO(thomaswue): Reenable this check.
|
|
158 |
// errorMessage(element, "%s annotated class must be either final or abstract",
|
50330
|
159 |
// getSimpleName(NODE_INFO_CLASS_NAME));
|
43972
|
160 |
// continue;
|
|
161 |
}
|
|
162 |
boolean found = false;
|
|
163 |
for (Element e : typeElement.getEnclosedElements()) {
|
|
164 |
if (e.getKind() == ElementKind.FIELD) {
|
|
165 |
if (e.getSimpleName().toString().equals("TYPE")) {
|
|
166 |
found = true;
|
|
167 |
break;
|
|
168 |
}
|
|
169 |
}
|
|
170 |
}
|
|
171 |
if (!found) {
|
50330
|
172 |
errorMessage(element, "%s annotated class must have a field named TYPE", getSimpleName(NODE_INFO_CLASS_NAME));
|
43972
|
173 |
}
|
|
174 |
|
|
175 |
if (!typeElement.equals(verifier.Node) && !modifiers.contains(Modifier.ABSTRACT)) {
|
|
176 |
verifier.verify(typeElement);
|
|
177 |
}
|
|
178 |
} catch (ElementException ee) {
|
|
179 |
errorMessage(ee.element, ee.getMessage());
|
|
180 |
} catch (Throwable t) {
|
|
181 |
reportException(isBug367599(t) ? Kind.NOTE : Kind.ERROR, element, t);
|
|
182 |
} finally {
|
|
183 |
scope = null;
|
|
184 |
}
|
|
185 |
}
|
|
186 |
return false;
|
|
187 |
}
|
|
188 |
|
|
189 |
/**
|
|
190 |
* Determines if a given exception is (most likely) caused by
|
|
191 |
* <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599">Bug 367599</a>.
|
|
192 |
*/
|
|
193 |
public static boolean isBug367599(Throwable t) {
|
|
194 |
if (t instanceof FilerException) {
|
|
195 |
for (StackTraceElement ste : t.getStackTrace()) {
|
|
196 |
if (ste.toString().contains("org.eclipse.jdt.internal.apt.pluggable.core.filer.IdeFilerImpl.create")) {
|
|
197 |
// See: https://bugs.eclipse.org/bugs/show_bug.cgi?id=367599
|
|
198 |
return true;
|
|
199 |
}
|
|
200 |
}
|
|
201 |
}
|
|
202 |
if (t.getCause() != null) {
|
|
203 |
return isBug367599(t.getCause());
|
|
204 |
}
|
|
205 |
return false;
|
|
206 |
}
|
|
207 |
}
|