/**
* Copyright (C) 2006-2017 INRIA and contributors
* Spoon - http://spoon.gforge.inria.fr/
*
* This software is governed by the CeCILL-C License under French law and
* abiding by the rules of distribution of free software. You can use, modify
* and/or redistribute the software under the terms of the CeCILL-C license as
* circulated by CEA, CNRS and INRIA at http://www.cecill.info.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
*
* The fact that you are presently reading this means that you have had
* knowledge of the CeCILL-C license and that you accept its terms.
*/
package spoon.support.reflect.declaration;
import spoon.reflect.declaration.CtField;
import spoon.reflect.declaration.CtFormalTypeDeclarer;
import spoon.reflect.declaration.CtMethod;
import spoon.reflect.declaration.CtModifiable;
import spoon.reflect.declaration.CtPackage;
import spoon.reflect.declaration.CtType;
import spoon.reflect.declaration.CtTypeParameter;
import spoon.reflect.declaration.ModifierKind;
import spoon.reflect.declaration.ParentNotInitializedException;
import spoon.reflect.reference.CtExecutableReference;
import spoon.reflect.reference.CtFieldReference;
import spoon.reflect.reference.CtTypeParameterReference;
import spoon.reflect.reference.CtTypeReference;
import spoon.reflect.visitor.CtVisitor;
import spoon.support.DerivedProperty;
import spoon.support.UnsettableProperty;
import spoon.support.visitor.GenericTypeAdapter;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
public class CtTypeParameterImpl extends CtTypeImpl<Object> implements CtTypeParameter {
CtTypeReference<?> superClass;
@Override
public void accept(CtVisitor visitor) {
visitor.visitCtTypeParameter(this);
}
@Override
public CtTypeReference<?> getSuperclass() {
return superClass;
}
@Override
public <C extends CtType<Object>> C setSuperclass(CtTypeReference<?> superClass) {
if (superClass != null) {
superClass.setParent(this);
}
this.superClass = superClass;
return (C) this;
}
@Override
public String getQualifiedName() {
return simpleName;
}
@Override
public CtTypeParameterReference getReference() {
return getFactory().Type().createReference(this);
}
@Override
public boolean isGenerics() {
return true;
}
@Override
public CtTypeParameter clone() {
return (CtTypeParameter) super.clone();
}
@Override
public CtFormalTypeDeclarer getTypeParameterDeclarer() {
try {
return getParent(CtFormalTypeDeclarer.class);
} catch (ParentNotInitializedException e) {
return null;
}
}
@Override
@UnsettableProperty
public <F, C extends CtType<Object>> C addFieldAtTop(CtField<F> field) {
// unsettable property
return (C) this;
}
@Override
@UnsettableProperty
public <F, C extends CtType<Object>> C addField(CtField<F> field) {
// unsettable property
return (C) this;
}
@Override
@UnsettableProperty
public <F, C extends CtType<Object>> C addField(int index, CtField<F> field) {
// unsettable property
return (C) this;
}
@Override
@UnsettableProperty
public <C extends CtType<Object>> C setFields(List<CtField<?>> fields) {
// unsettable property
return (C) this;
}
@Override
@DerivedProperty
public <F> boolean removeField(CtField<F> field) {
// unsettable property
return false;
}
@Override
public CtField<?> getField(String name) {
return null;
}
@Override
public List<CtField<?>> getFields() {
return Collections.emptyList();
}
@Override
@UnsettableProperty
public <N, C extends CtType<Object>> C addNestedType(CtType<N> nestedType) {
// unsettable property
return (C) this;
}
@Override
@UnsettableProperty
public <N> boolean removeNestedType(CtType<N> nestedType) {
// unsettable property
return false;
}
@Override
@UnsettableProperty
public <C extends CtType<Object>> C setNestedTypes(Set<CtType<?>> nestedTypes) {
// unsettable property
return (C) this;
}
@Override
public <N extends CtType<?>> N getNestedType(String name) {
return null;
}
@Override
public Set<CtType<?>> getNestedTypes() {
return Collections.emptySet();
}
@Override
public CtPackage getPackage() {
return null;
}
@Override
public boolean isTopLevel() {
return false;
}
@Override
public Set<ModifierKind> getModifiers() {
return Collections.emptySet();
}
@Override
public boolean hasModifier(ModifierKind modifier) {
return false;
}
@Override
@UnsettableProperty
public <C extends CtModifiable> C setModifiers(Set<ModifierKind> modifiers) {
// unsettable property
return (C) this;
}
@Override
@UnsettableProperty
public <C extends CtModifiable> C addModifier(ModifierKind modifier) {
// unsettable property
return (C) this;
}
@Override
@UnsettableProperty
public boolean removeModifier(ModifierKind modifier) {
// unsettable property
return true;
}
@Override
@UnsettableProperty
public <C extends CtModifiable> C setVisibility(ModifierKind visibility) {
// unsettable property
return (C) this;
}
@Override
public ModifierKind getVisibility() {
return null;
}
@Override
public boolean isPrimitive() {
return false;
}
@Override
public boolean isAnonymous() {
return false;
}
@Override
public boolean isLocalType() {
return false;
}
@Override
public List<CtFieldReference<?>> getAllFields() {
return Collections.emptyList();
}
@Override
public List<CtFieldReference<?>> getDeclaredFields() {
return Collections.emptyList();
}
@Override
public boolean isSubtypeOf(CtTypeReference<?> superTypeRef) {
if (superTypeRef instanceof CtTypeParameterReference) {
//the type is type parameter too. Use appropriate sub type checking algorithm
CtTypeParameter superTypeParam = (CtTypeParameter) superTypeRef.getDeclaration();
return isSubtypeOf(getFactory().Type().createTypeAdapter(getTypeParameterDeclarer()), this, superTypeParam);
}
//type is normal type
return getTypeErasure().isSubtypeOf(superTypeRef);
}
private static boolean isSubtypeOf(GenericTypeAdapter typeAdapter, CtTypeParameter subTypeParam, CtTypeParameter superTypeParam) {
while (subTypeParam != null) {
if (isSameInSameScope(subTypeParam, typeAdapter.adaptType(superTypeParam))) {
//both type params are same
return true;
}
CtTypeReference<?> superTypeOfSubTypeParam = subTypeParam.getSuperclass();
if (superTypeOfSubTypeParam == null) {
//there is no super type defined, so they are different type parameters
return false;
}
if (superTypeOfSubTypeParam instanceof CtTypeParameterReference) {
subTypeParam = ((CtTypeParameterReference) superTypeOfSubTypeParam).getDeclaration();
} else {
//the super type is not type parameter. Normal type cannot be a super type of generic parameter
return false;
}
}
return false;
}
/**
* Note: This method expects that both arguments are already adapted to the same scope
* @param typeParam a type param 1
* @param typeRef a reference to some type 2
* @return true if typeParam and typeRef represents same type parameter.
*/
private static boolean isSameInSameScope(CtTypeParameter typeParam, CtTypeReference<?> typeRef) {
if (typeRef instanceof CtTypeParameterReference) {
return typeParam.getSimpleName().equals(((CtTypeParameterReference) typeRef).getSimpleName());
}
return false;
}
@Override
public CtTypeReference<?> getTypeErasure() {
CtTypeReference<?> boundType = getBound(this);
return boundType.getTypeErasure();
}
private static CtTypeReference<?> getBound(CtTypeParameter typeParam) {
CtTypeReference<?> bound = typeParam.getSuperclass();
if (bound == null) {
bound = typeParam.getFactory().Type().OBJECT;
}
return bound;
}
@Override
@UnsettableProperty
public <M, C extends CtType<Object>> C addMethod(CtMethod<M> method) {
// unsettable property
return (C) this;
}
@Override
@UnsettableProperty
public <M> boolean removeMethod(CtMethod<M> method) {
// unsettable property
return false;
}
@Override
@UnsettableProperty
public <S, C extends CtType<Object>> C addSuperInterface(CtTypeReference<S> interfac) {
// unsettable property
return (C) this;
}
@Override
@UnsettableProperty
public <S> boolean removeSuperInterface(CtTypeReference<S> interfac) {
// unsettable property
return false;
}
@Override
public <R> CtMethod<R> getMethod(CtTypeReference<R> returnType, String name, CtTypeReference<?>... parameterTypes) {
return null;
}
@Override
public <R> CtMethod<R> getMethod(String name, CtTypeReference<?>... parameterTypes) {
return null;
}
@Override
public Set<CtMethod<?>> getMethods() {
return Collections.emptySet();
}
@Override
public Set<CtMethod<?>> getMethodsAnnotatedWith(CtTypeReference<?>... annotationTypes) {
return Collections.emptySet();
}
@Override
public List<CtMethod<?>> getMethodsByName(String name) {
return Collections.emptyList();
}
@Override
public Set<CtTypeReference<?>> getSuperInterfaces() {
return Collections.emptySet();
}
@Override
@UnsettableProperty
public <C extends CtType<Object>> C setMethods(Set<CtMethod<?>> methods) {
// unsettable property
return (C) this;
}
@Override
@UnsettableProperty
public <C extends CtType<Object>> C setSuperInterfaces(Set<CtTypeReference<?>> interfaces) {
// unsettable property
return (C) this;
}
@Override
public Collection<CtExecutableReference<?>> getDeclaredExecutables() {
return Collections.emptyList();
}
@Override
public Collection<CtExecutableReference<?>> getAllExecutables() {
return Collections.emptyList();
}
@Override
public Set<CtMethod<?>> getAllMethods() {
return Collections.emptySet();
}
}