• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2016 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.binder;
18 
19 import static com.google.common.collect.Iterables.getOnlyElement;
20 
21 import com.google.common.collect.ImmutableList;
22 import com.google.common.collect.ImmutableMap;
23 import com.google.common.collect.ImmutableSet;
24 import com.google.common.collect.Multimap;
25 import com.google.common.collect.MultimapBuilder;
26 import com.google.turbine.binder.bound.AnnotationMetadata;
27 import com.google.turbine.binder.bound.SourceTypeBoundClass;
28 import com.google.turbine.binder.bound.TurbineAnnotationValue;
29 import com.google.turbine.binder.bound.TypeBoundClass;
30 import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
31 import com.google.turbine.binder.bound.TypeBoundClass.MethodInfo;
32 import com.google.turbine.binder.bound.TypeBoundClass.ParamInfo;
33 import com.google.turbine.binder.bound.TypeBoundClass.RecordComponentInfo;
34 import com.google.turbine.binder.env.Env;
35 import com.google.turbine.binder.sym.ClassSymbol;
36 import com.google.turbine.diag.TurbineError;
37 import com.google.turbine.diag.TurbineError.ErrorKind;
38 import com.google.turbine.model.Const;
39 import com.google.turbine.model.TurbineElementType;
40 import com.google.turbine.type.AnnoInfo;
41 import com.google.turbine.type.Type;
42 import com.google.turbine.type.Type.ArrayTy;
43 import com.google.turbine.type.Type.ClassTy;
44 import com.google.turbine.type.Type.ClassTy.SimpleClassTy;
45 import com.google.turbine.type.Type.PrimTy;
46 import com.google.turbine.type.Type.TyVar;
47 import java.util.Collection;
48 import java.util.Map;
49 
50 /**
51  * Disambiguate annotations on field, parameter, and method return types that could be declaration
52  * or type annotations.
53  *
54  * <p>Given a declaration like {@code private @A int x;} or {@code @A private int x;}, there are
55  * three possibilities:
56  *
57  * <ol>
58  *   <li>{@code @A} is a declaration annotation on the field.
59  *   <li>{@code @A} is a {@code TYPE_USE} annotation on the type.
60  *   <li>{@code @A} sets {@code TYPE_USE} <em>and</em> {@code FIELD} targets, and appears in the
61  *       bytecode as both a declaration annotation and as a type annotation.
62  * </ol>
63  *
64  * <p>This can't be disambiguated syntactically (note that the presence of other modifiers before or
65  * after the annotation has no bearing on whether it's a type annotation). So, we wait until
66  * constant binding is done, read the {@code @Target} meta-annotation for each ambiguous annotation,
67  * and move it to the appropriate location.
68  */
69 public final class DisambiguateTypeAnnotations {
bind( SourceTypeBoundClass base, Env<ClassSymbol, TypeBoundClass> env)70   public static SourceTypeBoundClass bind(
71       SourceTypeBoundClass base, Env<ClassSymbol, TypeBoundClass> env) {
72     return new SourceTypeBoundClass(
73         base.interfaceTypes(),
74         base.permits(),
75         base.superClassType(),
76         base.typeParameterTypes(),
77         base.access(),
78         bindComponents(env, base.components(), TurbineElementType.RECORD_COMPONENT),
79         bindMethods(env, base.methods()),
80         bindFields(env, base.fields()),
81         base.owner(),
82         base.kind(),
83         base.children(),
84         base.typeParameters(),
85         base.enclosingScope(),
86         base.scope(),
87         base.memberImports(),
88         base.annotationMetadata(),
89         groupRepeated(env, base.annotations()),
90         base.source(),
91         base.decl());
92   }
93 
bindMethods( Env<ClassSymbol, TypeBoundClass> env, ImmutableList<MethodInfo> fields)94   private static ImmutableList<MethodInfo> bindMethods(
95       Env<ClassSymbol, TypeBoundClass> env, ImmutableList<MethodInfo> fields) {
96     ImmutableList.Builder<MethodInfo> result = ImmutableList.builder();
97     for (MethodInfo field : fields) {
98       result.add(bindMethod(env, field));
99     }
100     return result.build();
101   }
102 
bindMethod(Env<ClassSymbol, TypeBoundClass> env, MethodInfo base)103   private static MethodInfo bindMethod(Env<ClassSymbol, TypeBoundClass> env, MethodInfo base) {
104     ImmutableList.Builder<AnnoInfo> declarationAnnotations = ImmutableList.builder();
105     Type returnType =
106         disambiguate(
107             env,
108             base.name().equals("<init>")
109                 ? TurbineElementType.CONSTRUCTOR
110                 : TurbineElementType.METHOD,
111             base.returnType(),
112             base.annotations(),
113             declarationAnnotations);
114     return new MethodInfo(
115         base.sym(),
116         base.tyParams(),
117         returnType,
118         bindParameters(env, base.parameters(), TurbineElementType.PARAMETER),
119         base.exceptions(),
120         base.access(),
121         base.defaultValue(),
122         base.decl(),
123         declarationAnnotations.build(),
124         base.receiver() != null
125             ? bindParam(env, base.receiver(), TurbineElementType.PARAMETER)
126             : null);
127   }
128 
bindParameters( Env<ClassSymbol, TypeBoundClass> env, ImmutableList<ParamInfo> params, TurbineElementType declarationTarget)129   private static ImmutableList<ParamInfo> bindParameters(
130       Env<ClassSymbol, TypeBoundClass> env,
131       ImmutableList<ParamInfo> params,
132       TurbineElementType declarationTarget) {
133     ImmutableList.Builder<ParamInfo> result = ImmutableList.builder();
134     for (ParamInfo param : params) {
135       result.add(bindParam(env, param, declarationTarget));
136     }
137     return result.build();
138   }
139 
bindParam( Env<ClassSymbol, TypeBoundClass> env, ParamInfo base, TurbineElementType declarationTarget)140   private static ParamInfo bindParam(
141       Env<ClassSymbol, TypeBoundClass> env, ParamInfo base, TurbineElementType declarationTarget) {
142     ImmutableList.Builder<AnnoInfo> declarationAnnotations = ImmutableList.builder();
143     Type type =
144         disambiguate(
145             env, declarationTarget, base.type(), base.annotations(), declarationAnnotations);
146     return new ParamInfo(base.sym(), type, declarationAnnotations.build(), base.access());
147   }
148 
bindComponents( Env<ClassSymbol, TypeBoundClass> env, ImmutableList<RecordComponentInfo> components, TurbineElementType declarationTarget)149   private static ImmutableList<RecordComponentInfo> bindComponents(
150       Env<ClassSymbol, TypeBoundClass> env,
151       ImmutableList<RecordComponentInfo> components,
152       TurbineElementType declarationTarget) {
153     ImmutableList.Builder<RecordComponentInfo> result = ImmutableList.builder();
154     for (RecordComponentInfo component : components) {
155       ImmutableList.Builder<AnnoInfo> declarationAnnotations = ImmutableList.builder();
156       Type type =
157           disambiguate(
158               env,
159               declarationTarget,
160               component.type(),
161               component.annotations(),
162               declarationAnnotations);
163       result.add(
164           new RecordComponentInfo(
165               component.sym(), type, declarationAnnotations.build(), component.access()));
166     }
167     return result.build();
168   }
169 
170   /**
171    * Moves type annotations in {@code annotations} to {@code type}, and adds any declaration
172    * annotations on {@code type} to {@code declarationAnnotations}.
173    */
disambiguate( Env<ClassSymbol, TypeBoundClass> env, TurbineElementType declarationTarget, Type type, ImmutableList<AnnoInfo> annotations, ImmutableList.Builder<AnnoInfo> declarationAnnotations)174   private static Type disambiguate(
175       Env<ClassSymbol, TypeBoundClass> env,
176       TurbineElementType declarationTarget,
177       Type type,
178       ImmutableList<AnnoInfo> annotations,
179       ImmutableList.Builder<AnnoInfo> declarationAnnotations) {
180     // desugar @Repeatable annotations before disambiguating: annotation containers may target
181     // a subset of the types targeted by their element annotation
182     annotations = groupRepeated(env, annotations);
183     ImmutableList.Builder<AnnoInfo> typeAnnotations = ImmutableList.builder();
184     for (AnnoInfo anno : annotations) {
185       ImmutableSet<TurbineElementType> target = getTarget(env, anno);
186       if (target.contains(TurbineElementType.TYPE_USE)) {
187         typeAnnotations.add(anno);
188       }
189       if (target.contains(declarationTarget)) {
190         declarationAnnotations.add(anno);
191       }
192     }
193     return addAnnotationsToType(type, typeAnnotations.build());
194   }
195 
getTarget( Env<ClassSymbol, TypeBoundClass> env, AnnoInfo anno)196   private static ImmutableSet<TurbineElementType> getTarget(
197       Env<ClassSymbol, TypeBoundClass> env, AnnoInfo anno) {
198     ClassSymbol sym = anno.sym();
199     if (sym == null) {
200       return AnnotationMetadata.DEFAULT_TARGETS;
201     }
202     TypeBoundClass info = env.get(sym);
203     if (info == null) {
204       return AnnotationMetadata.DEFAULT_TARGETS;
205     }
206     AnnotationMetadata metadata = info.annotationMetadata();
207     if (metadata == null) {
208       return AnnotationMetadata.DEFAULT_TARGETS;
209     }
210     return metadata.target();
211   }
212 
bindFields( Env<ClassSymbol, TypeBoundClass> env, ImmutableList<FieldInfo> fields)213   private static ImmutableList<FieldInfo> bindFields(
214       Env<ClassSymbol, TypeBoundClass> env, ImmutableList<FieldInfo> fields) {
215     ImmutableList.Builder<FieldInfo> result = ImmutableList.builder();
216     for (FieldInfo field : fields) {
217       result.add(bindField(env, field));
218     }
219     return result.build();
220   }
221 
bindField(Env<ClassSymbol, TypeBoundClass> env, FieldInfo base)222   private static FieldInfo bindField(Env<ClassSymbol, TypeBoundClass> env, FieldInfo base) {
223     ImmutableList.Builder<AnnoInfo> declarationAnnotations = ImmutableList.builder();
224     Type type =
225         disambiguate(
226             env, TurbineElementType.FIELD, base.type(), base.annotations(), declarationAnnotations);
227     return new FieldInfo(
228         base.sym(), type, base.access(), declarationAnnotations.build(), base.decl(), base.value());
229   }
230 
231   /**
232    * Finds the left-most annotatable type in {@code type}, adds the {@code extra} type annotations
233    * to it, and removes any declaration annotations and saves them in {@code removed}.
234    *
235    * <p>The left-most type is e.g. the element type of an array, or the left-most type in a nested
236    * type declaration.
237    *
238    * <p>Note: the second case means that type annotation disambiguation has to occur on nested types
239    * before they are canonicalized.
240    */
addAnnotationsToType(Type type, ImmutableList<AnnoInfo> extra)241   private static Type addAnnotationsToType(Type type, ImmutableList<AnnoInfo> extra) {
242     switch (type.tyKind()) {
243       case PRIM_TY:
244         PrimTy primTy = (PrimTy) type;
245         return Type.PrimTy.create(primTy.primkind(), appendAnnotations(primTy.annos(), extra));
246       case CLASS_TY:
247         ClassTy classTy = (ClassTy) type;
248         SimpleClassTy base = classTy.classes().get(0);
249         SimpleClassTy simple =
250             SimpleClassTy.create(base.sym(), base.targs(), appendAnnotations(base.annos(), extra));
251         return Type.ClassTy.create(
252             ImmutableList.<SimpleClassTy>builder()
253                 .add(simple)
254                 .addAll(classTy.classes().subList(1, classTy.classes().size()))
255                 .build());
256       case ARRAY_TY:
257         ArrayTy arrayTy = (ArrayTy) type;
258         return ArrayTy.create(addAnnotationsToType(arrayTy.elementType(), extra), arrayTy.annos());
259       case TY_VAR:
260         TyVar tyVar = (TyVar) type;
261         return Type.TyVar.create(tyVar.sym(), appendAnnotations(tyVar.annos(), extra));
262       case VOID_TY:
263       case ERROR_TY:
264         return type;
265       case WILD_TY:
266         throw new AssertionError("unexpected wildcard type outside type argument context");
267       default:
268         throw new AssertionError(type.tyKind());
269     }
270   }
271 
appendAnnotations( ImmutableList<AnnoInfo> annos, ImmutableList<AnnoInfo> extra)272   private static ImmutableList<AnnoInfo> appendAnnotations(
273       ImmutableList<AnnoInfo> annos, ImmutableList<AnnoInfo> extra) {
274     return ImmutableList.<AnnoInfo>builder().addAll(annos).addAll(extra).build();
275   }
276 
277   /**
278    * Group repeated annotations and wrap them in their container annotation.
279    *
280    * <p>For example, convert {@code @Foo @Foo} to {@code @Foos({@Foo, @Foo})}.
281    *
282    * <p>This method is used by {@link DisambiguateTypeAnnotations} for declaration annotations, and
283    * by {@link com.google.turbine.lower.Lower} for type annotations. We could group type annotations
284    * here, but it would require another rewrite pass.
285    */
groupRepeated( Env<ClassSymbol, TypeBoundClass> env, ImmutableList<AnnoInfo> annotations)286   public static ImmutableList<AnnoInfo> groupRepeated(
287       Env<ClassSymbol, TypeBoundClass> env, ImmutableList<AnnoInfo> annotations) {
288     Multimap<ClassSymbol, AnnoInfo> repeated =
289         MultimapBuilder.linkedHashKeys().arrayListValues().build();
290     ImmutableList.Builder<AnnoInfo> result = ImmutableList.builder();
291     for (AnnoInfo anno : annotations) {
292       if (anno.sym() == null) {
293         result.add(anno);
294         continue;
295       }
296       repeated.put(anno.sym(), anno);
297     }
298     for (Map.Entry<ClassSymbol, Collection<AnnoInfo>> entry : repeated.asMap().entrySet()) {
299       ClassSymbol symbol = entry.getKey();
300       Collection<AnnoInfo> infos = entry.getValue();
301       if (infos.size() > 1) {
302         ImmutableList.Builder<Const> elements = ImmutableList.builder();
303         for (AnnoInfo element : infos) {
304           elements.add(new TurbineAnnotationValue(element));
305         }
306         TypeBoundClass info = env.get(symbol);
307         if (info == null || info.annotationMetadata() == null) {
308           continue;
309         }
310         ClassSymbol container = info.annotationMetadata().repeatable();
311         if (container == null) {
312           if (isKotlinRepeatable(info)) {
313             continue;
314           }
315           AnnoInfo anno = infos.iterator().next();
316           throw TurbineError.format(
317               anno.source(), anno.position(), ErrorKind.NONREPEATABLE_ANNOTATION, symbol);
318         }
319         result.add(
320             new AnnoInfo(
321                 null,
322                 container,
323                 null,
324                 ImmutableMap.of("value", new Const.ArrayInitValue(elements.build()))));
325       } else {
326         result.add(getOnlyElement(infos));
327       }
328     }
329     return result.build();
330   }
331 
332   // Work-around for https://youtrack.jetbrains.net/issue/KT-34189.
333   // Kotlin stubs include repeated annotations that are valid in Kotlin (i.e. meta-annotated with
334   // @kotlin.annotation.Repeatable), even though they are invalid Java.
335   // TODO(b/142002426): kill this with fire
isKotlinRepeatable(TypeBoundClass info)336   static boolean isKotlinRepeatable(TypeBoundClass info) {
337     for (AnnoInfo metaAnno : info.annotations()) {
338       if (metaAnno.sym() != null
339           && metaAnno.sym().binaryName().equals("kotlin/annotation/Repeatable")) {
340         return true;
341       }
342     }
343     return false;
344   }
345 
DisambiguateTypeAnnotations()346   private DisambiguateTypeAnnotations() {}
347 }
348