public TypeMirror getCanonicalType()

in src/com/facebook/buck/jvm/java/abi/source/PostEnterCanonicalizer.java [109:242]


  public TypeMirror getCanonicalType(
      @PropagatesNullable TypeMirror typeMirror, @Nullable TreePath treePath) {
    if (typeMirror == null) {
      return null;
    }

    Tree tree = treePath == null ? null : treePath.getLeaf();
    switch (typeMirror.getKind()) {
      case ARRAY:
        {
          ArrayType arrayType = (ArrayType) typeMirror;
          return types.getArrayType(
              getCanonicalType(
                  arrayType.getComponentType(),
                  treePath,
                  tree == null ? null : ((ArrayTypeTree) tree).getType()));
        }
      case TYPEVAR:
        {
          TypeVariable typeVar = (TypeVariable) typeMirror;
          return elements.getCanonicalElement(typeVar.asElement()).asType();
        }
      case WILDCARD:
        {
          WildcardType wildcardType = (WildcardType) typeMirror;
          Tree boundTree = tree == null ? null : ((WildcardTree) tree).getBound();
          return types.getWildcardType(
              getCanonicalType(wildcardType.getExtendsBound(), treePath, boundTree),
              getCanonicalType(wildcardType.getSuperBound(), treePath, boundTree));
        }
      case DECLARED:
        {
          DeclaredType declaredType = (DeclaredType) typeMirror;

          // It is possible to have a DeclaredType with ErrorTypes for arguments, so we must
          // compute the TreePaths while canonicalizing type arguments
          List<? extends TypeMirror> underlyingTypeArgs = declaredType.getTypeArguments();
          TypeMirror[] canonicalTypeArgs;
          if (underlyingTypeArgs.isEmpty()) {
            canonicalTypeArgs = new TypeMirror[0];
          } else {
            canonicalTypeArgs =
                getCanonicalTypes(
                        underlyingTypeArgs,
                        treePath,
                        tree == null ? null : ((ParameterizedTypeTree) tree).getTypeArguments())
                    .toArray(new TypeMirror[0]);
          }

          // While it is not possible to have a DeclaredType with an enclosing ErrorType (the only
          // way to get a DeclaredType in the first place is if the compiler can resolve all
          // enclosing types), it *is* possible to have a DeclaredType with an enclosing
          // DeclaredType that has ErrorTypes for type arguments. So we need to check if there's an
          // explicitly specified enclosing type and provide the tree if so.
          TypeMirror enclosingType = declaredType.getEnclosingType();
          DeclaredType canonicalEnclosingType = null;
          if (enclosingType.getKind() != TypeKind.NONE) {
            TreePath enclosingTypePath = treePath;
            if (enclosingTypePath != null
                && enclosingTypePath.getLeaf().getKind() == Tree.Kind.PARAMETERIZED_TYPE) {
              enclosingTypePath =
                  new TreePath(
                      enclosingTypePath,
                      ((ParameterizedTypeTree) enclosingTypePath.getLeaf()).getType());
            }
            if (enclosingTypePath != null
                && enclosingTypePath.getLeaf().getKind() == Tree.Kind.MEMBER_SELECT) {
              enclosingTypePath =
                  new TreePath(
                      enclosingTypePath,
                      ((MemberSelectTree) enclosingTypePath.getLeaf()).getExpression());
            } else {
              enclosingTypePath = null;
            }
            canonicalEnclosingType =
                (DeclaredType) getCanonicalType(enclosingType, enclosingTypePath);
          }

          TypeElement canonicalElement =
              (TypeElement) elements.getCanonicalElement(declaredType.asElement());
          // If an import statement for a type that is not available would shadow a type from a
          // star-imported package (such as java.lang), the compiler will happily resolve to the
          // star-imported type (expecting that the imported type will be filled in by an annotation
          // processor). We check whether we would have inferred something different.
          if (canonicalElement.getNestingKind() == NestingKind.TOP_LEVEL
              && treePath != null
              && treePath.getLeaf().getKind() == Tree.Kind.IDENTIFIER) {
            DeclaredType inferredType = (DeclaredType) getImportedType(treePath);
            if (inferredType != null) {
              TypeElement inferredElement =
                  (TypeElement) elements.getCanonicalElement(inferredType.asElement());
              canonicalElement = inferredElement;
            }
          }

          return types.getDeclaredType(canonicalEnclosingType, canonicalElement, canonicalTypeArgs);
        }
      case PACKAGE:
      case ERROR:
        {
          if (treePath == null) {
            throw new IllegalArgumentException("Cannot resolve error types without a Tree.");
          }

          try {
            return getInferredType(treePath);
          } catch (CompilerErrorException e) {
            javacTrees.printMessage(
                Kind.ERROR, e.getMessage(), treePath.getLeaf(), treePath.getCompilationUnit());
            return typeMirror;
          }
        }
      case BOOLEAN:
      case BYTE:
      case SHORT:
      case INT:
      case LONG:
      case CHAR:
      case FLOAT:
      case DOUBLE:
      case VOID:
      case NONE:
      case NULL:
        return typeMirror;
      case EXECUTABLE:
      case OTHER:
      case UNION:
      case INTERSECTION:
        // Temporary. Remove once migration to Java 10/11 is complete.
        // $CASES-OMITTED$
      default:
        throw new UnsupportedOperationException();
    }
  }