comparison graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/java/transform/OrganizedImports.java @ 16759:23415229349b

Truffle-DSL: new package structure.
author Christian Humer <christian.humer@gmail.com>
date Mon, 11 Aug 2014 15:57:14 +0200
parents graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/codewriter/OrganizedImports.java@bd28da642eea
children 45c8f64978d6
comparison
equal deleted inserted replaced
16758:c5f8eeb3cbc8 16759:23415229349b
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.dsl.processor.java.transform;
24
25 import static com.oracle.truffle.dsl.processor.java.ElementUtils.*;
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.dsl.processor.java.*;
34 import com.oracle.truffle.dsl.processor.java.model.*;
35
36 public final class OrganizedImports {
37
38 private final Set<TypeMirror> staticImportUsage = new HashSet<>();
39
40 private final Map<String, TypeMirror> simpleNamesUsed = new HashMap<>();
41
42 private final Set<String> declaredStaticMethods = new HashSet<>();
43 private final Set<String> declaredStaticFields = new HashSet<>();
44 private final Set<String> ambiguousStaticMethods = new HashSet<>();
45 private final Set<String> ambiguousStaticFields = new HashSet<>();
46
47 private final CodeTypeElement topLevelClass;
48
49 private OrganizedImports(CodeTypeElement topLevelClass) {
50 this.topLevelClass = topLevelClass;
51 }
52
53 public static OrganizedImports organize(CodeTypeElement topLevelClass) {
54 OrganizedImports organized = new OrganizedImports(topLevelClass);
55 organized.organizeImpl();
56 return organized;
57 }
58
59 private void organizeImpl() {
60 ImportTypeReferenceVisitor reference = new ImportTypeReferenceVisitor();
61 topLevelClass.accept(reference, null);
62
63 processStaticImports(topLevelClass);
64 List<TypeElement> types = ElementUtils.getSuperTypes(topLevelClass);
65 for (TypeElement typeElement : types) {
66 processStaticImports(typeElement);
67 }
68
69 for (TypeMirror type : staticImportUsage) {
70 TypeElement element = fromTypeMirror(type);
71 if (element != null) {
72 // already processed by supertype
73 if (types.contains(element)) {
74 continue;
75 }
76 processStaticImports(element);
77 }
78 }
79 }
80
81 public String createTypeReference(Element enclosedElement, TypeMirror type) {
82 switch (type.getKind()) {
83 case BOOLEAN:
84 case BYTE:
85 case CHAR:
86 case DOUBLE:
87 case FLOAT:
88 case SHORT:
89 case INT:
90 case LONG:
91 case VOID:
92 return ElementUtils.getSimpleName(type);
93 case DECLARED:
94 return createDeclaredTypeName(enclosedElement, (DeclaredType) type);
95 case ARRAY:
96 return createTypeReference(enclosedElement, ((ArrayType) type).getComponentType()) + "[]";
97 case WILDCARD:
98 return createWildcardName(enclosedElement, (WildcardType) type);
99 case TYPEVAR:
100 return "?";
101 default:
102 throw new RuntimeException("Unknown type specified " + type.getKind() + " mirror: " + type);
103 }
104 }
105
106 public String createStaticFieldReference(Element enclosedElement, TypeMirror type, String fieldName) {
107 return createStaticReference(enclosedElement, type, fieldName, ambiguousStaticFields);
108 }
109
110 public String createStaticMethodReference(Element enclosedElement, TypeMirror type, String methodName) {
111 return createStaticReference(enclosedElement, type, methodName, ambiguousStaticMethods);
112 }
113
114 private String createStaticReference(Element enclosedElement, TypeMirror type, String name, Set<String> ambiguousSymbols) {
115 if (ambiguousSymbols.contains(name)) {
116 // ambiguous import
117 return createTypeReference(enclosedElement, type) + "." + name;
118 } else {
119 // import declared and not ambiguous
120 return name;
121 }
122 }
123
124 private String createWildcardName(Element enclosedElement, WildcardType type) {
125 StringBuilder b = new StringBuilder();
126 if (type.getExtendsBound() != null) {
127 b.append("? extends ").append(createTypeReference(enclosedElement, type.getExtendsBound()));
128 } else if (type.getSuperBound() != null) {
129 b.append("? super ").append(createTypeReference(enclosedElement, type.getExtendsBound()));
130 }
131 return b.toString();
132 }
133
134 private String createDeclaredTypeName(Element enclosedElement, DeclaredType type) {
135 String name;
136 name = ElementUtils.fixECJBinaryNameIssue(type.asElement().getSimpleName().toString());
137
138 if (needsImport(enclosedElement, type)) {
139 TypeMirror usedByType = simpleNamesUsed.get(name);
140 if (usedByType == null) {
141 simpleNamesUsed.put(name, type);
142 usedByType = type;
143 }
144
145 if (!typeEquals(type, usedByType)) {
146 name = getQualifiedName(type);
147 }
148 }
149
150 if (type.getTypeArguments().size() == 0) {
151 return name;
152 }
153
154 StringBuilder b = new StringBuilder(name);
155 b.append("<");
156 if (type.getTypeArguments().size() > 0) {
157 for (int i = 0; i < type.getTypeArguments().size(); i++) {
158 b.append(createTypeReference(enclosedElement, type.getTypeArguments().get(i)));
159 if (i < type.getTypeArguments().size() - 1) {
160 b.append(", ");
161 }
162 }
163 }
164 b.append(">");
165 return b.toString();
166 }
167
168 public Set<CodeImport> generateImports() {
169 Set<CodeImport> imports = new HashSet<>();
170
171 imports.addAll(generateImports(simpleNamesUsed.values()));
172 imports.addAll(generateStaticImports(staticImportUsage));
173
174 return imports;
175 }
176
177 boolean processStaticImports(TypeElement element) {
178 Set<String> importedMethods = new HashSet<>();
179 List<ExecutableElement> methods = ElementFilter.methodsIn(element.getEnclosedElements());
180 for (ExecutableElement method : methods) {
181 if (method.getModifiers().contains(Modifier.STATIC)) {
182 importedMethods.add(method.getSimpleName().toString());
183 }
184 }
185
186 boolean allMethodsAmbiguous = processStaticImportElements(importedMethods, this.ambiguousStaticMethods, this.declaredStaticMethods);
187
188 Set<String> importedFields = new HashSet<>();
189 List<VariableElement> fields = ElementFilter.fieldsIn(element.getEnclosedElements());
190 for (VariableElement field : fields) {
191 if (field.getModifiers().contains(Modifier.STATIC)) {
192 importedFields.add(field.getSimpleName().toString());
193 }
194 }
195
196 boolean allFieldsAmbiguous = processStaticImportElements(importedFields, this.ambiguousStaticFields, this.declaredStaticFields);
197
198 return allMethodsAmbiguous && allFieldsAmbiguous;
199 }
200
201 private static boolean processStaticImportElements(Set<String> newElements, Set<String> ambiguousElements, Set<String> declaredElements) {
202 boolean allAmbiguous = false;
203 if (declaredElements.containsAll(newElements)) {
204 // all types already declared -> we can remove the import completely -> they will all
205 // get ambiguous
206 allAmbiguous = true;
207 }
208 Set<String> newAmbiguous = new HashSet<>();
209 Set<String> newDeclared = new HashSet<>();
210
211 for (String newElement : newElements) {
212 if (declaredElements.contains(newElement)) {
213 newAmbiguous.add(newElement);
214 } else if (ambiguousElements.contains(newElement)) {
215 // nothing to do
216 } else {
217 newDeclared.add(newElement);
218 }
219 }
220
221 ambiguousElements.addAll(newAmbiguous);
222 declaredElements.addAll(newDeclared);
223 return allAmbiguous;
224 }
225
226 private boolean needsImport(Element enclosedElement, TypeMirror importType) {
227 String importPackagName = getPackageName(importType);
228 if (importPackagName == null) {
229 return false;
230 } else if (importPackagName.equals("java.lang")) {
231 return false;
232 } else if (importPackagName.equals(getPackageName(topLevelClass)) && ElementUtils.isTopLevelClass(importType)) {
233 return false; // same package name -> no import
234 }
235
236 List<Element> elements = ElementUtils.getElementHierarchy(enclosedElement);
237
238 Set<String> autoImportedTypes = new HashSet<>();
239 for (Element element : elements) {
240 if (element.getKind().isClass()) {
241 collectSuperTypeImports((TypeElement) element, autoImportedTypes);
242 collectInnerTypeImports((TypeElement) element, autoImportedTypes);
243 }
244 }
245
246 String qualifiedName = getQualifiedName(importType);
247 if (autoImportedTypes.contains(qualifiedName)) {
248 return false;
249 }
250
251 return true;
252 }
253
254 private static Set<CodeImport> generateImports(Collection<TypeMirror> toGenerate) {
255 TreeSet<CodeImport> importObjects = new TreeSet<>();
256 for (TypeMirror importType : toGenerate) {
257 importObjects.add(new CodeImport(importType, getQualifiedName(importType), false));
258 }
259 return importObjects;
260 }
261
262 private static void collectInnerTypeImports(TypeElement e, Set<String> autoImportedTypes) {
263 autoImportedTypes.add(getQualifiedName(e));
264 for (TypeElement innerClass : ElementFilter.typesIn(e.getEnclosedElements())) {
265 collectInnerTypeImports(innerClass, autoImportedTypes);
266 }
267 }
268
269 private static void collectSuperTypeImports(TypeElement e, Set<String> autoImportedTypes) {
270 List<TypeElement> superTypes = getSuperTypes(e);
271 for (TypeElement superType : superTypes) {
272 List<TypeElement> declaredTypes = getDeclaredTypes(superType);
273 for (TypeElement declaredType : declaredTypes) {
274 autoImportedTypes.add(getQualifiedName(declaredType));
275 }
276 }
277 }
278
279 private Set<CodeImport> generateStaticImports(Set<TypeMirror> toGenerate) {
280 Set<String> autoImportedStaticTypes = new HashSet<>();
281
282 // if type is declared inside a super type of this class -> no import
283 autoImportedStaticTypes.add(getQualifiedName(topLevelClass));
284 autoImportedStaticTypes.addAll(getQualifiedSuperTypeNames(topLevelClass));
285
286 TreeSet<CodeImport> importObjects = new TreeSet<>();
287 for (TypeMirror importType : toGenerate) {
288 if (getPackageName(importType) == null) {
289 continue; // no package name -> no import
290 }
291
292 String qualifiedName = getQualifiedName(importType);
293 if (autoImportedStaticTypes.contains(qualifiedName)) {
294 continue;
295 }
296
297 importObjects.add(new CodeImport(importType, qualifiedName + ".*", true));
298 }
299
300 return importObjects;
301 }
302
303 private abstract static class TypeReferenceVisitor extends CodeElementScanner<Void, Void> {
304
305 @Override
306 public void visitTree(CodeTree e, Void p) {
307 if (e.getCodeKind() == CodeTreeKind.STATIC_FIELD_REFERENCE) {
308 visitStaticFieldReference(e, e.getType(), e.getString());
309 } else if (e.getCodeKind() == CodeTreeKind.STATIC_METHOD_REFERENCE) {
310 visitStaticMethodReference(e, e.getType(), e.getString());
311 } else if (e.getType() != null) {
312 visitTypeReference(e, e.getType());
313 }
314 super.visitTree(e, p);
315 }
316
317 @Override
318 public Void visitExecutable(CodeExecutableElement e, Void p) {
319 visitAnnotations(e, e.getAnnotationMirrors());
320 if (e.getReturnType() != null) {
321 visitTypeReference(e, e.getReturnType());
322 }
323 for (TypeMirror type : e.getThrownTypes()) {
324 visitTypeReference(e, type);
325 }
326 return super.visitExecutable(e, p);
327 }
328
329 @Override
330 public Void visitType(CodeTypeElement e, Void p) {
331 visitAnnotations(e, e.getAnnotationMirrors());
332
333 visitTypeReference(e, e.getSuperclass());
334 for (TypeMirror type : e.getImplements()) {
335 visitTypeReference(e, type);
336 }
337
338 return super.visitType(e, p);
339 }
340
341 private void visitAnnotations(Element enclosingElement, List<? extends AnnotationMirror> mirrors) {
342 for (AnnotationMirror mirror : mirrors) {
343 visitAnnotation(enclosingElement, mirror);
344 }
345 }
346
347 public void visitAnnotation(Element enclosingElement, AnnotationMirror e) {
348 visitTypeReference(enclosingElement, e.getAnnotationType());
349 if (!e.getElementValues().isEmpty()) {
350 Map<? extends ExecutableElement, ? extends AnnotationValue> values = e.getElementValues();
351 Set<? extends ExecutableElement> methodsSet = values.keySet();
352 List<ExecutableElement> methodsList = new ArrayList<>();
353 for (ExecutableElement method : methodsSet) {
354 if (values.get(method) == null) {
355 continue;
356 }
357 methodsList.add(method);
358 }
359
360 for (int i = 0; i < methodsList.size(); i++) {
361 AnnotationValue value = values.get(methodsList.get(i));
362 visitAnnotationValue(enclosingElement, value);
363 }
364 }
365 }
366
367 public void visitAnnotationValue(Element enclosingElement, AnnotationValue e) {
368 e.accept(new AnnotationValueReferenceVisitor(enclosingElement), null);
369 }
370
371 private class AnnotationValueReferenceVisitor extends AbstractAnnotationValueVisitor7<Void, Void> {
372
373 private final Element enclosingElement;
374
375 public AnnotationValueReferenceVisitor(Element enclosedElement) {
376 this.enclosingElement = enclosedElement;
377 }
378
379 @Override
380 public Void visitBoolean(boolean b, Void p) {
381 return null;
382 }
383
384 @Override
385 public Void visitByte(byte b, Void p) {
386 return null;
387 }
388
389 @Override
390 public Void visitChar(char c, Void p) {
391 return null;
392 }
393
394 @Override
395 public Void visitDouble(double d, Void p) {
396 return null;
397 }
398
399 @Override
400 public Void visitFloat(float f, Void p) {
401 return null;
402 }
403
404 @Override
405 public Void visitInt(int i, Void p) {
406 return null;
407 }
408
409 @Override
410 public Void visitLong(long i, Void p) {
411 return null;
412 }
413
414 @Override
415 public Void visitShort(short s, Void p) {
416 return null;
417 }
418
419 @Override
420 public Void visitString(String s, Void p) {
421 return null;
422 }
423
424 @Override
425 public Void visitType(TypeMirror t, Void p) {
426 visitTypeReference(enclosingElement, t);
427 return null;
428 }
429
430 @Override
431 public Void visitEnumConstant(VariableElement c, Void p) {
432 visitTypeReference(enclosingElement, c.asType());
433 return null;
434 }
435
436 @Override
437 public Void visitAnnotation(AnnotationMirror a, Void p) {
438 TypeReferenceVisitor.this.visitAnnotation(enclosingElement, a);
439 return null;
440 }
441
442 @Override
443 public Void visitArray(List<? extends AnnotationValue> vals, Void p) {
444 for (int i = 0; i < vals.size(); i++) {
445 TypeReferenceVisitor.this.visitAnnotationValue(enclosingElement, vals.get(i));
446 }
447 return null;
448 }
449 }
450
451 @Override
452 public Void visitVariable(VariableElement f, Void p) {
453 visitAnnotations(f, f.getAnnotationMirrors());
454 visitTypeReference(f, f.asType());
455 return super.visitVariable(f, p);
456 }
457
458 @Override
459 public void visitImport(CodeImport e, Void p) {
460 }
461
462 public abstract void visitTypeReference(Element enclosedType, TypeMirror type);
463
464 public abstract void visitStaticMethodReference(Element enclosedType, TypeMirror type, String elementName);
465
466 public abstract void visitStaticFieldReference(Element enclosedType, TypeMirror type, String elementName);
467
468 }
469
470 private class ImportTypeReferenceVisitor extends TypeReferenceVisitor {
471
472 @Override
473 public void visitStaticFieldReference(Element enclosedType, TypeMirror type, String elementName) {
474 staticImportUsage.add(type);
475 }
476
477 @Override
478 public void visitStaticMethodReference(Element enclosedType, TypeMirror type, String elementName) {
479 staticImportUsage.add(type);
480 }
481
482 @Override
483 public void visitTypeReference(Element enclosedType, TypeMirror type) {
484 createTypeReference(enclosedType, type);
485 }
486
487 }
488
489 }