/* * Copyright 2015 Lukas Krejci * * 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 org.revapi.java.compilation; import static org.revapi.java.model.MissingTypeElement.isMissing; import java.util.Collections; import java.util.List; import java.util.function.BiFunction; import java.util.function.Function; import javax.lang.model.element.Element; import javax.lang.model.element.TypeElement; import javax.lang.model.type.ArrayType; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.ExecutableType; import javax.lang.model.type.NoType; import javax.lang.model.type.NullType; import javax.lang.model.type.PrimitiveType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; import javax.lang.model.type.WildcardType; import javax.lang.model.util.Types; import org.revapi.java.model.MissingTypeElement; import org.revapi.java.spi.IgnoreCompletionFailures; /** * @author Lukas Krejci * @since 0.1 */ final class MissingTypeAwareDelegatingTypes implements Types { private final Types types; public MissingTypeAwareDelegatingTypes(Types types) { this.types = types; } @Override public Element asElement(final TypeMirror t) { return IgnoreCompletionFailures.in(checkMissing(types::asElement, null), t); } @Override public boolean isSameType(final TypeMirror t1, final TypeMirror t2) { return IgnoreCompletionFailures.in(checkMissing(types::isSameType, false), t1, t2); } @Override public boolean isSubtype(final TypeMirror t1, final TypeMirror t2) { return IgnoreCompletionFailures.in(checkMissing(types::isSubtype, false), t1, t2); } @Override public boolean isAssignable(final TypeMirror t1, final TypeMirror t2) { return IgnoreCompletionFailures.in(checkMissing(types::isAssignable, false), t1, t2); } @Override public boolean contains(final TypeMirror t1, final TypeMirror t2) { return IgnoreCompletionFailures.in(checkMissing(types::contains, false), t1, t2); } @Override public boolean isSubsignature(final ExecutableType m1, final ExecutableType m2) { return IgnoreCompletionFailures.in(checkMissing(types::isSubsignature, false), m1, m2); } @Override public List<? extends TypeMirror> directSupertypes(TypeMirror t) { return IgnoreCompletionFailures.in(checkMissing(types::directSupertypes, Collections.emptyList()), t); } @Override public TypeMirror erasure(TypeMirror t) { return IgnoreCompletionFailures.in(checkMissing(types::erasure, t), t); } @Override public TypeElement boxedClass(PrimitiveType p) { return IgnoreCompletionFailures.in(types::boxedClass, p); } @Override public PrimitiveType unboxedType(TypeMirror t) { if (isMissing(t)) { throw new IllegalArgumentException("Type " + t + " does not have an unboxing conversion."); } return IgnoreCompletionFailures.in(types::unboxedType, t); } @Override public TypeMirror capture(TypeMirror t) { return IgnoreCompletionFailures.in(checkMissing(types::capture, t), t); } @Override public PrimitiveType getPrimitiveType(TypeKind kind) { return types.getPrimitiveType(kind); } @Override public NullType getNullType() { return types.getNullType(); } @Override public NoType getNoType(TypeKind kind) { return types.getNoType(kind); } @Override public ArrayType getArrayType(TypeMirror componentType) { if (isMissing(componentType)) { throw new IllegalArgumentException("Type " + componentType + " is not a valid component of an array."); } return IgnoreCompletionFailures.in(types::getArrayType, componentType); } @Override public WildcardType getWildcardType(TypeMirror extendsBound, TypeMirror superBound) { if (isMissing(extendsBound) || isMissing(superBound)) { throw new IllegalArgumentException("Invalid bounds."); } return IgnoreCompletionFailures.in(types::getWildcardType, extendsBound, superBound); } @Override public DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) { if (typeElem instanceof MissingTypeElement) { throw new IllegalArgumentException("Invalid type element."); } for (TypeMirror t : typeArgs) { if (isMissing(t)) { throw new IllegalArgumentException("Invalid type arguments."); } } return IgnoreCompletionFailures.in(types::getDeclaredType, typeElem, typeArgs); } @Override public DeclaredType getDeclaredType(DeclaredType containing, TypeElement typeElem, TypeMirror... typeArgs) { if (isMissing(containing)) { throw new IllegalArgumentException("Invalid containing type."); } if (typeElem instanceof MissingTypeElement) { throw new IllegalArgumentException("Invalid type element."); } for (TypeMirror t : typeArgs) { if (isMissing(t)) { throw new IllegalArgumentException("Invalid type arguments."); } } return IgnoreCompletionFailures.in(types::getDeclaredType, containing, typeElem, typeArgs); } @Override public TypeMirror asMemberOf(DeclaredType containing, Element element) { if (isMissing(containing)) { throw new IllegalArgumentException("Invalid containing type."); } if (element instanceof MissingTypeElement) { throw new IllegalArgumentException("Invalid element."); } return IgnoreCompletionFailures.in(types::asMemberOf, containing, element); } private static <R, T extends TypeMirror> IgnoreCompletionFailures.Fn1<R, T> checkMissing(Function<T, R> fn, R returnValueOnMissing) { return (t) -> { if (isMissing(t)) { return returnValueOnMissing; } else { return fn.apply(t); } }; } private static <R, T1 extends TypeMirror, T2 extends TypeMirror> IgnoreCompletionFailures.Fn2<R, T1, T2> checkMissing(BiFunction<T1, T2, R> fn, R returnValueOnMissing) { return (t1, t2) -> { if (isMissing(t1) || isMissing(t2)) { return returnValueOnMissing; } else { return fn.apply(t1, t2); } }; } }