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
17package com.google.turbine.binder;
18
19import com.google.common.collect.ImmutableList;
20import com.google.common.collect.ImmutableMap;
21import com.google.turbine.binder.bound.SourceTypeBoundClass;
22import com.google.turbine.binder.bound.TypeBoundClass;
23import com.google.turbine.binder.bound.TypeBoundClass.FieldInfo;
24import com.google.turbine.binder.bound.TypeBoundClass.MethodInfo;
25import com.google.turbine.binder.bound.TypeBoundClass.ParamInfo;
26import com.google.turbine.binder.bound.TypeBoundClass.TyVarInfo;
27import com.google.turbine.binder.env.Env;
28import com.google.turbine.binder.sym.ClassSymbol;
29import com.google.turbine.binder.sym.TyVarSymbol;
30import com.google.turbine.type.Type;
31import com.google.turbine.type.Type.ClassTy;
32import com.google.turbine.types.Canonicalize;
33import java.util.Map;
34
35/**
36 * Canonicalizes all qualified types in a {@link SourceTypeBoundClass} using {@link Canonicalize}.
37 */
38public class CanonicalTypeBinder {
39
40  static SourceTypeBoundClass bind(
41      ClassSymbol sym, SourceTypeBoundClass base, Env<ClassSymbol, TypeBoundClass> env) {
42    ClassTy superClassType = null;
43    if (base.superClassType() != null) {
44      superClassType = Canonicalize.canonicalizeClassTy(env, base.owner(), base.superClassType());
45    }
46    ImmutableList.Builder<ClassTy> interfaceTypes = ImmutableList.builder();
47    for (ClassTy i : base.interfaceTypes()) {
48      interfaceTypes.add(Canonicalize.canonicalizeClassTy(env, base.owner(), i));
49    }
50    ImmutableMap<TyVarSymbol, TyVarInfo> typParamTypes =
51        typeParameters(env, sym, base.typeParameterTypes());
52    ImmutableList<MethodInfo> methods = methods(env, sym, base.methods());
53    ImmutableList<FieldInfo> fields = fields(env, sym, base.fields());
54    return new SourceTypeBoundClass(
55        interfaceTypes.build(),
56        superClassType,
57        typParamTypes,
58        base.access(),
59        methods,
60        fields,
61        base.owner(),
62        base.kind(),
63        base.children(),
64        base.typeParameters(),
65        base.enclosingScope(),
66        base.scope(),
67        base.memberImports(),
68        base.annotationMetadata(),
69        base.annotations(),
70        base.source());
71  }
72
73  private static ImmutableList<FieldInfo> fields(
74      Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ImmutableList<FieldInfo> fields) {
75    ImmutableList.Builder<FieldInfo> result = ImmutableList.builder();
76    for (FieldInfo base : fields) {
77      result.add(
78          new FieldInfo(
79              base.sym(),
80              Canonicalize.canonicalize(env, sym, base.type()),
81              base.access(),
82              base.annotations(),
83              base.decl(),
84              base.value()));
85    }
86    return result.build();
87  }
88
89  private static ImmutableList<MethodInfo> methods(
90      Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ImmutableList<MethodInfo> methods) {
91    ImmutableList.Builder<MethodInfo> result = ImmutableList.builder();
92    for (MethodInfo base : methods) {
93      ImmutableMap<TyVarSymbol, TyVarInfo> tps = typeParameters(env, sym, base.tyParams());
94      Type ret = Canonicalize.canonicalize(env, sym, base.returnType());
95      ImmutableList.Builder<ParamInfo> parameters = ImmutableList.builder();
96      for (ParamInfo parameter : base.parameters()) {
97        parameters.add(param(env, sym, parameter));
98      }
99      ImmutableList<Type> exceptions = canonicalizeList(env, sym, base.exceptions());
100      result.add(
101          new MethodInfo(
102              base.sym(),
103              tps,
104              ret,
105              parameters.build(),
106              exceptions,
107              base.access(),
108              base.defaultValue(),
109              base.decl(),
110              base.annotations(),
111              base.receiver() != null ? param(env, sym, base.receiver()) : null));
112    }
113    return result.build();
114  }
115
116  private static ParamInfo param(
117      Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ParamInfo base) {
118    return new ParamInfo(
119        Canonicalize.canonicalize(env, sym, base.type()),
120        base.name(),
121        base.annotations(),
122        base.access());
123  }
124
125  private static ImmutableMap<TyVarSymbol, TyVarInfo> typeParameters(
126      Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, Map<TyVarSymbol, TyVarInfo> tps) {
127    ImmutableMap.Builder<TyVarSymbol, TyVarInfo> result = ImmutableMap.builder();
128    for (Map.Entry<TyVarSymbol, TyVarInfo> e : tps.entrySet()) {
129      TyVarInfo info = e.getValue();
130      Type superClassBound = null;
131      if (info.superClassBound() != null) {
132        superClassBound = Canonicalize.canonicalize(env, sym, info.superClassBound());
133      }
134      ImmutableList<Type> interfaceBounds = canonicalizeList(env, sym, info.interfaceBounds());
135      result.put(e.getKey(), new TyVarInfo(superClassBound, interfaceBounds, info.annotations()));
136    }
137    return result.build();
138  }
139
140  private static ImmutableList<Type> canonicalizeList(
141      Env<ClassSymbol, TypeBoundClass> env, ClassSymbol sym, ImmutableList<Type> types) {
142    ImmutableList.Builder<Type> result = ImmutableList.builder();
143    for (Type type : types) {
144      result.add(Canonicalize.canonicalize(env, sym, type));
145    }
146    return result.build();
147  }
148}
149