Package com.redhat.ceylon.compiler.loader.impl.reflect.mirror

Source Code of com.redhat.ceylon.compiler.loader.impl.reflect.mirror.ReflectionType

/*
* Copyright Red Hat Inc. and/or its affiliates and other contributors
* as indicated by the authors tag. All rights reserved.
*
* This copyrighted material is made available to anyone wishing to use,
* modify, copy, or redistribute it subject to the terms and conditions
* of the GNU General Public License version 2.
*
* This particular file is subject to the "Classpath" exception as provided in the
* LICENSE file that accompanied this code.
*
* This program is distributed in the hope that it will be useful, but WITHOUT A
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
* PARTICULAR PURPOSE.  See the GNU General Public License for more details.
* You should have received a copy of the GNU General Public License,
* along with this distribution; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA  02110-1301, USA.
*/

package com.redhat.ceylon.compiler.loader.impl.reflect.mirror;

import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import javax.lang.model.type.TypeKind;

import com.redhat.ceylon.compiler.java.codegen.Naming;
import com.redhat.ceylon.compiler.java.loader.mirror.JavacClass;
import com.redhat.ceylon.compiler.java.loader.mirror.JavacTypeParameter;
import com.redhat.ceylon.compiler.java.util.Util;
import com.redhat.ceylon.compiler.loader.mirror.ClassMirror;
import com.redhat.ceylon.compiler.loader.mirror.TypeMirror;
import com.redhat.ceylon.compiler.loader.mirror.TypeParameterMirror;
import com.sun.tools.javac.code.Symbol.ClassSymbol;

public class ReflectionType implements TypeMirror {

    private Type type;
    private List<TypeMirror> typeArguments;
    private ReflectionType componentType;
    private ReflectionType upperBound;
    private ReflectionType lowerBound;
    private boolean lowerBoundSet;
    private boolean upperBoundSet;
    private ReflectionClass declaredClass;
    private boolean declaredClassSet;
    private boolean typeParameterSet;
    private ReflectionTypeParameter typeParameter;

    public ReflectionType(Type type) {
        this.type = type;
    }

    @Override
    public String getQualifiedName() {
        if(type instanceof ParameterizedType){
            return ((Class<?>)((ParameterizedType)type).getRawType()).getName();
        }
        if(type instanceof TypeVariable)
            return ((TypeVariable<?>)type).getName();
        Class<?> klass = (Class<?>)type;
        return klass.getName();
    }
   
    private String unquote(String s) {
        s = Naming.stripLeadingDollar(s);
        if (Util.isInitialLowerCase(s) && s.charAt(s.length()-1) == '_') {
            return s.substring(0, s.length()-1);
        }
        return s;
    }
   
    private String unquoteLastPart(String s) {
        int index = s.lastIndexOf('.');
        if (index != -1) {
            return s.substring(0, index) + '.' + unquote(s.substring(index+1));
        }
        return s;
    }

    @Override
    public List<TypeMirror> getTypeArguments() {
        if(typeArguments != null)
            return typeArguments;
        if(type instanceof ParameterizedType){
            Type[] javaTypeArguments = ((ParameterizedType)type).getActualTypeArguments();
            typeArguments = new ArrayList<TypeMirror>(javaTypeArguments.length);
            for(Type typeArgument : javaTypeArguments)
                typeArguments.add(new ReflectionType(typeArgument));
            return typeArguments;
        }else
            typeArguments = Collections.<TypeMirror>emptyList();
        return typeArguments;
    }

    private static final Map<Class<?>, TypeKind> primitives = new HashMap<Class<?>, TypeKind>();
    static{
        primitives.put(Boolean.TYPE, TypeKind.BOOLEAN);
        primitives.put(Byte.TYPE, TypeKind.BYTE);
        primitives.put(Character.TYPE, TypeKind.CHAR);
        primitives.put(Short.TYPE, TypeKind.SHORT);
        primitives.put(Integer.TYPE, TypeKind.INT);
        primitives.put(Long.TYPE, TypeKind.LONG);
        primitives.put(Float.TYPE, TypeKind.FLOAT);
        primitives.put(Double.TYPE, TypeKind.DOUBLE);
        primitives.put(Void.TYPE, TypeKind.VOID);
    }
   
    @Override
    public TypeKind getKind() {
        if(type instanceof ParameterizedType)
            return TypeKind.DECLARED;
        if(type instanceof GenericArrayType)
            return TypeKind.ARRAY;
        if(type instanceof TypeVariable)
            return TypeKind.TYPEVAR;
        if(type instanceof WildcardType)
            return TypeKind.WILDCARD;
        if(type instanceof Class){
            TypeKind kind = primitives.get(type);
            if(kind != null)
                return kind;
            return ((Class<?>)type).isArray() ? TypeKind.ARRAY : TypeKind.DECLARED;
        }
        throw new RuntimeException("Unknown type: "+type);
    }

    @Override
    public TypeMirror getComponentType() {
        if(componentType != null)
            return componentType;
        Type ct;
        if(type instanceof Class)
            ct = ((Class<?>)type).getComponentType();
        else
            ct = ((GenericArrayType)type).getGenericComponentType();
        componentType = new ReflectionType(ct);
        return componentType;
    }

    @Override
    public boolean isPrimitive() {
        return primitives.containsKey(type);
    }

    @Override
    public String toString() {
        return "[ReflectionType: "+type.toString()+"]";
    }

    @Override
    public TypeMirror getUpperBound() {
        if(upperBoundSet)
            return upperBound;
        if(type instanceof WildcardType){
            // so the JavaDoc for WildcardType says that the upper bound can still be set to Object
            // even if we have a lower bound set. In order to detect this, we check the lower bound.
            // if there is no lower bound we will get null so all works out
            if(getLowerBound() == null){
                Type[] ct = ((WildcardType)type).getUpperBounds();
                // I don't see how there can possibly be more than one bound here according to the spec and grammar, for a wildcard type
                if(ct.length != 1)
                    throw new RuntimeException("Not one upper bound in wildcard type: "+ct.length);
                upperBound = new ReflectionType(ct[0]);
            }else
                upperBound = null;
        }
        upperBoundSet = true;
        return upperBound;
    }

    @Override
    public TypeMirror getLowerBound() {
        if(lowerBoundSet)
            return lowerBound;
        Type[] ct = ((WildcardType)type).getLowerBounds();
        if(ct.length == 0)
            return null;
        // I don't see how there can possibly be more than one bound here according to the spec and grammar, for a wildcard type
        if(ct.length > 1)
            throw new RuntimeException("More than one lower bound in wildcard type: "+ct.length);
        lowerBound = new ReflectionType(ct[0]);
        lowerBoundSet = true;
        return lowerBound;
    }

    @Override
    public boolean isRaw() {
        if(type instanceof ParameterizedType){
            // we're raw if our type is a parameterised type that should have type params
            ParameterizedType ptype = ((ParameterizedType)type);
            Class<?> klass = (Class<?>) ptype.getRawType();
            return klass.getTypeParameters().length != ptype.getActualTypeArguments().length;
        }
        if(type instanceof GenericArrayType)
            return getComponentType().isRaw();
        if(type instanceof TypeVariable)
            return false;
        if(type instanceof WildcardType)
            return false;
        if(type instanceof Class){
            // we're raw if our type is a parameterised type that should have type params
            return ((Class<?>)type).getTypeParameters().length != 0;
        }
        throw new RuntimeException("Unknown type: "+type);
    }

    @Override
    public ClassMirror getDeclaredClass() {
        if(!declaredClassSet){
            if(type instanceof Class){
                declaredClass = new ReflectionClass((Class<?>) type);
            }else if(type instanceof ParameterizedType){
                declaredClass = new ReflectionClass((Class<?>) ((ParameterizedType) type).getRawType());
            }
            declaredClassSet = true;
        }
        return declaredClass;
    }

    @Override
    public TypeParameterMirror getTypeParameter() {
        if(getKind() != TypeKind.TYPEVAR)
            return null;
        if(!typeParameterSet){
            typeParameter = new ReflectionTypeParameter(type);
            typeParameterSet = true;
        }
        return typeParameter;
    }
}
TOP

Related Classes of com.redhat.ceylon.compiler.loader.impl.reflect.mirror.ReflectionType

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.