Fri, 24 Apr 2020 03:58:51 +0100
Merge
1 /*
2 * Copyright (c) 2013, 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 */
24 /*
25 * @test
26 * @bug 8026180
27 * @summary Ensuring javax.lang.model.**, javax.tools.**, javax.annotation.processing.**
28 * and com.sun.source.** don't export inappropriate types.
29 * @library /tools/javac/lib
30 * @build JavacTestingAbstractProcessor NoPrivateTypesExported
31 * @compile -processor NoPrivateTypesExported NoPrivateTypesExported.java
32 */
33 import java.lang.annotation.Documented;
34 import java.util.Arrays;
35 import java.util.HashSet;
36 import java.util.List;
37 import java.util.Set;
38 import javax.annotation.processing.RoundEnvironment;
39 import javax.lang.model.element.AnnotationMirror;
40 import javax.lang.model.element.AnnotationValue;
41 import javax.lang.model.element.Element;
42 import javax.lang.model.element.ElementKind;
43 import javax.lang.model.element.ExecutableElement;
44 import javax.lang.model.element.PackageElement;
45 import javax.lang.model.element.TypeElement;
46 import javax.lang.model.element.TypeParameterElement;
47 import javax.lang.model.element.VariableElement;
48 import javax.lang.model.type.ArrayType;
49 import javax.lang.model.type.DeclaredType;
50 import javax.lang.model.type.IntersectionType;
51 import javax.lang.model.type.TypeMirror;
52 import javax.lang.model.type.TypeVariable;
53 import javax.lang.model.type.WildcardType;
54 import javax.lang.model.util.ElementScanner8;
55 import javax.lang.model.util.SimpleAnnotationValueVisitor8;
56 import javax.tools.Diagnostic.Kind;
58 public class NoPrivateTypesExported extends JavacTestingAbstractProcessor {
60 private static final String[] javaxLangModelPackages = new String[] {
61 "javax.lang.model",
62 "javax.lang.model.element",
63 "javax.lang.model.type",
64 "javax.lang.model.util",
65 };
67 private static final Set<String> javaxLangModelAcceptable;
69 private static final String[] javaxToolsProcessingPackages = new String[] {
70 "javax.annotation.processing",
71 "javax.tools",
72 };
74 private static final Set<String> javaxToolsProcessingAcceptable;
76 private static final String[] comSunSourcePackages = new String[] {
77 "com.sun.source.doctree",
78 "com.sun.source.tree",
79 "com.sun.source.util"
80 };
82 private static final Set<String> comSunSourceAcceptable;
84 static {
85 javaxLangModelAcceptable = new HashSet<>(Arrays.asList(
86 "java.io.",
87 "java.lang.",
88 "java.net.",
89 "java.nio.",
90 "java.util.",
91 "javax.lang.model.",
92 "javax.annotation.processing.SupportedSourceVersion",
93 "jdk.Exported"
94 ));
95 Set<String> javaxToolsProcessingAcceptableTemp = new HashSet<>();
96 javaxToolsProcessingAcceptableTemp.addAll(javaxLangModelAcceptable);
97 javaxToolsProcessingAcceptableTemp.addAll(Arrays.asList(
98 "javax.annotation.processing.",
99 "javax.tools."
100 ));
101 javaxToolsProcessingAcceptable = javaxToolsProcessingAcceptableTemp;
102 Set<String> comSunSourceAcceptableTemp = new HashSet<>();
103 comSunSourceAcceptableTemp.addAll(javaxToolsProcessingAcceptable);
104 comSunSourceAcceptableTemp.addAll(Arrays.asList(
105 "com.sun.source.doctree.",
106 "com.sun.source.tree.",
107 "com.sun.source.util."
108 ));
109 comSunSourceAcceptable = comSunSourceAcceptableTemp;
110 }
112 @Override
113 public boolean process(Set<? extends TypeElement> annotations,
114 RoundEnvironment roundEnv) {
115 if (roundEnv.processingOver()) {
116 verifyPackage(javaxLangModelPackages, javaxLangModelAcceptable);
117 verifyPackage(javaxToolsProcessingPackages, javaxToolsProcessingAcceptable);
118 verifyPackage(comSunSourcePackages, comSunSourceAcceptable);
119 }
120 return true;
121 }
123 private void verifyPackage(String[] packagesToTest, Set<String> acceptable) {
124 for (String packageToTest : packagesToTest) {
125 PackageElement packageElement = processingEnv.getElementUtils()
126 .getPackageElement(packageToTest);
128 verifyReferredTypesAcceptable(packageElement, acceptable);
129 }
130 }
132 private void verifyReferredTypesAcceptable(Element rootElement,
133 final Set<String> acceptable) {
134 new ElementScanner8<Void, Void>() {
135 @Override public Void visitType(TypeElement e, Void p) {
136 verifyTypeAcceptable(e.getSuperclass(), acceptable);
137 verifyTypesAcceptable(e.getInterfaces(), acceptable);
138 scan(e.getTypeParameters(), p);
139 scan(e.getEnclosedElements(), p);
140 verifyAnnotations(e.getAnnotationMirrors(), acceptable);
141 return null;
142 }
143 @Override public Void visitTypeParameter(TypeParameterElement e, Void p) {
144 verifyTypesAcceptable(e.getBounds(), acceptable);
145 scan(e.getEnclosedElements(), p);
146 verifyAnnotations(e.getAnnotationMirrors(), acceptable);
147 return null;
148 }
149 @Override public Void visitPackage(PackageElement e, Void p) {
150 scan(e.getEnclosedElements(), p);
151 verifyAnnotations(e.getAnnotationMirrors(), acceptable);
152 return null;
153 }
154 @Override public Void visitVariable(VariableElement e, Void p) {
155 verifyTypeAcceptable(e.asType(), acceptable);
156 scan(e.getEnclosedElements(), p);
157 verifyAnnotations(e.getAnnotationMirrors(), acceptable);
158 return null;
159 }
160 @Override
161 public Void visitExecutable(ExecutableElement e, Void p) {
162 scan(e.getTypeParameters(), p);
163 verifyTypeAcceptable(e.getReturnType(), acceptable);
164 scan(e.getParameters(), p);
165 verifyTypesAcceptable(e.getThrownTypes(), acceptable);
166 scan(e.getEnclosedElements(), p);
167 verifyAnnotations(e.getAnnotationMirrors(), acceptable);
168 return null;
169 }
170 }.scan(rootElement, null);
171 }
173 private void verifyAnnotations(Iterable<? extends AnnotationMirror> annotations,
174 Set<String> acceptable) {
175 for (AnnotationMirror mirror : annotations) {
176 Element annotationElement = mirror.getAnnotationType().asElement();
178 if (annotationElement.getAnnotation(Documented.class) == null) {
179 note("Ignoring undocumented annotation: " + mirror.getAnnotationType());
180 }
182 verifyTypeAcceptable(mirror.getAnnotationType(), acceptable);
184 for (AnnotationValue value : mirror.getElementValues().values()) {
185 verifyAnnotationValue(value, acceptable);
186 }
187 }
188 }
190 private void verifyAnnotationValue(AnnotationValue value,
191 final Set<String> acceptable) {
192 value.accept(new SimpleAnnotationValueVisitor8<Void, Void>() {
193 @Override public Void visitType(TypeMirror t, Void p) {
194 verifyTypeAcceptable(t, acceptable);
195 return null;
196 }
197 @Override
198 public Void visitEnumConstant(VariableElement c, Void p) {
199 verifyReferredTypesAcceptable(c, acceptable);
200 return null;
201 }
202 @Override public Void visitArray(List<? extends AnnotationValue> vals,
203 Void p) {
204 for (AnnotationValue val : vals) {
205 val.accept(this, p);
206 }
207 return null;
208 }
209 @Override protected Void defaultAction(Object o, Void p) {
210 error("Unexpected AnnotationValue: " + o.toString());
211 return super.defaultAction(o, p);
212 }
213 }, null);
214 }
216 private void verifyTypesAcceptable(Iterable<? extends TypeMirror> types,
217 Set<String> acceptable) {
218 if (types == null) return ;
220 for (TypeMirror type : types) {
221 verifyTypeAcceptable(type, acceptable);
222 }
223 }
225 private void verifyTypeAcceptable(TypeMirror type, Set<String> acceptable) {
226 if (type == null) return ;
228 verifyAnnotations(type.getAnnotationMirrors(), acceptable);
230 switch (type.getKind()) {
231 case BOOLEAN: case BYTE: case CHAR: case DOUBLE: case FLOAT:
232 case INT: case LONG: case SHORT: case VOID: case NONE: case NULL:
233 return ;
234 case DECLARED:
235 DeclaredType dt = (DeclaredType) type;
236 TypeElement outermostTypeElement = outermostTypeElement(dt.asElement());
237 String outermostType = outermostTypeElement.getQualifiedName().toString();
238 boolean isAcceptable = false;
239 for (String acceptablePackage : acceptable) {
240 if (outermostType.startsWith(acceptablePackage)) {
241 isAcceptable = true;
242 break;
243 }
244 }
245 if (!isAcceptable) {
246 error("Type not acceptable for this API: " + dt.toString());
247 }
249 for (TypeMirror bound : dt.getTypeArguments()) {
250 verifyTypeAcceptable(bound, acceptable);
251 }
252 break;
253 case ARRAY:
254 verifyTypeAcceptable(((ArrayType) type).getComponentType(), acceptable);
255 break;
256 case INTERSECTION:
257 for (TypeMirror element : ((IntersectionType) type).getBounds()) {
258 verifyTypeAcceptable(element, acceptable);
259 }
260 break;
261 case TYPEVAR:
262 verifyTypeAcceptable(((TypeVariable) type).getLowerBound(), acceptable);
263 verifyTypeAcceptable(((TypeVariable) type).getUpperBound(), acceptable);
264 break;
265 case WILDCARD:
266 verifyTypeAcceptable(((WildcardType) type).getExtendsBound(), acceptable);
267 verifyTypeAcceptable(((WildcardType) type).getSuperBound(), acceptable);
268 break;
269 default:
270 error("Type not acceptable for this API: " + type.toString());
271 break;
273 }
274 }
276 private TypeElement outermostTypeElement(Element el) {
277 while (el.getEnclosingElement().getKind() != ElementKind.PACKAGE) {
278 el = el.getEnclosingElement();
279 }
281 return (TypeElement) el;
282 }
284 private void error(String text) {
285 processingEnv.getMessager().printMessage(Kind.ERROR, text);
286 }
288 private void note(String text) {
289 processingEnv.getMessager().printMessage(Kind.NOTE, text);
290 }
291 }