/*
 * Copyright (C) 2020 The Dagger Authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package dagger.internal.codegen.validation;

import static androidx.room.compiler.processing.compat.XConverters.toJavac;

import androidx.room.compiler.processing.XType;
import com.google.auto.common.MoreTypes;
import com.google.auto.common.SuperficialValidation;
import com.google.common.base.Equivalence;
import dagger.internal.codegen.langmodel.DaggerTypes;
import java.util.ArrayDeque;
import java.util.HashSet;
import java.util.Queue;
import java.util.Set;
import javax.lang.model.type.TypeMirror;

/** Utility methods for validating the type hierarchy of a given type. */
final class TypeHierarchyValidator {
  private TypeHierarchyValidator() {}

  /**
   * Validate the type hierarchy of the given type including all super classes, interfaces, and
   * type parameters.
   *
   * @throws TypeNotPresentException if an type in the hierarchy is not valid.
   */
  public static void validateTypeHierarchy(XType type, DaggerTypes types) {
    validateTypeHierarchy(toJavac(type), types);
  }

  /**
   * Validate the type hierarchy of the given type including all super classes, interfaces, and
   * type parameters.
   *
   * @throws TypeNotPresentException if an type in the hierarchy is not valid.
   */
  public static void validateTypeHierarchy(TypeMirror type, DaggerTypes types) {
    Queue<TypeMirror> queue = new ArrayDeque<>();
    Set<Equivalence.Wrapper<TypeMirror>> queued = new HashSet<>();
    queue.add(type);
    queued.add(MoreTypes.equivalence().wrap(type));
    while (!queue.isEmpty()) {
      TypeMirror currType = queue.remove();
      if (!SuperficialValidation.validateType(currType)) {
        throw new TypeNotPresentException(currType.toString(), null);
      }
      for (TypeMirror superType : types.directSupertypes(currType)) {
        if (queued.add(MoreTypes.equivalence().wrap(superType))) {
          queue.add(superType);
        }
      }
    }
  }
}

@@ -1545,357 +1545,8 @@
 ) %7B%0A
-    validateTypeHierarchy(toJavac(type), types);%0A  %7D%0A%0A  /**%0A   * Validate the type hierarchy of the given type including all super classes, interfaces, and%0A   * type parameters.%0A   *%0A   * @throws TypeNotPresentException if an type in the hierarchy is not valid.%0A   */%0A  public static void validateTypeHierarchy(TypeMirror type, DaggerTypes types) %7B%0A
     
@@ -1551,26 +1551,21 @@
   Queue%3C
+X
 Type
-Mirror
 %3E queue 
@@ -1722,14 +1722,23 @@
 rap(
+toJavac(
 type))
+)
 ;%0A  
@@ -1772,26 +1772,21 @@
 %7B%0A      
+X
 Type
-Mirror
  currTyp
@@ -1851,16 +1851,24 @@
 ateType(
+toJavac(
 currType
@@ -1861,32 +1861,33 @@
 Javac(currType))
+)
  %7B%0A        throw
@@ -1962,26 +1962,21 @@
    for (
+X
 Type
-Mirror
  superTy
@@ -1984,39 +1984,31 @@
 e : 
-types.direc
+currType.ge
 tSuper
-t
+T
 ypes(
-currType
 )) %7B
@@ -2060,16 +2060,24 @@
 ().wrap(
+toJavac(
 superTyp
@@ -2072,32 +2072,33 @@
 vac(superType)))
+)
  %7B%0A          que

Use `XType#getSuperTypes` instead of `Types#directSupertypes`.