comparison graal/com.oracle.truffle.codegen.processor/src/com/oracle/truffle/codegen/processor/codewriter/OrganizedImports.java @ 7291:a748e4d44694

Truffle API to specify type-specalized Node classes; annotation processor for automatic code generation of the type-specialized Node classes during the build process
author Christian Humer <christian.humer@gmail.com>
date Fri, 21 Dec 2012 10:44:31 -0800
parents
children 6343a09b2ec1
comparison
equal deleted inserted replaced
7290:a81db08fe930 7291:a748e4d44694
1 /*
2 * Copyright (c) 2012, 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 */
23 package com.oracle.truffle.codegen.processor.codewriter;
24
25 import static com.oracle.truffle.codegen.processor.Utils.*;
26
27 import java.util.*;
28
29 import javax.lang.model.element.*;
30 import javax.lang.model.type.*;
31 import javax.lang.model.util.*;
32
33 import com.oracle.truffle.codegen.processor.*;
34 import com.oracle.truffle.codegen.processor.ast.*;
35
36 public final class OrganizedImports {
37
38 private final Map<TypeMirror, Integer> importUsage = new HashMap<>();
39 private final Map<TypeMirror, Integer> staticImportUsage = new HashMap<>();
40
41 private final Map<String, TypeMirror> simpleNamesUsed = new HashMap<>();
42
43 private final Set<String> declaredStaticMethods = new HashSet<>();
44 private final Set<String> declaredStaticFields = new HashSet<>();
45 private final Set<String> ambiguousStaticMethods = new HashSet<>();
46 private final Set<String> ambiguousStaticFields = new HashSet<>();
47
48 private final CodeTypeElement topLevelClass;
49
50 private OrganizedImports(CodeTypeElement topLevelClass) {
51 this.topLevelClass = topLevelClass;
52 }
53
54 public static OrganizedImports organize(CodeTypeElement topLevelClass) {
55 OrganizedImports organized = new OrganizedImports(topLevelClass);
56
57 OrganizedImports.ReferenceCollector reference = new ReferenceCollector();
58 topLevelClass.accept(reference, null);
59
60 OrganizedImports.ImportResolver resolver = new ImportResolver(reference, organized);
61 topLevelClass.accept(resolver, null);
62 return organized;
63 }
64
65 public String useImport(TypeMirror type) {
66 String simpleName = getSimpleName(type);
67 TypeMirror usedByType = simpleNamesUsed.get(type);
68 if (usedByType == null) {
69 simpleNamesUsed.put(simpleName, type);
70 usedByType = type;
71 } else if (!typeEquals(type, usedByType)) {
72 // we need a qualified name
73 return getQualifiedName(type);
74 }
75
76 // we can use the simple name
77 addUsage(type, importUsage);
78 return simpleName;
79 }
80
81 public String useStaticFieldImport(TypeMirror type, String fieldName) {
82 return useStaticImport(type, fieldName, ambiguousStaticFields, declaredStaticFields);
83 }
84
85 public String useStaticMethodImport(TypeMirror type, String methodName) {
86 return useStaticImport(type, methodName, ambiguousStaticMethods, declaredStaticMethods);
87 }
88
89 private String useStaticImport(TypeMirror type, String name, Set<String> ambiguousSymbols, Set<String> declaredSymbols) {
90 if (ambiguousSymbols.contains(name)) {
91 // ambiguous import
92 return useImport(type) + "." + name;
93 } else if (!declaredSymbols.contains(name)) {
94 // not imported at all
95 return useImport(type) + "." + name;
96 } else {
97 // import declared and not ambiguous
98 addUsage(type, staticImportUsage);
99 return name;
100 }
101 }
102
103 public Set<CodeImport> generateImports() {
104 Set<CodeImport> imports = new HashSet<>();
105
106 imports.addAll(generateImports(topLevelClass, importUsage.keySet()));
107 imports.addAll(generateStaticImports(topLevelClass, staticImportUsage.keySet()));
108
109 return imports;
110 }
111
112 void clearStaticImports() {
113 declaredStaticFields.clear();
114 declaredStaticMethods.clear();
115 ambiguousStaticFields.clear();
116 ambiguousStaticMethods.clear();
117 }
118
119 boolean processStaticImports(TypeElement element) {
120 Set<String> importedMethods = new HashSet<>();
121 List<ExecutableElement> methods = ElementFilter.methodsIn(element.getEnclosedElements());
122 for (ExecutableElement method : methods) {
123 if (method.getModifiers().contains(Modifier.STATIC)) {
124 importedMethods.add(method.getSimpleName().toString());
125 }
126 }
127
128 boolean allMethodsAmbiguous = processStaticImportElements(importedMethods, this.ambiguousStaticMethods, this.declaredStaticMethods);
129
130 Set<String> importedFields = new HashSet<>();
131 List<VariableElement> fields = ElementFilter.fieldsIn(element.getEnclosedElements());
132 for (VariableElement field : fields) {
133 if (field.getModifiers().contains(Modifier.STATIC)) {
134 importedFields.add(field.getSimpleName().toString());
135 }
136 }
137
138 boolean allFieldsAmbiguous = processStaticImportElements(importedFields, this.ambiguousStaticFields, this.declaredStaticFields);
139
140 return allMethodsAmbiguous && allFieldsAmbiguous;
141 }
142
143 private static boolean processStaticImportElements(Set<String> newElements, Set<String> ambiguousElements, Set<String> declaredElements) {
144 boolean allAmbiguous = false;
145 if (declaredElements.containsAll(newElements)) {
146 // all types already declared -> we can remove the import completely -> they will all get ambiguous
147 allAmbiguous = true;
148 }
149 Set<String> newAmbiguous = new HashSet<>();
150 Set<String> newDeclared = new HashSet<>();
151
152 for (String newElement : newElements) {
153 if (declaredElements.contains(newElement)) {
154 newAmbiguous.add(newElement);
155 } else if (ambiguousElements.contains(newElement)) {
156 // nothing to do
157 } else {
158 newDeclared.add(newElement);
159 }
160 }
161
162 ambiguousElements.addAll(newAmbiguous);
163 declaredElements.addAll(newDeclared);
164 return allAmbiguous;
165 }
166
167 private static Set<CodeImport> generateImports(CodeTypeElement e, Set<TypeMirror> toGenerate) {
168 Set<String> autoImportedTypes = new HashSet<>();
169
170 // if type is declared inside a super type of this class -> no import
171 collectSuperTypeImports(e, autoImportedTypes);
172 collectInnerTypeImports(e, autoImportedTypes);
173
174 TreeSet<CodeImport> importObjects = new TreeSet<>();
175 for (TypeMirror importType : toGenerate) {
176 String importTypePackageName = getPackageName(importType);
177 if (importTypePackageName == null) {
178 continue; // no package name -> no import
179 }
180
181 if (importTypePackageName.equals("java.lang")) {
182 continue; // java.lang is automatically imported
183 }
184
185 if (importTypePackageName.equals(getPackageName(e))) {
186 continue; // same package name -> no import
187 }
188
189 String qualifiedName = getQualifiedName(importType);
190
191 if (autoImportedTypes.contains(qualifiedName)) {
192 continue;
193 }
194
195 importObjects.add(new CodeImport(importType, getQualifiedName(importType), false));
196 }
197
198 return importObjects;
199 }
200
201 private static void collectInnerTypeImports(TypeElement e, Set<String> autoImportedTypes) {
202 for (TypeElement innerClass : ElementFilter.typesIn(e.getEnclosedElements())) {
203 collectSuperTypeImports(innerClass, autoImportedTypes);
204 collectInnerTypeImports(innerClass, autoImportedTypes);
205 }
206 }
207
208 private static void collectSuperTypeImports(TypeElement e, Set<String> autoImportedTypes) {
209 List<TypeElement> superTypes = getSuperTypes(e);
210 for (TypeElement superType : superTypes) {
211 List<TypeElement> declaredTypes = getDeclaredTypes(superType);
212 for (TypeElement declaredType : declaredTypes) {
213 autoImportedTypes.add(getQualifiedName(declaredType));
214 }
215 }
216 }
217
218 private static Set<CodeImport> generateStaticImports(CodeTypeElement e, Set<TypeMirror> toGenerate) {
219 Set<String> autoImportedStaticTypes = new HashSet<>();
220
221 // if type is declared inside a super type of this class -> no import
222 autoImportedStaticTypes.add(getQualifiedName(e));
223 autoImportedStaticTypes.addAll(getQualifiedSuperTypeNames(e));
224
225 TreeSet<CodeImport> importObjects = new TreeSet<>();
226 for (TypeMirror importType : toGenerate) {
227 if (getPackageName(importType) == null) {
228 continue; // no package name -> no import
229 }
230
231 String qualifiedName = getQualifiedName(importType);
232 if (autoImportedStaticTypes.contains(qualifiedName)) {
233 continue;
234 }
235
236 importObjects.add(new CodeImport(importType, qualifiedName + ".*", true));
237 }
238
239 return importObjects;
240 }
241
242 private static void addUsage(TypeMirror type, Map<TypeMirror, Integer> usageMap) {
243 if (type != null) {
244 Integer value = usageMap.get(type);
245 if (value == null) {
246 usageMap.put(type, 1);
247 } else {
248 usageMap.put(type, value + 1);
249 }
250 }
251 }
252
253 private static class ReferenceCollector extends CodeElementScanner<Void, Void> {
254
255 final Map<TypeMirror, Integer> typeReferences = new HashMap<>();
256 final Map<TypeMirror, Integer> staticTypeReferences = new HashMap<>();
257
258 @Override
259 public void visitTree(CodeTree e, Void p) {
260 if (e.getCodeKind() == CodeTreeKind.STATIC_FIELD_REFERENCE) {
261 addStaticImport(e.getType());
262 } else if (e.getCodeKind() == CodeTreeKind.STATIC_METHOD_REFERENCE) {
263 addStaticImport(e.getType());
264 } else {
265 addImport(e.getType());
266 }
267 super.visitTree(e, p);
268 }
269
270 @Override
271 public Void visitExecutable(CodeExecutableElement e, Void p) {
272 visitAnnotations(e.getAnnotationMirrors());
273 if (e.getReturnType() != null) {
274 addImport(e.getReturnType());
275 }
276 for (TypeMirror type : e.getThrownTypes()) {
277 addImport(type);
278 }
279 return super.visitExecutable(e, p);
280 }
281
282 @Override
283 public Void visitType(CodeTypeElement e, Void p) {
284 visitAnnotations(e.getAnnotationMirrors());
285
286 addImport(e.getSuperclass());
287 for (TypeMirror type : e.getImplements()) {
288 addImport(type);
289 }
290
291 return super.visitType(e, p);
292 }
293
294 @Override
295 public Void visitVariable(VariableElement f, Void p) {
296 visitAnnotations(f.getAnnotationMirrors());
297 addImport(f.asType());
298 return super.visitVariable(f, p);
299 }
300
301 private void visitAnnotations(List<? extends AnnotationMirror> mirrors) {
302 for (AnnotationMirror mirror : mirrors) {
303 visitAnnotation(mirror);
304 }
305 }
306
307 public void visitAnnotation(AnnotationMirror e) {
308 addImport(e.getAnnotationType());
309 }
310
311 @Override
312 public void visitImport(CodeImport e, Void p) {
313 }
314
315 private void addStaticImport(TypeMirror type) {
316 addUsage(type, staticTypeReferences);
317 }
318
319 private void addImport(TypeMirror type) {
320 addUsage(type, typeReferences);
321 }
322
323 }
324
325 private static class ImportResolver extends CodeElementScanner<Void, Void> {
326
327 private final ReferenceCollector collector;
328 private final OrganizedImports organizedImports;
329
330 public ImportResolver(OrganizedImports.ReferenceCollector collector, OrganizedImports organizedImports) {
331 this.collector = collector;
332 this.organizedImports = organizedImports;
333 }
334
335 @Override
336 public Void visitType(CodeTypeElement e, Void p) {
337 if (e.isTopLevelClass()) {
338 organizedImports.clearStaticImports();
339
340 organizedImports.processStaticImports(e);
341 List<TypeElement> types = Utils.getSuperTypes(e);
342 for (TypeElement typeElement : types) {
343 organizedImports.processStaticImports(typeElement);
344 }
345
346 for (TypeMirror type : collector.staticTypeReferences.keySet()) {
347 TypeElement element = fromTypeMirror(type);
348 if (element != null) {
349 // already processed by supertype
350 if (types.contains(element)) {
351 continue;
352 }
353 organizedImports.processStaticImports(element);
354 }
355 }
356
357 for (TypeMirror imp : collector.typeReferences.keySet()) {
358 organizedImports.useImport(imp);
359 }
360 }
361 return super.visitType(e, p);
362 }
363
364 @Override
365 public void visitTree(CodeTree e, Void p) {
366 if (e.getCodeKind() == CodeTreeKind.TYPE) {
367 organizedImports.useImport(e.getType());
368 } else if (e.getCodeKind() == CodeTreeKind.STATIC_FIELD_REFERENCE) {
369 organizedImports.useStaticFieldImport(e.getType(), e.getString());
370 } else if (e.getCodeKind() == CodeTreeKind.STATIC_METHOD_REFERENCE) {
371 organizedImports.useStaticMethodImport(e.getType(), e.getString());
372 }
373 super.visitTree(e, p);
374 }
375 }
376
377 }