blob: 71317ea460f19294199866ab6070aa3bfc8d1a70 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005 BEA Systems, Inc.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* tyeung@bea.com - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.apt.core.internal.util;
import com.sun.mirror.declaration.PackageDeclaration;
import com.sun.mirror.declaration.TypeDeclaration;
import com.sun.mirror.declaration.TypeParameterDeclaration;
import com.sun.mirror.type.ArrayType;
import com.sun.mirror.type.DeclaredType;
import com.sun.mirror.type.PrimitiveType;
import com.sun.mirror.type.ReferenceType;
import com.sun.mirror.type.TypeMirror;
import com.sun.mirror.type.TypeVariable;
import com.sun.mirror.type.VoidType;
import com.sun.mirror.type.WildcardType;
import com.sun.mirror.util.Types;
import java.util.Collection;
import org.eclipse.jdt.apt.core.internal.EclipseMirrorImpl;
import org.eclipse.jdt.apt.core.internal.NonEclipseImplementationException;
import org.eclipse.jdt.apt.core.internal.declaration.PackageDeclarationImpl;
import org.eclipse.jdt.apt.core.internal.declaration.TypeDeclarationImpl;
import org.eclipse.jdt.apt.core.internal.declaration.TypeParameterDeclarationImpl;
import org.eclipse.jdt.apt.core.internal.env.BaseProcessorEnv;
import org.eclipse.jdt.apt.core.internal.type.ArrayTypeImpl;
import org.eclipse.jdt.apt.core.internal.type.PrimitiveTypeImpl;
import org.eclipse.jdt.apt.core.internal.type.VoidTypeImpl;
import org.eclipse.jdt.apt.core.internal.type.WildcardTypeImpl;
import org.eclipse.jdt.core.BindingKey;
import org.eclipse.jdt.core.Signature;
import org.eclipse.jdt.core.dom.IPackageBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
public class TypesUtil implements Types
{
private static final String[] NO_ARGS = new String[0];
private final BaseProcessorEnv _env;
public static void main(String[] args){}
public TypesUtil(BaseProcessorEnv env){
_env = env;
assert env != null : "null environment."; //$NON-NLS-1$
}
public ArrayType getArrayType(TypeMirror componentType)
{
if( componentType == null ) return null;
if( componentType instanceof EclipseMirrorImpl ){
final EclipseMirrorImpl impl = (EclipseMirrorImpl)componentType;
// the leaf type of the array
final ITypeBinding leaf;
final int dimension;
switch( impl.kind() )
{
case TYPE_ERROR:
throw new IllegalArgumentException("cannot create an array from error type"); //$NON-NLS-1$
case TYPE_VOID:
throw new IllegalArgumentException("cannot create an array from void type"); //$NON-NLS-1$
case TYPE_PRIMITIVE:
leaf = ((PrimitiveTypeImpl)componentType).getTypeBinding();
dimension = 1;
break;
case TYPE_ARRAY:
final ITypeBinding array = ((ArrayTypeImpl)componentType).getArrayBinding();
dimension = array.getDimensions() + 1;
leaf = array.getElementType();
break;
case TYPE_WILDCARD:
leaf = ((WildcardTypeImpl)componentType).getWildcardBinding();
dimension = 1;
break;
default:
leaf = ((TypeDeclarationImpl)componentType).getTypeBinding();
dimension = 1;
}
if( leaf == null || leaf.isParameterizedType() )
throw new IllegalArgumentException("illegal component type: " + componentType); //$NON-NLS-1$
final String bindingKey = BindingKey.createArrayTypeBindingKey(leaf.getKey(), dimension);
final ITypeBinding arrayType = _env.getTypeBinding(bindingKey);
if(arrayType == null)
return null;
return (ArrayType)Factory.createTypeMirror(arrayType, _env);
}
throw new NonEclipseImplementationException("only applicable to eclipse type system objects." + //$NON-NLS-1$
" Found " + componentType.getClass().getName()); //$NON-NLS-1$
}
/**
* @param outer a type
* @param inner the simple name of the nested class
* @return the binding that correspond to <code>outer.getQualifiedName()</code>.<code>inner</code>
* or null if it cannot be located.
*/
private ITypeBinding findMemberType(ITypeBinding outer, String inner )
{
if( outer == null || inner == null ) return null;
outer = outer.getTypeDeclaration();
final ITypeBinding[] nestedTypes = outer.getDeclaredTypes();
// first we search throw the ones that are directly declared within 'outer'
for( ITypeBinding nestedType : nestedTypes ){
if( inner.equals(nestedType.getName()) )
return nestedType;
}
// then we look up the hierachy chain.
// first we search the super type
ITypeBinding result = findMemberType(outer.getSuperclass(), inner);
if( result != null ) return result;
// then the super interfaces
final ITypeBinding[] interfaces = outer.getInterfaces();
for( ITypeBinding interfaceType : interfaces ){
result = findMemberType(interfaceType, inner);
if( result != null ) return result;
}
// can't find it.
return null;
}
public com.sun.mirror.type.DeclaredType getDeclaredType(DeclaredType containing, TypeDeclaration decl, TypeMirror... typeArgs)
{
if( decl == null ) return null;
final ITypeBinding outerBinding = getTypeBinding(containing);
final ITypeBinding memberBinding;
if( containing == null )
memberBinding = getTypeBinding(decl);
else{
if( outerBinding.isGenericType() )
throw new IllegalArgumentException("[containing], " + containing + ", is a generic type."); //$NON-NLS-1$ //$NON-NLS-2$
// make sure 'decl' is a valid member of 'outerBinding'
memberBinding = findMemberType(outerBinding, decl.getSimpleName() );
if( memberBinding == null )
throw new IllegalArgumentException(decl + " is not a member type of " + containing ); //$NON-NLS-1$
}
final int numArgs = typeArgs == null ? 0 : typeArgs.length;
if( memberBinding.isGenericType() ){
final String[] argKeys = numArgs == 0 ? NO_ARGS : new String[numArgs];
for( int i=0; i<numArgs; i++ ){
final ITypeBinding binding = getTypeBinding(typeArgs[i]);
assert binding != null : "failed to get binding mirror type"; //$NON-NLS-1$
argKeys[i] = binding.getKey();
}
final ITypeBinding[] typeParams = memberBinding.getTypeParameters();
final int numTypeParams = typeParams == null ? 0 : typeParams.length;
// if no argument then a raw type will be created, otherwise it's an error when the
// number of type parameter and arguments don't agree.
if( numTypeParams != numArgs && numArgs != 0 )
throw new IllegalArgumentException("type, " + memberBinding.getQualifiedName() + ", require " + numTypeParams + " type arguments " + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
"but found " + numArgs ); //$NON-NLS-1$
final String typeKey = BindingKey.createParameterizedTypeBindingKey(memberBinding.getKey(), argKeys);
final ITypeBinding resultBinding = _env.getTypeBinding(typeKey);
return Factory.createReferenceType(resultBinding, _env);
}
else{
if( numArgs != 0 )
throw new IllegalArgumentException("type, " + memberBinding + " is not a generic type and cannot have type arguments."); //$NON-NLS-1$ //$NON-NLS-2$
// simple case, turning a non-generic TypeDeclaration into a DeclaredType
return (DeclaredType)decl;
}
}
public com.sun.mirror.type.DeclaredType getDeclaredType(TypeDeclaration decl, TypeMirror... typeArgs)
{
return getDeclaredType(null, decl, typeArgs);
}
public TypeMirror getErasure(TypeMirror t)
{
if( t == null ) return null;
if(t instanceof EclipseMirrorImpl){
final EclipseMirrorImpl impl = (EclipseMirrorImpl)t;
final ITypeBinding binding;
switch( impl.kind() )
{
case TYPE_PRIMITIVE:
case TYPE_VOID:
case TYPE_ERROR:
return t;
case TYPE_ARRAY:
binding = ((ArrayTypeImpl)t).getArrayBinding();
break;
case TYPE_WILDCARD:
binding = ((WildcardTypeImpl)t).getWildcardBinding();
break;
default:
binding = ((TypeDeclarationImpl)t).getTypeBinding();
}
final ITypeBinding erasure = binding.getErasure();
if( erasure == binding ) return t;
TypeMirror m_erasure = Factory.createTypeMirror(erasure, impl.getEnvironment() );
if( m_erasure == null )
return Factory.createErrorClassType(erasure);
return m_erasure;
}
throw new NonEclipseImplementationException("only applicable to eclipse type system objects." + //$NON-NLS-1$
" Found " + t.getClass().getName()); //$NON-NLS-1$
}
public PrimitiveType getPrimitiveType(PrimitiveType.Kind kind)
{
if( kind == null ) return null;
switch(kind)
{
case BOOLEAN: return _env.getBooleanType();
case BYTE: return _env.getByteType();
case CHAR: return _env.getCharType();
case DOUBLE: return _env.getDoubleType();
case FLOAT: return _env.getFloatType();
case INT: return _env.getIntType();
case LONG: return _env.getLongType();
case SHORT: return _env.getShortType();
default: throw new IllegalStateException("unknown primitive kind : " + kind); //$NON-NLS-1$
}
}
public TypeVariable getTypeVariable(TypeParameterDeclaration tparam)
{
if( tparam == null ) return null;
if( tparam instanceof TypeParameterDeclarationImpl)
return (TypeVariable) tparam;
throw new NonEclipseImplementationException("only applicable to eclipse type system objects." + //$NON-NLS-1$
" Found " + tparam.getClass().getName()); //$NON-NLS-1$
}
public VoidType getVoidType()
{
return _env.getVoidType();
}
public WildcardType getWildcardType(Collection<ReferenceType> upperBounds, Collection<ReferenceType> lowerBounds)
{
final String boundKey;
final char boundKind;
final int upperBoundCount = upperBounds == null ? 0 : upperBounds.size();
final int lowerBoundCount = lowerBounds == null ? 0 : lowerBounds.size();
if( upperBoundCount == 0 && lowerBoundCount == 0 ){
boundKey = null;
boundKind = Signature.C_STAR;
}
else if( upperBoundCount == 1 && lowerBoundCount == 0){
final ITypeBinding binding = getTypeBinding(upperBounds.iterator().next());
boundKey = binding.getKey();
boundKind = Signature.C_EXTENDS;
}
else if(lowerBoundCount == 1 && upperBoundCount == 0){
final ITypeBinding binding = getTypeBinding(lowerBounds.iterator().next());
boundKey = binding.getKey();
boundKind = Signature.C_SUPER;
}
else
throw new IllegalArgumentException("Wildcard can only have a upper bound, a lower bound or be unbounded."); //$NON-NLS-1$
final String wildcardkey = BindingKey.createWilcardTypeBindingKey(boundKey, boundKind);
final ITypeBinding wildcard = _env.getTypeBinding(wildcardkey);
return (WildcardType)Factory.createTypeMirror(wildcard, _env);
}
/**
* @return true iff t2 = t1 does not require explicit casting and not cause an error.
*/
public boolean isAssignable(TypeMirror t1, TypeMirror t2)
{
final ITypeBinding left = getTypeBinding(t1);
final ITypeBinding right = getTypeBinding(t2);
if( left == right ) return true;
else if( left == null || right == null ) return false;
return right.isAssignmentCompatible(left);
}
public boolean isSubtype(TypeMirror t1, TypeMirror t2)
{
final ITypeBinding b1 = getTypeBinding(t1);
final ITypeBinding b2 = getTypeBinding(t2);
if( b1 == null || b2 == null ) return false;
return b1.isSubTypeCompatible(b2);
}
public static IPackageBinding getPackageBinding(PackageDeclaration pkg)
throws NonEclipseImplementationException
{
if(pkg == null) return null;
if( pkg instanceof EclipseMirrorImpl ){
final PackageDeclarationImpl impl = (PackageDeclarationImpl)pkg;
return impl.getPackageBinding();
}
throw new NonEclipseImplementationException("only applicable to eclipse type system objects." + //$NON-NLS-1$
" Found " + pkg.getClass().getName()); //$NON-NLS-1$
}
/**
* @return the binding correspond to the given type.
* Return null if the type is an error marker.
* @throws NonEclipseImplementationException
*/
public static ITypeBinding getTypeBinding(TypeMirror type)
throws NonEclipseImplementationException
{
if(type == null ) return null;
if( type instanceof EclipseMirrorImpl ){
final EclipseMirrorImpl impl = (EclipseMirrorImpl)type;
switch(impl.kind() )
{
case TYPE_PRIMITIVE: return ((PrimitiveTypeImpl)type).getTypeBinding();
case TYPE_VOID: return ((VoidTypeImpl)type).getTypeBinding();
case TYPE_ERROR: return null;
case TYPE_ARRAY: return ((ArrayTypeImpl)type).getArrayBinding();
case TYPE_WILDCARD: return ((WildcardTypeImpl)type).getWildcardBinding();
default: return ((TypeDeclarationImpl)type).getTypeBinding();
}
}
throw new NonEclipseImplementationException("only applicable to eclipse type system objects." + //$NON-NLS-1$
" Found " + type.getClass().getName()); //$NON-NLS-1$
}
/**
* @return the binding correspond to the given type.
* @throws NonEclipseImplementationException
*/
public static ITypeBinding getTypeBinding(TypeDeclaration type)
throws NonEclipseImplementationException
{
if(type == null ) return null;
if( type instanceof EclipseMirrorImpl ){
return ((TypeDeclarationImpl)type).getTypeBinding();
}
throw new NonEclipseImplementationException("only applicable to eclipse type system objects." + //$NON-NLS-1$
" Found " + type.getClass().getName()); //$NON-NLS-1$
}
}