15d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin/*
25d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * Copyright (C) 2013 Google, Inc.
35d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * Copyright (C) 2013 Square, Inc.
45d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin *
55d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * Licensed under the Apache License, Version 2.0 (the "License");
65d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * you may not use this file except in compliance with the License.
75d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * You may obtain a copy of the License at
85d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin *
95d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * http://www.apache.org/licenses/LICENSE-2.0
105d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin *
115d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * Unless required by applicable law or agreed to in writing, software
125d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * distributed under the License is distributed on an "AS IS" BASIS,
135d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
145d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * See the License for the specific language governing permissions and
155d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * limitations under the License.
165d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin */
175d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinpackage dagger.internal.codegen;
185d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
195d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport com.google.auto.common.MoreTypes;
205d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport com.google.common.base.Equivalence;
215d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport com.google.common.base.Equivalence.Wrapper;
225d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport com.google.common.base.Optional;
235d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport com.google.common.collect.ImmutableSet;
2487182e06b8f6ec9a11ed6ebcaf74444e79b18ae2Paul Duffinimport dagger.producers.Produced;
255d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport java.util.Map;
265d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport java.util.Set;
275d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.inject.Provider;
285d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.element.Element;
295d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.element.ExecutableElement;
305d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.element.Modifier;
315d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.element.TypeElement;
325d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.type.DeclaredType;
335d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.type.TypeMirror;
345d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport javax.lang.model.util.Elements;
355d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
365d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static com.google.auto.common.MoreElements.getLocalAndInheritedMethods;
375d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static com.google.auto.common.MoreTypes.asDeclared;
385d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static com.google.common.base.Preconditions.checkState;
395d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static javax.lang.model.element.ElementKind.CONSTRUCTOR;
405d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static javax.lang.model.element.Modifier.ABSTRACT;
415d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static javax.lang.model.element.Modifier.PRIVATE;
425d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinimport static javax.lang.model.element.Modifier.STATIC;
435d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
445d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin/**
455d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin * Utilities for handling types in annotation processors
465d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin */
475d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffinfinal class Util {
485d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  /**
4987182e06b8f6ec9a11ed6ebcaf74444e79b18ae2Paul Duffin   * Returns the {@code V} type for a {@link Map} type like {@code Map<K, Provider<V>>} if the map
505d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   * includes such a construction
515d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   */
5287182e06b8f6ec9a11ed6ebcaf74444e79b18ae2Paul Duffin  public static TypeMirror getProvidedValueTypeOfMap(DeclaredType mapType) {
535d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    checkState(MoreTypes.isTypeOf(Map.class, mapType), "%s is not a Map.", mapType);
5487182e06b8f6ec9a11ed6ebcaf74444e79b18ae2Paul Duffin    return asDeclared(mapType.getTypeArguments().get(1)).getTypeArguments().get(0);
555d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  }
565d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
575d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  // TODO(cgruber): Consider an object that holds and exposes the various parts of a Map type.
585d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  /**
595d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   * returns the value type for a {@link Map} type like Map<K, V>}.
605d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   */
6187182e06b8f6ec9a11ed6ebcaf74444e79b18ae2Paul Duffin  public static TypeMirror getValueTypeOfMap(DeclaredType mapType) {
625d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    checkState(MoreTypes.isTypeOf(Map.class, mapType), "%s is not a Map.", mapType);
6387182e06b8f6ec9a11ed6ebcaf74444e79b18ae2Paul Duffin    return mapType.getTypeArguments().get(1);
645d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  }
655d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
665d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  /**
675d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   * Returns the key type for a {@link Map} type like Map<K, Provider<V>>}
685d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   */
6987182e06b8f6ec9a11ed6ebcaf74444e79b18ae2Paul Duffin  public static TypeMirror getKeyTypeOfMap(DeclaredType mapType) {
705d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    checkState(MoreTypes.isTypeOf(Map.class, mapType), "%s is not a Map.", mapType);
7187182e06b8f6ec9a11ed6ebcaf74444e79b18ae2Paul Duffin    return mapType.getTypeArguments().get(0);
725d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  }
735d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
745d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  /**
755d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   * Returns true if {@code type} is a {@link Map} whose value type is not a {@link Provider}.
765d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   */
775d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  public static boolean isMapWithNonProvidedValues(TypeMirror type) {
785d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    return MoreTypes.isType(type)
795d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        && MoreTypes.isTypeOf(Map.class, type)
805d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        && !MoreTypes.isTypeOf(Provider.class, asDeclared(type).getTypeArguments().get(1));
815d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  }
825d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
835d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  /**
845d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   * Returns true if {@code type} is a {@link Map} whose value type is a {@link Provider}.
855d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   */
865d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  public static boolean isMapWithProvidedValues(TypeMirror type) {
875d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    return MoreTypes.isType(type)
885d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        && MoreTypes.isTypeOf(Map.class, type)
895d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        && MoreTypes.isTypeOf(Provider.class, asDeclared(type).getTypeArguments().get(1));
905d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  }
915d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
9287182e06b8f6ec9a11ed6ebcaf74444e79b18ae2Paul Duffin  /** Returns true if {@code type} is a {@code Set<Produced<T>>}. */
9387182e06b8f6ec9a11ed6ebcaf74444e79b18ae2Paul Duffin  static boolean isSetOfProduced(TypeMirror type) {
9487182e06b8f6ec9a11ed6ebcaf74444e79b18ae2Paul Duffin    return MoreTypes.isType(type)
9587182e06b8f6ec9a11ed6ebcaf74444e79b18ae2Paul Duffin        && MoreTypes.isTypeOf(Set.class, type)
9687182e06b8f6ec9a11ed6ebcaf74444e79b18ae2Paul Duffin        && MoreTypes.isTypeOf(Produced.class, MoreTypes.asDeclared(type).getTypeArguments().get(0));
9787182e06b8f6ec9a11ed6ebcaf74444e79b18ae2Paul Duffin  }
9887182e06b8f6ec9a11ed6ebcaf74444e79b18ae2Paul Duffin
995d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  /**
1005d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   * Wraps an {@link Optional} of a type in an {@code Optional} of a {@link Wrapper} for that type.
1015d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   */
1025d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  static <T> Optional<Equivalence.Wrapper<T>> wrapOptionalInEquivalence(
1035d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      Equivalence<T> equivalence, Optional<T> optional) {
1045d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    return optional.isPresent()
1055d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        ? Optional.of(equivalence.wrap(optional.get()))
1065d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        : Optional.<Equivalence.Wrapper<T>>absent();
1075d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  }
1085d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
1095d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  /**
1105d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   * Unwraps an {@link Optional} of a {@link Wrapper} into an {@code Optional} of the underlying
1115d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   * type.
1125d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   */
1135d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  static <T> Optional<T> unwrapOptionalEquivalence(
1145d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      Optional<Equivalence.Wrapper<T>> wrappedOptional) {
1155d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    return wrappedOptional.isPresent()
1165d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        ? Optional.of(wrappedOptional.get().get())
1175d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        : Optional.<T>absent();
1185d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  }
1195d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
1205d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  private static boolean requiresEnclosingInstance(TypeElement typeElement) {
1215d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    switch (typeElement.getNestingKind()) {
1225d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      case TOP_LEVEL:
1235d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        return false;
1245d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      case MEMBER:
1255d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        return !typeElement.getModifiers().contains(STATIC);
1265d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      case ANONYMOUS:
1275d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      case LOCAL:
1285d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        return true;
1295d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      default:
1305d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        throw new AssertionError("TypeElement cannot have nesting kind: "
1315d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin            + typeElement.getNestingKind());
1325d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    }
1335d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  }
1345d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
1355d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  /**
1365d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   * Returns true if and only if a component can instantiate new instances (typically of a module)
1375d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   * rather than requiring that they be passed.
1385d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin   */
1395d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  static boolean componentCanMakeNewInstances(TypeElement typeElement) {
1405d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    switch (typeElement.getKind()) {
1415d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      case CLASS:
1425d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        break;
1435d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      case ENUM:
1445d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      case ANNOTATION_TYPE:
1455d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      case INTERFACE:
1465d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        return false;
1475d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      default:
1485d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        throw new AssertionError("TypeElement cannot have kind: " + typeElement.getKind());
1495d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    }
1505d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
1515d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    if (typeElement.getModifiers().contains(ABSTRACT)) {
1525d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      return false;
1535d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    }
1545d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
1555d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    if (requiresEnclosingInstance(typeElement)) {
1565d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      return false;
1575d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    }
1585d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
1595d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    for (Element enclosed : typeElement.getEnclosedElements()) {
1605d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      if (enclosed.getKind().equals(CONSTRUCTOR)
1615d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin          && ((ExecutableElement) enclosed).getParameters().isEmpty()
1625d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin          && !enclosed.getModifiers().contains(PRIVATE)) {
1635d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        return true;
1645d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      }
1655d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    }
1665d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
1675d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    // TODO(gak): still need checks for visibility
1685d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
1695d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    return false;
1705d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  }
1715d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
1725d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  static ImmutableSet<ExecutableElement> getUnimplementedMethods(
1735d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      Elements elements, TypeElement type) {
1745d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    ImmutableSet.Builder<ExecutableElement> unimplementedMethods = ImmutableSet.builder();
1755d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    Set<ExecutableElement> methods = getLocalAndInheritedMethods(type, elements);
1765d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    for (ExecutableElement method : methods) {
1775d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      if (method.getModifiers().contains(Modifier.ABSTRACT)) {
1785d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin        unimplementedMethods.add(method);
1795d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin      }
1805d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    }
1815d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin    return unimplementedMethods.build();
1825d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  }
1835d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin
1845d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin  private Util() {}
1855d3207ac2713386ed61c6ca8f0356e8f093a62e1Paul Duffin}
186