AbstractDeclaredType.java
package com.mackenziehigh.autumn.lang.compiler.typesystem;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IAnnotationMethod;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IClassType;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IDeclaredType;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IEnumConstant;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IField;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IInterfaceType;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IMethod;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IType;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.ITypeFactory;
import com.mackenziehigh.autumn.resources.Finished;
import java.lang.reflect.Modifier;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
/**
* This class provides a partial implementation of the IDeclaredType interface.
*
* @author Mackenzie High
*/
@Finished("2014/07/12")
public abstract class AbstractDeclaredType
extends AbstractType
implements IDeclaredType
{
/**
* Sole Constructor.
*
* @param factory type-factory that is used to access types.
* @param descriptor is the type-descriptor of the new type.
*/
public AbstractDeclaredType(final ITypeFactory factory,
final String descriptor)
{
super(factory, descriptor);
Preconditions.checkNotNull(factory);
Preconditions.checkNotNull(descriptor);
}
/**
* {@inheritDoc}
*/
@Override
public String getNamespace()
{
final String full_name = getDescriptor();
final int last_slash = full_name.lastIndexOf('/');
final String no_slashes = full_name.replace('/', '.');
final String result = no_slashes.substring(1, last_slash);
return result;
}
/**
* {@inheritDoc}
*/
@Override
public List<IClassType> getAllSuperclasses()
{
final List<IClassType> result = Lists.newLinkedList();
IClassType p = this.getSuperclass();
if (this.getDescriptor().equals("Ljava/lang/Object;"))
{
result.add((IClassType) getTypeFactory().fromClass(Object.class));
}
else
{
result.add(this.getSuperclass());
result.addAll(this.getSuperclass().getAllSuperclasses());
}
return ImmutableList.copyOf(result);
}
/**
* {@inheritDoc}
*/
@Override
public Collection<IInterfaceType> getAllSuperinterfaces()
{
final Set<IInterfaceType> result = Sets.newHashSet();
final Set<IDeclaredType> visited = Sets.newHashSet();
findSuperinterfaces(result, visited, this);
return ImmutableSet.copyOf(result);
}
private void findSuperinterfaces(final Set<IInterfaceType> output,
final Set<IDeclaredType> visited,
final IDeclaredType target)
{
if (visited.contains(target))
{
return;
}
else
{
visited.add(target);
}
output.addAll(target.getSuperinterfaces());
findSuperinterfaces(output, visited, target.getSuperclass());
for (IInterfaceType direct_superinterface : target.getSuperinterfaces())
{
findSuperinterfaces(output, visited, direct_superinterface);
}
}
/**
* {@inheritDoc}
*/
@Override
public Collection<IMethod> getAllVisibleMethods()
{
final List<IDeclaredType> supertypes = Lists.newLinkedList();
supertypes.addAll(this.getAllSuperclasses());
supertypes.addAll(this.getAllSuperinterfaces());
final Set<IMethod> result = Sets.newHashSet();
result.addAll(this.getMethods());
for (IDeclaredType supertype : supertypes)
{
for (IMethod method : supertype.getMethods())
{
final int modifiers = method.getModifiers();
if (!Modifier.isStatic(modifiers) && !Modifier.isPrivate(modifiers))
{
result.add(method);
}
}
}
return Collections.unmodifiableCollection(result);
}
/**
* {@inheritDoc}
*/
@Override
public boolean isSubtypeOf(final IType target)
{
Preconditions.checkNotNull(target);
if (this.equals(target))
{
return true; // Because, target is this.
}
else if (this.getAllSuperclasses().contains(target))
{
return true; // Because, target is a superclass of this.
}
else if (this.getAllSuperinterfaces().contains(target))
{
return true; // Because, target is a superinterfaces of this.
}
else
{
return false;
}
}
/**
* {@inheritDoc}
*/
public Collection<IAnnotationMethod> getAnnotationMethods()
{
final List<IAnnotationMethod> result = Lists.newLinkedList();
for (IMethod method : this.getMethods())
{
if (method.isAnnotationMethod())
{
result.add((IAnnotationMethod) method);
}
}
return ImmutableList.copyOf(result);
}
/**
* {@inheritDoc}
*/
public Collection<IEnumConstant> getEnumConstants()
{
final List<IEnumConstant> result = Lists.newLinkedList();
for (IField field : this.getFields())
{
if (field.isEnumConstant())
{
result.add((IEnumConstant) field);
}
}
return ImmutableList.copyOf(result);
}
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
return getDescriptor();
}
/**
* {@inheritDoc}
*/
@Override
public boolean isNullType()
{
return false;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isVoidType()
{
return false;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isPrimitiveType()
{
return false;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isReferenceType()
{
return true;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isArrayType()
{
return false;
}
/**
* {@inheritDoc}
*/
@Override
public boolean isDeclaredType()
{
return true;
}
}