comparison truffle/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java @ 21951:9c8c0937da41

Moving all sources into truffle subdirectory
author Jaroslav Tulach <jaroslav.tulach@oracle.com>
date Wed, 17 Jun 2015 10:58:08 +0200
parents graal/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/parser/TypeSystemParser.java@f5b49d881909
children dc83cc1f94f2
comparison
equal deleted inserted replaced
21950:2a5011c7e641 21951:9c8c0937da41
1 /*
2 * Copyright (c) 2012, 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.parser;
24
25 import java.lang.annotation.*;
26 import java.util.*;
27
28 import javax.lang.model.element.*;
29 import javax.lang.model.type.*;
30 import javax.lang.model.util.*;
31
32 import com.oracle.truffle.api.dsl.*;
33 import com.oracle.truffle.api.dsl.internal.*;
34 import com.oracle.truffle.dsl.processor.java.*;
35 import com.oracle.truffle.dsl.processor.model.*;
36
37 @DSLOptions
38 public class TypeSystemParser extends AbstractParser<TypeSystemData> {
39
40 public static final List<Class<TypeSystem>> ANNOTATIONS = Arrays.asList(TypeSystem.class);
41
42 @Override
43 public Class<? extends Annotation> getAnnotationType() {
44 return TypeSystem.class;
45 }
46
47 @Override
48 protected TypeSystemData parse(Element element, AnnotationMirror mirror) {
49 TypeElement templateType = (TypeElement) element;
50 AnnotationMirror templateTypeAnnotation = mirror;
51 DSLOptions options = element.getAnnotation(DSLOptions.class);
52 if (options == null) {
53 options = TypeSystemParser.class.getAnnotation(DSLOptions.class);
54 }
55 assert options != null;
56
57 TypeSystemData typeSystem = new TypeSystemData(context, templateType, templateTypeAnnotation, options, false);
58
59 // annotation type on class path!?
60 TypeElement annotationTypeElement = processingEnv.getElementUtils().getTypeElement(getAnnotationType().getCanonicalName());
61 if (annotationTypeElement == null) {
62 typeSystem.addError("Required class %s is not on the classpath.", getAnnotationType().getName());
63 }
64 if (templateType.getModifiers().contains(Modifier.PRIVATE)) {
65 typeSystem.addError("A @%s must have at least package protected visibility.", getAnnotationType().getName());
66 }
67
68 if (templateType.getModifiers().contains(Modifier.FINAL)) {
69 typeSystem.addError("The @%s must not be final.", getAnnotationType().getName());
70 }
71 if (typeSystem.hasErrors()) {
72 return typeSystem;
73 }
74
75 if (typeSystem.hasErrors()) {
76 return typeSystem;
77 }
78
79 verifyExclusiveMethodAnnotation(typeSystem, TypeCast.class, TypeCheck.class);
80
81 List<Element> elements = new ArrayList<>(context.getEnvironment().getElementUtils().getAllMembers(templateType));
82 List<ImplicitCastData> implicitCasts = new ImplicitCastParser(context, typeSystem).parse(elements);
83 List<TypeCastData> casts = new TypeCastParser(context, typeSystem).parse(elements);
84 List<TypeCheckData> checks = new TypeCheckParser(context, typeSystem).parse(elements);
85
86 if (casts == null || checks == null || implicitCasts == null) {
87 return typeSystem;
88 }
89
90 List<TypeMirror> legacyTypes = ElementUtils.getAnnotationValueList(TypeMirror.class, typeSystem.getTemplateTypeAnnotation(), "value");
91 for (int i = 0; i < legacyTypes.size(); i++) {
92 legacyTypes.set(i, ElementUtils.fillInGenericWildcards(legacyTypes.get(i)));
93 }
94
95 typeSystem.getLegacyTypes().addAll(legacyTypes);
96 verifyTypes(typeSystem);
97 typeSystem.getLegacyTypes().add(context.getType(Object.class));
98 typeSystem.getLegacyTypes().add(context.getType(void.class));
99 verifyNamesUnique(typeSystem);
100
101 typeSystem.getImplicitCasts().addAll(implicitCasts);
102 typeSystem.getCasts().addAll(casts);
103 typeSystem.getChecks().addAll(checks);
104
105 if (typeSystem.hasErrors()) {
106 return typeSystem;
107 }
108 return typeSystem;
109 }
110
111 private void verifyExclusiveMethodAnnotation(Template template, Class<?>... annotationTypes) {
112 List<ExecutableElement> methods = ElementFilter.methodsIn(template.getTemplateType().getEnclosedElements());
113 for (ExecutableElement method : methods) {
114 List<AnnotationMirror> foundAnnotations = new ArrayList<>();
115 for (int i = 0; i < annotationTypes.length; i++) {
116 Class<?> annotationType = annotationTypes[i];
117 AnnotationMirror mirror = ElementUtils.findAnnotationMirror(context.getEnvironment(), method, annotationType);
118 if (mirror != null) {
119 foundAnnotations.add(mirror);
120 }
121 }
122 if (foundAnnotations.size() > 1) {
123 List<String> annotationNames = new ArrayList<>();
124 for (AnnotationMirror mirror : foundAnnotations) {
125 annotationNames.add("@" + ElementUtils.getSimpleName(mirror.getAnnotationType()));
126 }
127
128 template.addError("Non exclusive usage of annotations %s.", annotationNames);
129 }
130 }
131 }
132
133 private void verifyTypes(TypeSystemData typeSystem) {
134 for (TypeMirror type : typeSystem.getLegacyTypes()) {
135 if (isPrimitiveWrapper(type)) {
136 typeSystem.addError("Types must not contain primitive wrapper types.");
137 }
138
139 if (ElementUtils.typeEquals(type, context.getType(Object.class))) {
140 typeSystem.addError("Types must not contain the generic type java.lang.Object.");
141 }
142 }
143
144 verifyTypeOrder(typeSystem);
145 }
146
147 private static void verifyTypeOrder(TypeSystemData typeSystem) {
148 Map<String, List<String>> invalidTypes = new HashMap<>();
149
150 for (int i = typeSystem.getLegacyTypes().size() - 1; i >= 0; i--) {
151 TypeMirror typeData = typeSystem.getLegacyTypes().get(i);
152 TypeMirror type = typeSystem.boxType(typeData);
153 if (invalidTypes.containsKey(ElementUtils.getQualifiedName(type))) {
154 typeSystem.addError("Invalid type order. The type(s) %s are inherited from a earlier defined type %s.", invalidTypes.get(ElementUtils.getQualifiedName(type)),
155 ElementUtils.getQualifiedName(type));
156 }
157 TypeElement element = ElementUtils.fromTypeMirror(type);
158 List<String> nextInvalidTypes = new ArrayList<>();
159 if (element != null) {
160 nextInvalidTypes.addAll(ElementUtils.getQualifiedSuperTypeNames(element));
161 }
162 nextInvalidTypes.add(ElementUtils.getQualifiedName(type));
163
164 for (String qualifiedName : nextInvalidTypes) {
165 List<String> inheritedTypes = invalidTypes.get(qualifiedName);
166 if (inheritedTypes == null) {
167 inheritedTypes = new ArrayList<>();
168 invalidTypes.put(qualifiedName, inheritedTypes);
169 }
170 inheritedTypes.add(ElementUtils.getQualifiedName(typeSystem.boxType(typeData)));
171 }
172 }
173 }
174
175 private boolean isPrimitiveWrapper(TypeMirror type) {
176 Types types = context.getEnvironment().getTypeUtils();
177 for (TypeKind kind : TypeKind.values()) {
178 if (!kind.isPrimitive()) {
179 continue;
180 }
181 if (ElementUtils.typeEquals(type, types.boxedClass(types.getPrimitiveType(kind)).asType())) {
182 return true;
183 }
184 }
185 return false;
186 }
187
188 private static void verifyNamesUnique(TypeSystemData typeSystem) {
189 Set<String> usedNames = new HashSet<>();
190 for (TypeMirror type : typeSystem.getLegacyTypes()) {
191 String boxedName = ElementUtils.getSimpleName(typeSystem.boxType(type));
192 String primitiveName = ElementUtils.getSimpleName(type);
193 if (usedNames.contains(boxedName)) {
194 typeSystem.addError("Two types result in the same boxed name: %s.", boxedName);
195 } else if (usedNames.contains(primitiveName)) {
196 typeSystem.addError("Two types result in the same primitive name: %s.", primitiveName);
197 }
198 usedNames.add(boxedName);
199 usedNames.add(primitiveName);
200 }
201 }
202
203 }