• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 Google Inc. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.turbine.processing;
18 
19 import static com.google.common.collect.Iterables.getOnlyElement;
20 import static java.util.Objects.requireNonNull;
21 
22 import com.google.common.base.Splitter;
23 import com.google.common.base.Supplier;
24 import com.google.common.base.Verify;
25 import com.google.common.collect.ImmutableList;
26 import com.google.common.collect.ImmutableMap;
27 import com.google.common.collect.ImmutableSet;
28 import com.google.turbine.binder.bound.TypeBoundClass;
29 import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
30 import com.google.turbine.binder.bound.TypeBoundClass.MethodInfo;
31 import com.google.turbine.binder.bound.TypeBoundClass.ParamInfo;
32 import com.google.turbine.binder.bound.TypeBoundClass.TyVarInfo;
33 import com.google.turbine.binder.env.CompoundEnv;
34 import com.google.turbine.binder.env.Env;
35 import com.google.turbine.binder.lookup.LookupKey;
36 import com.google.turbine.binder.lookup.LookupResult;
37 import com.google.turbine.binder.lookup.TopLevelIndex;
38 import com.google.turbine.binder.sym.ClassSymbol;
39 import com.google.turbine.binder.sym.FieldSymbol;
40 import com.google.turbine.binder.sym.MethodSymbol;
41 import com.google.turbine.binder.sym.PackageSymbol;
42 import com.google.turbine.binder.sym.ParamSymbol;
43 import com.google.turbine.binder.sym.Symbol;
44 import com.google.turbine.binder.sym.TyVarSymbol;
45 import com.google.turbine.model.TurbineConstantTypeKind;
46 import com.google.turbine.processing.TurbineElement.TurbineExecutableElement;
47 import com.google.turbine.processing.TurbineElement.TurbineFieldElement;
48 import com.google.turbine.processing.TurbineElement.TurbineNoTypeElement;
49 import com.google.turbine.processing.TurbineElement.TurbinePackageElement;
50 import com.google.turbine.processing.TurbineElement.TurbineParameterElement;
51 import com.google.turbine.processing.TurbineElement.TurbineTypeElement;
52 import com.google.turbine.processing.TurbineElement.TurbineTypeParameterElement;
53 import com.google.turbine.processing.TurbineTypeMirror.TurbineArrayType;
54 import com.google.turbine.processing.TurbineTypeMirror.TurbineDeclaredType;
55 import com.google.turbine.processing.TurbineTypeMirror.TurbineErrorType;
56 import com.google.turbine.processing.TurbineTypeMirror.TurbineExecutableType;
57 import com.google.turbine.processing.TurbineTypeMirror.TurbineIntersectionType;
58 import com.google.turbine.processing.TurbineTypeMirror.TurbineNoType;
59 import com.google.turbine.processing.TurbineTypeMirror.TurbineNullType;
60 import com.google.turbine.processing.TurbineTypeMirror.TurbinePackageType;
61 import com.google.turbine.processing.TurbineTypeMirror.TurbinePrimitiveType;
62 import com.google.turbine.processing.TurbineTypeMirror.TurbineTypeVariable;
63 import com.google.turbine.processing.TurbineTypeMirror.TurbineVoidType;
64 import com.google.turbine.processing.TurbineTypeMirror.TurbineWildcardType;
65 import com.google.turbine.tree.Tree.Ident;
66 import com.google.turbine.type.Type;
67 import com.google.turbine.type.Type.ArrayTy;
68 import com.google.turbine.type.Type.ClassTy;
69 import com.google.turbine.type.Type.ErrorTy;
70 import com.google.turbine.type.Type.IntersectionTy;
71 import com.google.turbine.type.Type.MethodTy;
72 import com.google.turbine.type.Type.PrimTy;
73 import com.google.turbine.type.Type.TyVar;
74 import com.google.turbine.type.Type.WildTy;
75 import java.util.HashMap;
76 import java.util.Map;
77 import java.util.concurrent.atomic.AtomicInteger;
78 import javax.lang.model.element.Element;
79 import javax.lang.model.element.VariableElement;
80 import javax.lang.model.type.NoType;
81 import javax.lang.model.type.NullType;
82 import javax.lang.model.type.TypeMirror;
83 
84 /**
85  * A factoy for turbine's implementations of {@link Element} and {@link TypeMirror}.
86  *
87  * <p>The model provided by those interfaces contains cycles between types and elements, e.g. {@link
88  * Element#asType} and {@link javax.lang.model.type.DeclaredType#asElement}. Turbine's internal
89  * model uses an immutable representation of classes and types which cannot represent cycles
90  * directly. Instead, the implementations in {@link TurbineElement} and {@link TurbineTypeMirror}
91  * maintain a reference to this class, and use it to lazily construct edges in the type and element
92  * graph.
93  */
94 public class ModelFactory {
95 
96   public Env<ClassSymbol, ? extends TypeBoundClass> env;
97 
98   private final AtomicInteger round = new AtomicInteger(0);
99 
round(CompoundEnv<ClassSymbol, TypeBoundClass> env, TopLevelIndex tli)100   public void round(CompoundEnv<ClassSymbol, TypeBoundClass> env, TopLevelIndex tli) {
101     this.env = env;
102     this.tli = tli;
103     round.getAndIncrement();
104     cha.round(env);
105   }
106 
107   private final HashMap<Type, TurbineTypeMirror> typeCache = new HashMap<>();
108 
109   private final Map<FieldSymbol, TurbineFieldElement> fieldCache = new HashMap<>();
110   private final Map<MethodSymbol, TurbineExecutableElement> methodCache = new HashMap<>();
111   private final Map<ClassSymbol, TurbineTypeElement> classCache = new HashMap<>();
112   private final Map<ParamSymbol, TurbineParameterElement> paramCache = new HashMap<>();
113   private final Map<TyVarSymbol, TurbineTypeParameterElement> tyParamCache = new HashMap<>();
114   private final Map<PackageSymbol, TurbinePackageElement> packageCache = new HashMap<>();
115 
116   private final HashMap<CharSequence, ClassSymbol> inferSymbolCache = new HashMap<>();
117 
118   private final ClassHierarchy cha;
119   private final ClassLoader processorLoader;
120 
121   private TopLevelIndex tli;
122 
ModelFactory( Env<ClassSymbol, ? extends TypeBoundClass> env, ClassLoader processorLoader, TopLevelIndex tli)123   public ModelFactory(
124       Env<ClassSymbol, ? extends TypeBoundClass> env,
125       ClassLoader processorLoader,
126       TopLevelIndex tli) {
127     this.env = requireNonNull(env);
128     this.cha = new ClassHierarchy(env);
129     this.processorLoader = requireNonNull(processorLoader);
130     this.tli = requireNonNull(tli);
131   }
132 
asTypeMirror(Type type)133   TypeMirror asTypeMirror(Type type) {
134     return typeCache.computeIfAbsent(type, this::createTypeMirror);
135   }
136 
137   /**
138    * Returns a supplier that memoizes the result of the input supplier.
139    *
140    * <p>It ensures that the results are invalidated after each annotation processing round, to
141    * support computations that depend on information in the current round and which might change in
142    * future, e.g. as additional types are generated.
143    */
memoize(Supplier<T> s)144   <T> Supplier<T> memoize(Supplier<T> s) {
145     return new Supplier<T>() {
146       T v;
147       int initializedInRound = -1;
148 
149       @Override
150       public T get() {
151         int r = round.get();
152         if (initializedInRound != r) {
153           v = s.get();
154           initializedInRound = r;
155         }
156         return v;
157       }
158     };
159   }
160 
161   /** Creates a {@link TurbineTypeMirror} backed by a {@link Type}. */
createTypeMirror(Type type)162   private TurbineTypeMirror createTypeMirror(Type type) {
163     switch (type.tyKind()) {
164       case PRIM_TY:
165         if (((PrimTy) type).primkind() == TurbineConstantTypeKind.STRING) {
166           return new TurbineDeclaredType(this, ClassTy.STRING);
167         }
168         return new TurbinePrimitiveType(this, (PrimTy) type);
169       case CLASS_TY:
170         return new TurbineDeclaredType(this, (ClassTy) type);
171       case ARRAY_TY:
172         return new TurbineArrayType(this, (ArrayTy) type);
173       case VOID_TY:
174         return new TurbineVoidType(this);
175       case WILD_TY:
176         return new TurbineWildcardType(this, (WildTy) type);
177       case TY_VAR:
178         return new TurbineTypeVariable(this, (TyVar) type);
179       case INTERSECTION_TY:
180         IntersectionTy intersectionTy = (IntersectionTy) type;
181         switch (intersectionTy.bounds().size()) {
182           case 0:
183             return createTypeMirror(ClassTy.OBJECT);
184           case 1:
185             return createTypeMirror(getOnlyElement(intersectionTy.bounds()));
186           default:
187             return new TurbineIntersectionType(this, intersectionTy);
188         }
189       case NONE_TY:
190         return new TurbineNoType(this);
191       case METHOD_TY:
192         return new TurbineExecutableType(this, (MethodTy) type);
193       case ERROR_TY:
194         return new TurbineErrorType(this, (ErrorTy) type);
195     }
196     throw new AssertionError(type.tyKind());
197   }
198 
199   /** Creates a list of {@link TurbineTypeMirror}s backed by the given {@link Type}s. */
asTypeMirrors(Iterable<? extends Type> types)200   ImmutableList<TypeMirror> asTypeMirrors(Iterable<? extends Type> types) {
201     ImmutableList.Builder<TypeMirror> result = ImmutableList.builder();
202     for (Type type : types) {
203       result.add(asTypeMirror(type));
204     }
205     return result.build();
206   }
207 
noType()208   NoType noType() {
209     return (NoType) asTypeMirror(Type.NONE);
210   }
211 
packageType(PackageSymbol symbol)212   NoType packageType(PackageSymbol symbol) {
213     return new TurbinePackageType(this, symbol);
214   }
215 
nullType()216   public NullType nullType() {
217     return new TurbineNullType(this);
218   }
219 
220   /** Creates an {@link Element} backed by the given {@link Symbol}. */
element(Symbol symbol)221   Element element(Symbol symbol) {
222     switch (symbol.symKind()) {
223       case CLASS:
224         return typeElement((ClassSymbol) symbol);
225       case TY_PARAM:
226         return typeParameterElement((TyVarSymbol) symbol);
227       case METHOD:
228         return executableElement((MethodSymbol) symbol);
229       case FIELD:
230         return fieldElement((FieldSymbol) symbol);
231       case PARAMETER:
232         return parameterElement((ParamSymbol) symbol);
233       case PACKAGE:
234         return packageElement((PackageSymbol) symbol);
235       case MODULE:
236         break;
237     }
238     throw new AssertionError(symbol.symKind());
239   }
240 
noElement(String name)241   Element noElement(String name) {
242     return new TurbineNoTypeElement(this, name);
243   }
244 
fieldElement(FieldSymbol symbol)245   TurbineFieldElement fieldElement(FieldSymbol symbol) {
246     return fieldCache.computeIfAbsent(symbol, k -> new TurbineFieldElement(this, symbol));
247   }
248 
executableElement(MethodSymbol symbol)249   TurbineExecutableElement executableElement(MethodSymbol symbol) {
250     return methodCache.computeIfAbsent(symbol, k -> new TurbineExecutableElement(this, symbol));
251   }
252 
typeElement(ClassSymbol symbol)253   public TurbineTypeElement typeElement(ClassSymbol symbol) {
254     Verify.verify(!symbol.simpleName().equals("package-info"), "%s", symbol);
255     return classCache.computeIfAbsent(symbol, k -> new TurbineTypeElement(this, symbol));
256   }
257 
packageElement(PackageSymbol symbol)258   TurbinePackageElement packageElement(PackageSymbol symbol) {
259     return packageCache.computeIfAbsent(symbol, k -> new TurbinePackageElement(this, symbol));
260   }
261 
parameterElement(ParamSymbol sym)262   VariableElement parameterElement(ParamSymbol sym) {
263     return paramCache.computeIfAbsent(sym, k -> new TurbineParameterElement(this, sym));
264   }
265 
typeParameterElement(TyVarSymbol sym)266   TurbineTypeParameterElement typeParameterElement(TyVarSymbol sym) {
267     return tyParamCache.computeIfAbsent(sym, k -> new TurbineTypeParameterElement(this, sym));
268   }
269 
elements(ImmutableSet<? extends Symbol> symbols)270   ImmutableSet<Element> elements(ImmutableSet<? extends Symbol> symbols) {
271     ImmutableSet.Builder<Element> result = ImmutableSet.builder();
272     for (Symbol symbol : symbols) {
273       result.add(element(symbol));
274     }
275     return result.build();
276   }
277 
inferSymbol(CharSequence name)278   public ClassSymbol inferSymbol(CharSequence name) {
279     return inferSymbolCache.computeIfAbsent(name, key -> inferSymbolImpl(name));
280   }
281 
inferSymbolImpl(CharSequence name)282   private ClassSymbol inferSymbolImpl(CharSequence name) {
283     LookupResult lookup = tli.scope().lookup(new LookupKey(asIdents(name)));
284     if (lookup == null) {
285       return null;
286     }
287     ClassSymbol sym = (ClassSymbol) lookup.sym();
288     for (Ident bit : lookup.remaining()) {
289       sym = getSymbol(sym).children().get(bit.value());
290       if (sym == null) {
291         return null;
292       }
293     }
294     return sym;
295   }
296 
asIdents(CharSequence name)297   private static ImmutableList<Ident> asIdents(CharSequence name) {
298     ImmutableList.Builder<Ident> result = ImmutableList.builder();
299     for (String bit : Splitter.on('.').split(name)) {
300       result.add(new Ident(-1, bit));
301     }
302     return result.build();
303   }
304 
305   /**
306    * Returns the {@link TypeBoundClass} for the given {@link ClassSymbol} from the current
307    * environment.
308    */
getSymbol(ClassSymbol sym)309   TypeBoundClass getSymbol(ClassSymbol sym) {
310     return env.get(sym);
311   }
312 
getMethodInfo(MethodSymbol method)313   MethodInfo getMethodInfo(MethodSymbol method) {
314     TypeBoundClass info = getSymbol(method.owner());
315     for (MethodInfo m : info.methods()) {
316       if (m.sym().equals(method)) {
317         return m;
318       }
319     }
320     return null;
321   }
322 
getParamInfo(ParamSymbol sym)323   ParamInfo getParamInfo(ParamSymbol sym) {
324     MethodInfo info = getMethodInfo(sym.owner());
325     for (ParamInfo p : info.parameters()) {
326       if (p.sym().equals(sym)) {
327         return p;
328       }
329     }
330     return null;
331   }
332 
getFieldInfo(FieldSymbol symbol)333   FieldInfo getFieldInfo(FieldSymbol symbol) {
334     TypeBoundClass info = getSymbol(symbol.owner());
335     requireNonNull(info, symbol.owner().toString());
336     for (FieldInfo field : info.fields()) {
337       if (field.sym().equals(symbol)) {
338         return field;
339       }
340     }
341     throw new AssertionError(symbol);
342   }
343 
getTyVarInfo(TyVarSymbol tyVar)344   TyVarInfo getTyVarInfo(TyVarSymbol tyVar) {
345     Symbol owner = tyVar.owner();
346     Verify.verifyNotNull(owner); // TODO(cushon): capture variables
347     ImmutableMap<TyVarSymbol, TyVarInfo> tyParams;
348     switch (owner.symKind()) {
349       case METHOD:
350         tyParams = getMethodInfo((MethodSymbol) owner).tyParams();
351         break;
352       case CLASS:
353         tyParams = getSymbol((ClassSymbol) owner).typeParameterTypes();
354         break;
355       default:
356         throw new AssertionError(owner.symKind());
357     }
358     return tyParams.get(tyVar);
359   }
360 
enclosingClass(Symbol sym)361   static ClassSymbol enclosingClass(Symbol sym) {
362     switch (sym.symKind()) {
363       case CLASS:
364         return (ClassSymbol) sym;
365       case TY_PARAM:
366         return enclosingClass(((TyVarSymbol) sym).owner());
367       case METHOD:
368         return ((MethodSymbol) sym).owner();
369       case FIELD:
370         return ((FieldSymbol) sym).owner();
371       case PARAMETER:
372         return ((ParamSymbol) sym).owner().owner();
373       case PACKAGE:
374       case MODULE:
375         throw new IllegalArgumentException(sym.toString());
376     }
377     throw new AssertionError(sym.symKind());
378   }
379 
cha()380   ClassHierarchy cha() {
381     return cha;
382   }
383 
processorLoader()384   ClassLoader processorLoader() {
385     return processorLoader;
386   }
387 
tli()388   TopLevelIndex tli() {
389     return tli;
390   }
391 }
392