blob: a9794aafbe71daeaf58265f8b7d2231c858055f2 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007 - 2017 BEA Systems, Inc. and others
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Walter Harley - initial API and implementation
* IBM Corporation - fix for 342598, 382590
* Jean-Marie Henaff <jmhenaff@google.com> (Google) - Bug 481555
*******************************************************************************/
package org.eclipse.jdt.internal.compiler.apt.model;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
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.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.internal.compiler.apt.dispatch.BaseProcessingEnvImpl;
import org.eclipse.jdt.internal.compiler.ast.Wildcard;
import org.eclipse.jdt.internal.compiler.lookup.ArrayBinding;
import org.eclipse.jdt.internal.compiler.lookup.BaseTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.Binding;
import org.eclipse.jdt.internal.compiler.lookup.FieldBinding;
import org.eclipse.jdt.internal.compiler.lookup.MethodBinding;
import org.eclipse.jdt.internal.compiler.lookup.ParameterizedTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.ReferenceBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeVariableBinding;
/**
* Utilities for working with types (as opposed to elements).
* There is one of these for every ProcessingEnvironment.
*/
public class TypesImpl implements Types {
private final BaseProcessingEnvImpl _env;
/*
* The processing env creates and caches a TypesImpl. Other clients should
* not create their own; they should ask the env for it.
*/
public TypesImpl(BaseProcessingEnvImpl env) {
_env = env;
}
/* (non-Javadoc)
* @see javax.lang.model.util.Types#asElement(javax.lang.model.type.TypeMirror)
*/
@Override
public Element asElement(TypeMirror t) {
switch(t.getKind()) {
case DECLARED :
case TYPEVAR :
return _env.getFactory().newElement(((TypeMirrorImpl)t).binding());
default:
break;
}
return null;
}
@Override
public TypeMirror asMemberOf(DeclaredType containing, Element element) {
// throw new UnsupportedOperationException("NYI: TypesImpl.asMemberOf("
// + containing + ", " + element + ")"); //$NON-NLS-1$ //$NON-NLS-2$
// //$NON-NLS-3$
ElementImpl elementImpl = (ElementImpl) element;
DeclaredTypeImpl declaredTypeImpl = (DeclaredTypeImpl) containing;
ReferenceBinding referenceBinding = (ReferenceBinding) declaredTypeImpl._binding;
TypeMirror typeMirror;
switch (element.getKind()) {
case CONSTRUCTOR:
case METHOD:
typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() {
@Override
public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) {
MethodBinding methodBinding = ((MethodBinding) memberBinding);
for (MethodBinding method : typeBinding.methods()) {
if (CharOperation.equals(method.selector, methodBinding.selector)
&& (method.original() == methodBinding
|| method.areParameterErasuresEqual(methodBinding))) {
return TypesImpl.this._env.getFactory().newTypeMirror(method);
}
}
return null;
}
});
if (typeMirror != null) {
return typeMirror;
}
break;
case TYPE_PARAMETER:
typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() {
@Override
public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) {
if (typeBinding instanceof ParameterizedTypeBinding) {
TypeVariableBinding variableBinding = ((TypeVariableBinding) memberBinding);
ReferenceBinding binding = ((ParameterizedTypeBinding) typeBinding).genericType();
if (variableBinding.declaringElement == binding) { // check in advance avoid looking into type parameters unnecessarily.
TypeVariableBinding[] typeVariables = binding.typeVariables();
TypeBinding[] typeArguments = ((ParameterizedTypeBinding) typeBinding).typeArguments();
if (typeVariables.length == typeArguments.length) {
for(int i = 0; i < typeVariables.length; i++) {
if (typeVariables[i] == memberBinding) {
return TypesImpl.this._env.getFactory().newTypeMirror(typeArguments[i]);
}
}
}
}
}
return null;
}
});
if (typeMirror != null) {
return typeMirror;
}
break;
case FIELD:
case ENUM_CONSTANT:
case RECORD_COMPONENT:
typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() {
@Override
public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) {
FieldBinding fieldBinding = (FieldBinding) memberBinding;
for (FieldBinding field : typeBinding.fields()) {
if (CharOperation.equals(field.name, fieldBinding.name)) {
return TypesImpl.this._env.getFactory().newTypeMirror(field);
}
}
return null;
}
});
if (typeMirror != null) {
return typeMirror;
}
break;
case ENUM:
case ANNOTATION_TYPE:
case INTERFACE:
case CLASS:
case RECORD:
typeMirror = findMemberInHierarchy(referenceBinding, elementImpl._binding, new MemberInTypeFinder() {
@Override
public TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding) {
ReferenceBinding elementBinding = (ReferenceBinding) memberBinding;
// If referenceBinding is a ParameterizedTypeBinding, this
// will return only ParameterizedTypeBindings
// for member types, even if the member happens to be a
// static nested class. That's probably a bug;
// static nested classes are not parameterized by their
// outer class.
for (ReferenceBinding memberReferenceBinding : typeBinding.memberTypes()) {
if (CharOperation.equals(elementBinding.compoundName, memberReferenceBinding.compoundName)) {
return TypesImpl.this._env.getFactory().newTypeMirror(memberReferenceBinding);
}
}
return null;
}
});
if (typeMirror != null) {
return typeMirror;
}
break;
default:
throw new IllegalArgumentException("element " + element + //$NON-NLS-1$
" has unrecognized element kind " + element.getKind()); //$NON-NLS-1$
}
throw new IllegalArgumentException("element " + element + //$NON-NLS-1$
" is not a member of the containing type " + containing + //$NON-NLS-1$
" nor any of its superclasses"); //$NON-NLS-1$
}
private static interface MemberInTypeFinder {
TypeMirror find(ReferenceBinding typeBinding, Binding memberBinding);
}
private TypeMirror findMemberInHierarchy(ReferenceBinding typeBinding, Binding memberBinding,
MemberInTypeFinder finder) {
TypeMirror result = null;
if (typeBinding == null) {
return null;
}
result = finder.find(typeBinding, memberBinding);
if (result != null) {
return result;
}
result = findMemberInHierarchy(typeBinding.superclass(), memberBinding, finder);
if (result != null) {
return result;
}
for (ReferenceBinding superInterface : typeBinding.superInterfaces()) {
result = findMemberInHierarchy(superInterface, memberBinding, finder);
if (result != null) {
return result;
}
}
return null;
}
private void validateRealType(TypeMirror t) {
switch (t.getKind()) {
case EXECUTABLE:
case PACKAGE:
case MODULE:
throw new IllegalArgumentException(
"Executable, package and module are illegal argument for Types.contains(..)"); //$NON-NLS-1$
default:
break;
}
}
private void validateRealTypes(TypeMirror t1, TypeMirror t2) {
validateRealType(t1);
validateRealType(t2);
}
@Override
public TypeElement boxedClass(PrimitiveType p) {
PrimitiveTypeImpl primitiveTypeImpl = (PrimitiveTypeImpl) p;
BaseTypeBinding baseTypeBinding = (BaseTypeBinding)primitiveTypeImpl._binding;
TypeBinding boxed = _env.getLookupEnvironment().computeBoxingType(baseTypeBinding);
return (TypeElement) _env.getFactory().newElement(boxed);
}
@Override
public TypeMirror capture(TypeMirror t) {
validateRealType(t);
TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) t;
if (typeMirrorImpl._binding instanceof ParameterizedTypeBinding) {
throw new UnsupportedOperationException("NYI: TypesImpl.capture(...)"); //$NON-NLS-1$
}
return t;
}
@Override
public boolean contains(TypeMirror t1, TypeMirror t2) {
validateRealTypes(t1, t2);
throw new UnsupportedOperationException("NYI: TypesImpl.contains(" + t1 + ", " + t2 + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
}
@Override
public List<? extends TypeMirror> directSupertypes(TypeMirror t) {
validateRealType(t);
TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) t;
Binding binding = typeMirrorImpl._binding;
if (binding instanceof ReferenceBinding) {
ReferenceBinding referenceBinding = (ReferenceBinding) binding;
ArrayList<TypeMirror> list = new ArrayList<>();
ReferenceBinding superclass = referenceBinding.superclass();
if (superclass != null) {
list.add(this._env.getFactory().newTypeMirror(superclass));
}
for (ReferenceBinding interfaceBinding : referenceBinding.superInterfaces()) {
list.add(this._env.getFactory().newTypeMirror(interfaceBinding));
}
return Collections.unmodifiableList(list);
}
return Collections.emptyList();
}
@Override
public TypeMirror erasure(TypeMirror t) {
validateRealType(t);
TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) t;
Binding binding = typeMirrorImpl._binding;
if (binding instanceof ReferenceBinding) {
TypeBinding type = ((ReferenceBinding) binding).erasure();
if (type.isGenericType()) {
type = _env.getLookupEnvironment().convertToRawType(type, false);
}
return _env.getFactory().newTypeMirror(type);
}
if (binding instanceof ArrayBinding) {
TypeBinding typeBinding = (TypeBinding) binding;
TypeBinding leafType = typeBinding.leafComponentType().erasure();
if (leafType.isGenericType()) {
leafType = _env.getLookupEnvironment().convertToRawType(leafType, false);
}
return _env.getFactory().newTypeMirror(
this._env.getLookupEnvironment().createArrayType(leafType,
typeBinding.dimensions()));
}
return t;
}
@Override
public ArrayType getArrayType(TypeMirror componentType) {
TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) componentType;
TypeBinding typeBinding = (TypeBinding) typeMirrorImpl._binding;
return (ArrayType) _env.getFactory().newTypeMirror(
this._env.getLookupEnvironment().createArrayType(
typeBinding.leafComponentType(),
typeBinding.dimensions() + 1));
}
/*
* (non-Javadoc)
* Create a type instance by parameterizing a type element. If the element is a member type,
* its container won't be parameterized (if it needs to be, you would need to use the form of
* getDeclaredType that takes a container TypeMirror). If typeArgs is empty, and typeElem
* is not generic, then you should use TypeElem.asType(). If typeArgs is empty and typeElem
* is generic, this method will create the raw type.
*/
@Override
public DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) {
int typeArgsLength = typeArgs.length;
TypeElementImpl typeElementImpl = (TypeElementImpl) typeElem;
ReferenceBinding elementBinding = (ReferenceBinding) typeElementImpl._binding;
TypeVariableBinding[] typeVariables = elementBinding.typeVariables();
int typeVariablesLength = typeVariables.length;
if (typeArgsLength == 0) {
if (elementBinding.isGenericType()) {
// per javadoc,
return (DeclaredType) _env.getFactory().newTypeMirror(this._env.getLookupEnvironment().createRawType(elementBinding, null));
}
return (DeclaredType)typeElem.asType();
} else if (typeArgsLength != typeVariablesLength) {
throw new IllegalArgumentException("Number of typeArguments doesn't match the number of formal parameters of typeElem"); //$NON-NLS-1$
}
TypeBinding[] typeArguments = new TypeBinding[typeArgsLength];
for (int i = 0; i < typeArgsLength; i++) {
TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) typeArgs[i];
Binding binding = typeMirrorImpl._binding;
if (!(binding instanceof TypeBinding)) {
throw new IllegalArgumentException("Invalid type argument: " + typeMirrorImpl); //$NON-NLS-1$
}
typeArguments[i] = (TypeBinding) binding;
}
ReferenceBinding enclosing = elementBinding.enclosingType();
if (enclosing != null) {
enclosing = this._env.getLookupEnvironment().createRawType(enclosing, null);
}
return (DeclaredType) _env.getFactory().newTypeMirror(
this._env.getLookupEnvironment().createParameterizedType(elementBinding, typeArguments, enclosing));
}
/* (non-Javadoc)
* Create a specific type from a member element. The containing type can be parameterized,
* e.g. Outer<String>.Inner, but it cannot be generic, i.e., Outer<T>.Inner. It only makes
* sense to use this method when the member element is parameterized by its container; so,
* for example, it makes sense for an inner class but not for a static member class.
* Otherwise you should just use getDeclaredType(TypeElement, TypeMirror ...), if you need
* to specify type arguments, or TypeElement.asType() directly, if not.
*/
@Override
public DeclaredType getDeclaredType(DeclaredType containing, TypeElement typeElem,
TypeMirror... typeArgs) {
int typeArgsLength = typeArgs.length;
TypeElementImpl typeElementImpl = (TypeElementImpl) typeElem;
ReferenceBinding elementBinding = (ReferenceBinding) typeElementImpl._binding;
TypeVariableBinding[] typeVariables = elementBinding.typeVariables();
int typeVariablesLength = typeVariables.length;
DeclaredTypeImpl declaredTypeImpl = (DeclaredTypeImpl) containing;
ReferenceBinding enclosingType = (ReferenceBinding) declaredTypeImpl._binding;
if (typeArgsLength == 0) {
if (elementBinding.isGenericType()) {
// e.g., Outer.Inner<T> but T is not specified
// Per javadoc on interface, must return the raw type Outer.Inner
return (DeclaredType) _env.getFactory().newTypeMirror(
_env.getLookupEnvironment().createRawType(elementBinding, enclosingType));
} else {
// e.g., Outer<Long>.Inner
ParameterizedTypeBinding ptb = _env.getLookupEnvironment().createParameterizedType(elementBinding, null, enclosingType);
return (DeclaredType) _env.getFactory().newTypeMirror(ptb);
}
} else if (typeArgsLength != typeVariablesLength) {
throw new IllegalArgumentException("Number of typeArguments doesn't match the number of formal parameters of typeElem"); //$NON-NLS-1$
}
TypeBinding[] typeArguments = new TypeBinding[typeArgsLength];
for (int i = 0; i < typeArgsLength; i++) {
TypeMirrorImpl typeMirrorImpl = (TypeMirrorImpl) typeArgs[i];
Binding binding = typeMirrorImpl._binding;
if (!(binding instanceof TypeBinding)) {
throw new IllegalArgumentException("Invalid type for a type arguments : " + typeMirrorImpl); //$NON-NLS-1$
}
typeArguments[i] = (TypeBinding) binding;
}
return (DeclaredType) _env.getFactory().newTypeMirror(
this._env.getLookupEnvironment().createParameterizedType(elementBinding, typeArguments, enclosingType));
}
@Override
public NoType getNoType(TypeKind kind) {
return _env.getFactory().getNoType(kind);
}
@Override
public NullType getNullType() {
return _env.getFactory().getNullType();
}
@Override
public PrimitiveType getPrimitiveType(TypeKind kind) {
return _env.getFactory().getPrimitiveType(kind);
}
@Override
public WildcardType getWildcardType(TypeMirror extendsBound, TypeMirror superBound) {
if (extendsBound != null && superBound != null) {
throw new IllegalArgumentException("Extends and super bounds cannot be set at the same time"); //$NON-NLS-1$
}
if (extendsBound != null) {
TypeMirrorImpl extendsBoundMirrorType = (TypeMirrorImpl) extendsBound;
TypeBinding typeBinding = (TypeBinding) extendsBoundMirrorType._binding;
return (WildcardType) _env.getFactory().newTypeMirror(
this._env.getLookupEnvironment().createWildcard(
null,
0,
typeBinding,
null,
Wildcard.EXTENDS));
}
if (superBound != null) {
TypeMirrorImpl superBoundMirrorType = (TypeMirrorImpl) superBound;
TypeBinding typeBinding = (TypeBinding) superBoundMirrorType._binding;
return new WildcardTypeImpl(_env, this._env.getLookupEnvironment().createWildcard(
null,
0,
typeBinding,
null,
Wildcard.SUPER));
}
return new WildcardTypeImpl(_env, this._env.getLookupEnvironment().createWildcard(
null,
0,
null,
null,
Wildcard.UNBOUND));
}
/* (non-Javadoc)
* @return true if a value of type t1 can be assigned to a variable of type t2, i.e., t2 = t1.
*/
@Override
public boolean isAssignable(TypeMirror t1, TypeMirror t2) {
validateRealTypes(t1, t2);
if (!(t1 instanceof TypeMirrorImpl) || !(t2 instanceof TypeMirrorImpl)) {
return false;
}
Binding b1 = ((TypeMirrorImpl)t1).binding();
Binding b2 = ((TypeMirrorImpl)t2).binding();
if (!(b1 instanceof TypeBinding) || !(b2 instanceof TypeBinding)) {
// package, method, import, etc.
throw new IllegalArgumentException();
}
if (((TypeBinding)b1).isCompatibleWith((TypeBinding)b2)) {
return true;
}
TypeBinding convertedType = _env.getLookupEnvironment().computeBoxingType((TypeBinding)b1);
return null != convertedType && convertedType.isCompatibleWith((TypeBinding)b2);
}
@Override
public boolean isSameType(TypeMirror t1, TypeMirror t2) {
if (t1 instanceof NoTypeImpl) {
if (t2 instanceof NoTypeImpl) {
return ((NoTypeImpl) t1).getKind() == ((NoTypeImpl) t2).getKind();
}
return false;
} else if (t2 instanceof NoTypeImpl) {
return false;
}
if (t1.getKind() == TypeKind.WILDCARD || t2.getKind() == TypeKind.WILDCARD) {
// Wildcard types are never equal, according to the spec of this method
return false;
}
if (t1 == t2) {
return true;
}
if (!(t1 instanceof TypeMirrorImpl) || !(t2 instanceof TypeMirrorImpl)) {
return false;
}
Binding b1 = ((TypeMirrorImpl)t1).binding();
Binding b2 = ((TypeMirrorImpl)t2).binding();
if (b1 == b2) {
return true;
}
if (!(b1 instanceof TypeBinding) || !(b2 instanceof TypeBinding)) {
return false;
}
TypeBinding type1 = ((TypeBinding) b1);
TypeBinding type2 = ((TypeBinding) b2);
if (TypeBinding.equalsEquals(type1, type2))
return true;
return CharOperation.equals(type1.computeUniqueKey(), type2.computeUniqueKey());
}
@Override
public boolean isSubsignature(ExecutableType m1, ExecutableType m2) {
MethodBinding methodBinding1 = (MethodBinding) ((ExecutableTypeImpl) m1)._binding;
MethodBinding methodBinding2 = (MethodBinding) ((ExecutableTypeImpl) m2)._binding;
if (!CharOperation.equals(methodBinding1.selector, methodBinding2.selector))
return false;
return methodBinding1.areParameterErasuresEqual(methodBinding2) && methodBinding1.areTypeVariableErasuresEqual(methodBinding2);
}
/* (non-Javadoc)
* @return true if t1 is a subtype of t2, or if t1 == t2.
*/
@Override
public boolean isSubtype(TypeMirror t1, TypeMirror t2) {
validateRealTypes(t1, t2);
if (t1 instanceof NoTypeImpl) {
if (t2 instanceof NoTypeImpl) {
return ((NoTypeImpl) t1).getKind() == ((NoTypeImpl) t2).getKind();
}
return false;
} else if (t2 instanceof NoTypeImpl) {
return false;
}
if (!(t1 instanceof TypeMirrorImpl) || !(t2 instanceof TypeMirrorImpl)) {
throw new IllegalArgumentException();
}
if (t1 == t2) {
return true;
}
Binding b1 = ((TypeMirrorImpl)t1).binding();
Binding b2 = ((TypeMirrorImpl)t2).binding();
if (b1 == b2) {
return true;
}
if (!(b1 instanceof TypeBinding) || !(b2 instanceof TypeBinding)) {
// package, method, import, etc.
throw new IllegalArgumentException();
}
if (b1.kind() == Binding.BASE_TYPE || b2.kind() == Binding.BASE_TYPE) {
if (b1.kind() != b2.kind()) {
return false;
}
else {
// for primitives, compatibility implies subtype
return ((TypeBinding)b1).isCompatibleWith((TypeBinding)b2);
}
}
return ((TypeBinding)b1).isCompatibleWith((TypeBinding)b2);
}
@Override
public PrimitiveType unboxedType(TypeMirror t) {
if (!(((TypeMirrorImpl)t)._binding instanceof ReferenceBinding)) {
// Not an unboxable type - could be primitive, array, not a type at all, etc.
throw new IllegalArgumentException("Given type mirror cannot be unboxed"); //$NON-NLS-1$
}
ReferenceBinding boxed = (ReferenceBinding)((TypeMirrorImpl)t)._binding;
TypeBinding unboxed = _env.getLookupEnvironment().computeBoxingType(boxed);
if (unboxed.kind() != Binding.BASE_TYPE) {
// No boxing conversion was found
throw new IllegalArgumentException();
}
return (PrimitiveType) _env.getFactory().newTypeMirror((BaseTypeBinding)unboxed);
}
}