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.ArrayListMultimap; 22 import com.google.common.collect.ImmutableList; 23 import com.google.common.collect.ImmutableList.Builder; 24 import com.google.common.collect.ImmutableMap; 25 import com.google.common.collect.Multimap; 26 import com.google.turbine.binder.bound.AnnotationValue; 27 import com.google.turbine.binder.bound.SourceTypeBoundClass; 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.env.Env; 33 import com.google.turbine.binder.sym.ClassSymbol; 34 import com.google.turbine.diag.TurbineError; 35 import com.google.turbine.diag.TurbineError.ErrorKind; 36 import com.google.turbine.model.Const; 37 import com.google.turbine.model.TurbineElementType; 38 import com.google.turbine.type.AnnoInfo; 39 import com.google.turbine.type.Type; 40 import com.google.turbine.type.Type.ArrayTy; 41 import com.google.turbine.type.Type.ClassTy; 42 import com.google.turbine.type.Type.ClassTy.SimpleClassTy; 43 import com.google.turbine.type.Type.PrimTy; 44 import com.google.turbine.type.Type.TyVar; 45 import java.util.Collection; 46 import java.util.Map; 47 import java.util.Set; 48 49 /** 50 * Disambiguate annotations on field, parameter, and method return types that could be declaration 51 * or type annotations. 52 * 53 * <p>Given a declaration like {@code private @A int x;} or {@code @A private int x;}, there are 54 * three possibilities: 55 * 56 * <ol> 57 * <li>{@code @A} is a declaration annotation on the field. 58 * <li>{@code @A} is a {@code TYPE_USE} annotation on the type. 59 * <li>{@code @A} sets {@code TYPE_USE} <em>and</em> {@code FIELD} targets, and appears in the 60 * bytecode as both a declaration annotation and as a type annotation. 61 * </ol> 62 * 63 * <p>This can't be disambiguated syntactically (note that the presence of other modifiers before or 64 * after the annotation has no bearing on whether it's a type annotation). So, we wait until 65 * constant binding is done, read the {@code @Target} meta-annotation for each ambiguous annotation, 66 * and move it to the appropriate location. 67 */ 68 public class DisambiguateTypeAnnotations { bind( SourceTypeBoundClass base, Env<ClassSymbol, TypeBoundClass> env)69 public static SourceTypeBoundClass bind( 70 SourceTypeBoundClass base, Env<ClassSymbol, TypeBoundClass> env) { 71 return new SourceTypeBoundClass( 72 base.interfaceTypes(), 73 base.superClassType(), 74 base.typeParameterTypes(), 75 base.access(), 76 bindMethods(env, base.methods()), 77 bindFields(env, base.fields()), 78 base.owner(), 79 base.kind(), 80 base.children(), 81 base.typeParameters(), 82 base.enclosingScope(), 83 base.scope(), 84 base.memberImports(), 85 base.annotationMetadata(), 86 groupRepeated(env, base.annotations()), 87 base.source(), 88 base.decl()); 89 } 90 bindMethods( Env<ClassSymbol, TypeBoundClass> env, ImmutableList<MethodInfo> fields)91 private static ImmutableList<MethodInfo> bindMethods( 92 Env<ClassSymbol, TypeBoundClass> env, ImmutableList<MethodInfo> fields) { 93 ImmutableList.Builder<MethodInfo> result = ImmutableList.builder(); 94 for (MethodInfo field : fields) { 95 result.add(bindMethod(env, field)); 96 } 97 return result.build(); 98 } 99 bindMethod(Env<ClassSymbol, TypeBoundClass> env, MethodInfo base)100 private static MethodInfo bindMethod(Env<ClassSymbol, TypeBoundClass> env, MethodInfo base) { 101 ImmutableList.Builder<AnnoInfo> declarationAnnotations = ImmutableList.builder(); 102 Type returnType = 103 disambiguate( 104 env, 105 base.name().equals("<init>") 106 ? TurbineElementType.CONSTRUCTOR 107 : TurbineElementType.METHOD, 108 base.returnType(), 109 base.annotations(), 110 declarationAnnotations); 111 return new MethodInfo( 112 base.sym(), 113 base.tyParams(), 114 returnType, 115 bindParameters(env, base.parameters()), 116 base.exceptions(), 117 base.access(), 118 base.defaultValue(), 119 base.decl(), 120 declarationAnnotations.build(), 121 base.receiver() != null ? bindParam(env, base.receiver()) : null); 122 } 123 bindParameters( Env<ClassSymbol, TypeBoundClass> env, ImmutableList<ParamInfo> params)124 private static ImmutableList<ParamInfo> bindParameters( 125 Env<ClassSymbol, TypeBoundClass> env, ImmutableList<ParamInfo> params) { 126 ImmutableList.Builder<ParamInfo> result = ImmutableList.builder(); 127 for (ParamInfo param : params) { 128 result.add(bindParam(env, param)); 129 } 130 return result.build(); 131 } 132 bindParam(Env<ClassSymbol, TypeBoundClass> env, ParamInfo base)133 private static ParamInfo bindParam(Env<ClassSymbol, TypeBoundClass> env, ParamInfo base) { 134 ImmutableList.Builder<AnnoInfo> declarationAnnotations = ImmutableList.builder(); 135 Type type = 136 disambiguate( 137 env, 138 TurbineElementType.PARAMETER, 139 base.type(), 140 base.annotations(), 141 declarationAnnotations); 142 return new ParamInfo(type, base.name(), declarationAnnotations.build(), base.access()); 143 } 144 145 /** 146 * Moves type annotations in {@code annotations} to {@code type}, and adds any declaration 147 * annotations on {@code type} to {@code declarationAnnotations}. 148 */ disambiguate( Env<ClassSymbol, TypeBoundClass> env, TurbineElementType declarationTarget, Type type, ImmutableList<AnnoInfo> annotations, Builder<AnnoInfo> declarationAnnotations)149 private static Type disambiguate( 150 Env<ClassSymbol, TypeBoundClass> env, 151 TurbineElementType declarationTarget, 152 Type type, 153 ImmutableList<AnnoInfo> annotations, 154 Builder<AnnoInfo> declarationAnnotations) { 155 // desugar @Repeatable annotations before disambiguating: annotation containers may target 156 // a subset of the types targeted by their element annotation 157 annotations = groupRepeated(env, annotations); 158 ImmutableList.Builder<AnnoInfo> typeAnnotations = ImmutableList.builder(); 159 for (AnnoInfo anno : annotations) { 160 Set<TurbineElementType> target = env.get(anno.sym()).annotationMetadata().target(); 161 if (target.contains(TurbineElementType.TYPE_USE)) { 162 typeAnnotations.add(anno); 163 } 164 if (target.contains(declarationTarget)) { 165 declarationAnnotations.add(anno); 166 } 167 } 168 return addAnnotationsToType(type, typeAnnotations.build()); 169 } 170 bindFields( Env<ClassSymbol, TypeBoundClass> env, ImmutableList<FieldInfo> fields)171 private static ImmutableList<FieldInfo> bindFields( 172 Env<ClassSymbol, TypeBoundClass> env, ImmutableList<FieldInfo> fields) { 173 ImmutableList.Builder<FieldInfo> result = ImmutableList.builder(); 174 for (FieldInfo field : fields) { 175 result.add(bindField(env, field)); 176 } 177 return result.build(); 178 } 179 bindField(Env<ClassSymbol, TypeBoundClass> env, FieldInfo base)180 private static FieldInfo bindField(Env<ClassSymbol, TypeBoundClass> env, FieldInfo base) { 181 ImmutableList.Builder<AnnoInfo> declarationAnnotations = ImmutableList.builder(); 182 Type type = 183 disambiguate( 184 env, TurbineElementType.FIELD, base.type(), base.annotations(), declarationAnnotations); 185 return new FieldInfo( 186 base.sym(), type, base.access(), declarationAnnotations.build(), base.decl(), base.value()); 187 } 188 189 /** 190 * Finds the left-most annotatable type in {@code type}, adds the {@code extra} type annotations 191 * to it, and removes any declaration annotations and saves them in {@code removed}. 192 * 193 * <p>The left-most type is e.g. the element type of an array, or the left-most type in a nested 194 * type declaration. 195 * 196 * <p>Note: the second case means that type annotation disambiguation has to occur on nested types 197 * before they are canonicalized. 198 */ addAnnotationsToType(Type type, ImmutableList<AnnoInfo> extra)199 private static Type addAnnotationsToType(Type type, ImmutableList<AnnoInfo> extra) { 200 switch (type.tyKind()) { 201 case PRIM_TY: 202 PrimTy primTy = (PrimTy) type; 203 return Type.PrimTy.create(primTy.primkind(), appendAnnotations(primTy.annos(), extra)); 204 case CLASS_TY: 205 ClassTy classTy = (ClassTy) type; 206 SimpleClassTy base = classTy.classes().get(0); 207 SimpleClassTy simple = 208 SimpleClassTy.create(base.sym(), base.targs(), appendAnnotations(base.annos(), extra)); 209 return Type.ClassTy.create( 210 ImmutableList.<SimpleClassTy>builder() 211 .add(simple) 212 .addAll(classTy.classes().subList(1, classTy.classes().size())) 213 .build()); 214 case ARRAY_TY: 215 ArrayTy arrayTy = (ArrayTy) type; 216 return ArrayTy.create(addAnnotationsToType(arrayTy.elementType(), extra), arrayTy.annos()); 217 case TY_VAR: 218 TyVar tyVar = (TyVar) type; 219 return Type.TyVar.create(tyVar.sym(), appendAnnotations(tyVar.annos(), extra)); 220 case VOID_TY: 221 return type; 222 case WILD_TY: 223 throw new AssertionError("unexpected wildcard type outside type argument context"); 224 default: 225 throw new AssertionError(type.tyKind()); 226 } 227 } 228 appendAnnotations( ImmutableList<AnnoInfo> annos, ImmutableList<AnnoInfo> extra)229 private static ImmutableList<AnnoInfo> appendAnnotations( 230 ImmutableList<AnnoInfo> annos, ImmutableList<AnnoInfo> extra) { 231 return ImmutableList.<AnnoInfo>builder().addAll(annos).addAll(extra).build(); 232 } 233 234 /** 235 * Group repeated annotations and wrap them in their container annotation. 236 * 237 * <p>For example, convert {@code @Foo @Foo} to {@code @Foos({@Foo, @Foo})}. 238 * 239 * <p>This method is used by {@link DisambiguateTypeAnnotations} for declaration annotations, and 240 * by {@link com.google.turbine.lower.Lower} for type annotations. We could group type annotations 241 * here, but it would require another rewrite pass. 242 */ groupRepeated( Env<ClassSymbol, TypeBoundClass> env, ImmutableList<AnnoInfo> annotations)243 public static ImmutableList<AnnoInfo> groupRepeated( 244 Env<ClassSymbol, TypeBoundClass> env, ImmutableList<AnnoInfo> annotations) { 245 Multimap<ClassSymbol, AnnoInfo> repeated = ArrayListMultimap.create(); 246 for (AnnoInfo anno : annotations) { 247 repeated.put(anno.sym(), anno); 248 } 249 Builder<AnnoInfo> result = ImmutableList.builder(); 250 for (Map.Entry<ClassSymbol, Collection<AnnoInfo>> entry : repeated.asMap().entrySet()) { 251 ClassSymbol symbol = entry.getKey(); 252 Collection<AnnoInfo> infos = entry.getValue(); 253 if (infos.size() > 1) { 254 Builder<Const> elements = ImmutableList.builder(); 255 for (AnnoInfo element : infos) { 256 elements.add(new AnnotationValue(element.sym(), element.values())); 257 } 258 ClassSymbol container = env.get(symbol).annotationMetadata().repeatable(); 259 if (container == null) { 260 AnnoInfo anno = infos.iterator().next(); 261 throw TurbineError.format( 262 anno.source(), anno.position(), ErrorKind.NONREPEATABLE_ANNOTATION, symbol); 263 } 264 result.add( 265 new AnnoInfo( 266 null, 267 container, 268 null, 269 ImmutableMap.of("value", new Const.ArrayInitValue(elements.build())))); 270 } else { 271 result.add(getOnlyElement(infos)); 272 } 273 } 274 return result.build(); 275 } 276 } 277