GetterMethod.java
package com.mackenziehigh.autumn.lang.compiler.utils;
import com.google.common.base.Preconditions;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IDeclaredType;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IMethod;
import com.mackenziehigh.autumn.lang.compiler.typesystem.design.IVariableType;
/**
* An instance of this class represents a bytecode getter method.
*
* @author Mackenzie High
*/
public final class GetterMethod
{
/**
* This is the type that declares the getter.
*/
public final IDeclaredType owner;
/**
* This is the type of value that the getter returns.
*/
public final IVariableType returns;
/**
* This is the name of the element that the getter gets.
*/
public final String name;
/**
* Sole Constructor.
*
* @param owner is the type that declares the getter.
* @param returns is the return-type of the getter.
* @param name is the name of the getter.
*/
public GetterMethod(final IDeclaredType owner,
final IVariableType returns,
final String name)
{
Preconditions.checkNotNull(owner);
Preconditions.checkNotNull(returns);
Preconditions.checkNotNull(name);
this.owner = owner;
this.returns = returns;
this.name = name;
}
/**
* {@inheritDoc}
*/
@Override
public int hashCode()
{
int hash = 3;
hash = 97 * hash + (this.owner != null ? this.owner.hashCode() : 0);
hash = 97 * hash + (this.returns != null ? this.returns.hashCode() : 0);
hash = 97 * hash + (this.name != null ? this.name.hashCode() : 0);
return hash;
}
/**
* {@inheritDoc}
*/
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (getClass() != obj.getClass())
{
return false;
}
final GetterMethod other = (GetterMethod) obj;
if (this.owner != other.owner && (this.owner == null || !this.owner.equals(other.owner)))
{
return false;
}
if (this.returns != other.returns && (this.returns == null || !this.returns.equals(other.returns)))
{
return false;
}
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name))
{
return false;
}
return true;
}
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
return "getter " + Utils.simpleName(owner) + "." + name + "() : " + Utils.simpleName(returns);
}
/**
* This method determines whether this getter method is declared in its owner.
*
* @return true, iff the owner currently directly declares this getter method.
*/
public boolean isDeclared()
{
for (IMethod method : owner.getMethods())
{
/**
* If the name is different, continue.
*/
if (method.getName().equals(name) == false)
{
continue;
}
/**
* If the number of parameters is different, continue.
*/
if (method.getParameters().isEmpty() == false)
{
continue;
}
/**
* If the return-type is different, continue.
*/
if (method.getReturnType().equals(returns) == false)
{
continue;
}
/**
* Since the owner, name, parameter-list, and return-type match,
* we have found a method declaration that describes the getter method.
*/
return true;
}
/**
* None of the method declarations in the owner describe the getter method.
*/
return false;
}
/**
* This method retrieves the type-system representation of this method.
*
* @return the member of the owner-type that represents this getter method.
*/
public IMethod findSelf()
{
IMethod result = null;
for (IMethod method : owner.getMethods())
{
final boolean match1 = method.getName().equals(name);
final boolean match2 = method.getReturnType().equals(returns);
final boolean match3 = method.getParameters().isEmpty();
if (match1 && match2 && match3)
{
result = method;
break;
}
}
/**
* This method should only be invoked, when the result is known to exist.
*/
assert result != null;
return result;
}
/**
* If this getter is a bridge-method, this method determines which getter to invoke.
*
* @return getter method that this getter method invokes at runtime.
*/
public IMethod findBridgeTarget()
{
IMethod result = null;
final IMethod self = this.findSelf();
for (IMethod method : owner.getMethods())
{
if (method == self)
{
continue;
}
final boolean match1 = method.getName().equals(name);
final boolean match2 = method.getParameters().isEmpty();
final boolean matches = match1 && match2;
if (matches && result == null)
{
result = method;
continue;
}
if (matches == false || result == null)
{
continue;
}
final boolean subtype = method.getReturnType().isSubtypeOf(result.getReturnType());
final boolean equals = method.getReturnType().equals(result.getReturnType());
final boolean proper_subtype = subtype && !equals;
/**
* If the method is more specific than the previous result, use the new result.
*/
if (proper_subtype)
{
result = method;
}
}
/**
* This method should only be invoked, when the result is known to exist.
*/
assert result != null;
return result;
}
}