/*
* 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.java.loader.mirror;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.lang.model.type.TypeKind;
import com.redhat.ceylon.model.loader.mirror.ClassMirror;
import com.redhat.ceylon.model.loader.mirror.TypeMirror;
import com.redhat.ceylon.model.loader.mirror.TypeParameterMirror;
import com.sun.tools.javac.code.Symbol.ClassSymbol;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.code.Type.ArrayType;
import com.sun.tools.javac.code.Type.TypeVar;
import com.sun.tools.javac.code.Type.WildcardType;
public class JavacType implements TypeMirror {
private Type type;
private List<TypeMirror> typeArguments;
private boolean componentTypeSet;
private TypeMirror componentType;
private boolean upperBoundSet;
private JavacType upperBound;
private boolean lowerBoundSet;
private JavacType lowerBound;
private JavacClass declaredClass;
private boolean declaredClassSet;
private TypeParameterMirror typeParameter;
private boolean typeParameterSet;
private JavacType qualifyingType;
public JavacType(Type type) {
this.type = type;
}
public String toString() {
return getClass().getSimpleName() + " of " + type;
}
@Override
public String getQualifiedName() {
return type.tsym.getQualifiedName().toString();
}
@Override
public List<TypeMirror> getTypeArguments() {
if (typeArguments == null) {
List<TypeMirror> args = new ArrayList<TypeMirror>(type.getTypeArguments().size());
for(Type typeArg : type.getTypeArguments()){
args.add(new JavacType(typeArg));
}
typeArguments = Collections.unmodifiableList(args);
}
return typeArguments;
}
@Override
public TypeKind getKind() {
return type.getKind();
}
@Override
public TypeMirror getComponentType() {
if (!componentTypeSet
&& type instanceof ArrayType) {
Type compType = ((ArrayType)type).getComponentType();
if (compType != null) {
componentType = new JavacType(compType);
}
componentTypeSet = true;
}
return componentType;
}
@Override
public boolean isPrimitive() {
return type.isPrimitive();
}
@Override
public TypeMirror getUpperBound() {
if (!upperBoundSet){
if(type instanceof WildcardType) {
Type bound = ((WildcardType)type).getExtendsBound();
if (bound != null) {
upperBound = new JavacType(bound);
}
}else if(type instanceof TypeVar){
Type bound = ((TypeVar)type).getUpperBound();
// FIXME: the javadoc says that this can be a fake compound class whose real union bounds
// are in its implemented interfaces
if (bound != null) {
upperBound = new JavacType(bound);
}
}
upperBoundSet = true;
}
return upperBound;
}
@Override
public TypeMirror getLowerBound() {
if (!lowerBoundSet
&& type instanceof WildcardType) {
Type bound = ((WildcardType)type).getSuperBound();
if (bound != null) {
lowerBound = new JavacType(bound);
}
lowerBoundSet = true;
}
return lowerBound;
}
@Override
public boolean isRaw() {
return type.isRaw();
}
@Override
public ClassMirror getDeclaredClass(){
if(!declaredClassSet){
if(type.tsym instanceof ClassSymbol){
declaredClass = new JavacClass((ClassSymbol) type.tsym);
}
declaredClassSet = true;
}
return declaredClass;
}
@Override
public TypeParameterMirror getTypeParameter() {
if(getKind() != TypeKind.TYPEVAR)
return null;
if(!typeParameterSet){
typeParameter = new JavacTypeParameter(type.tsym);
typeParameterSet = true;
}
return typeParameter;
}
@Override
public TypeMirror getQualifyingType() {
if(qualifyingType == null){
Type enclosingType = type.getEnclosingType();
if(enclosingType != null && enclosingType instanceof Type.ClassType){
qualifyingType = new JavacType(enclosingType);
}
}
return qualifyingType;
}
}