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