slcom/slangc/model/UserTypeModel.sauce

890 lines
27 KiB
Plaintext
Raw Permalink Normal View History

package slangc.model;
import slangc.api.Reporter;
import slangc.bytecode.TypeSignature;
import slangc.parser.Branch;
import slangc.parser.Node;
import slangc.parser.NodeType;
import slangc.parser.Token;
public class UserTypeModel extends TypeModel {
SourceModel sourceFile;
Branch parsed;
TypeModel baseClass;
TypeModel[] interfaces;
/** This is only assigned by a subclass of StatementOrExpression which defines a type,
* specifically in the case of a new-class expression or an inner class declaration
* in a block/switch scope, and is used for looking up variables in the outer lexical
* scope (this happens separately from type lookup).
*/
public StatementOrExpression statementOrExpression;
private TemplateModel templateModel = null;
boolean isTemplateCopy = false;
//TemplateArguments directTemplateArguments = null;
UserTypeModel templateOuter = null;
UserTypeModel templateOriginal = null;
InnerTypeSet innerTypeMembers = null;
FieldSet fieldMembers = null;
MethodSet methodMembers = null;
public UserTypeModel(PackageModel packageModel, String name, SourceModel source, Branch parsed, TypeLevel level, InnerTypeScope owner) {
super(packageModel, name, level, owner);
this.sourceFile = source;
this.parsed = parsed;
}
public void setupTranslations() {
for (int i = 0; i < getAttributes().countTranslations(); i++) {
AttributeSet.Translation tr = getAttributes().getTranslation(i);
AliasTypeModel a = getPackage().getSystem().addAliasType(getPackage().getName(), getStartOfName() + tr.name, getPackage().getName(), getOuterName());
a.simplify();
}
}
@Override
public boolean matchesName(String name) {
return super.matchesName(name) || getAttributes().matchesTranslation(null, name);
}
private UserTypeModel(UserTypeModel original, TemplateArguments targs) {
super(original.pkg, original.getSpecialisedInnerName(targs), original.level, original.owner);
sourceFile = original.sourceFile;
parsed = original.parsed;
templateModel = original.templateModel.specialised(this, targs);
while (templateModel.expand() != 0) {}
isTemplateCopy = true;
templateOriginal = original;
templateOuter = this;
String[] names = original.getInnerTypeNames();
for(int i = 0; i < names.length; i++) {
TypeModel m = original.getInnerType(names[i]);
if (m instanceof UserTypeModel) {
((UserTypeModel)m).replicateForTemplateInstance(this, this);
}
}
//directTemplateArguments = targs;
}
@Override
public boolean isReferenceOnly() {
if (isTemplateCopy) {
// Always include template instances (even if the template is defined in referenced code)
return false;
} else if (getTypeLevel() == TypeLevel.OUTER) {
return !getSource().isIncluded();
} else {
return getOwner().getNearestType().isReferenceOnly();
}
}
/**
* Returns true if the type would exist at runtime and false otherwise (i.e. checks that it isn't just template that exists at compile time, but may be an *instance* of a template)
*/
@Override
public boolean existsAtRuntime() {
boolean might = false;
switch (getTypeType()) {
case TypeType.CLASS_TEMPLATE:
case TypeType.INTERFACE_TEMPLATE:
might = templateOuter == this; // A template type only exists if it's been instantiated, meaning it's templateOuter would point to itself
break;
default:
might = true;
}
//System.out.println("AAA");
if (might && getTypeLevel() == TypeLevel.OUTER) {
//System.out.println("AAAB");
return true;
} else if (might) {
//System.out.println("AAAC");
return getOwner().getNearestType().existsAtRuntime();
} else {
//System.out.println("AAAD");
return false;
}
}
private UserTypeModel(UserTypeModel original, UserTypeModel template, UserTypeModel outer) {
super(original.pkg, original.getInnerName(), original.level, outer);
sourceFile = original.sourceFile;
parsed = original.parsed;
templateModel = original.templateModel;
while (templateModel != null && templateModel.expand() != 0) {}
isTemplateCopy = true;
templateOriginal = original;
templateOuter = outer;
String[] names = original.getInnerTypeNames();
for(int i = 0; i < names.length; i++) {
TypeModel m = original.getInnerType(names[i]);
if (m instanceof UserTypeModel) {
((UserTypeModel)m).replicateForTemplateInstance(template, this);
}
}
}
private UserTypeModel replicateForTemplateInstance(UserTypeModel template, UserTypeModel outer) {
UserTypeModel t = new UserTypeModel(this, template, outer);
getPackage().addInstantiatedType(t);
return t;
}
public String getSpecialisedInnerName(TemplateArguments targs) {
return getInnerBaseName() + targs.toString();
}
public String getSpecialisedOuterName(TemplateArguments targs) {
return getOuterBaseName() + targs.toString();
}
@Override
public TypeModel getOrCreateTemplateInstance(TemplateArguments targs) {
if (getPackage().hasType(getSpecialisedOuterName(targs))) {
return getPackage().getType(getSpecialisedOuterName(targs));
}
UserTypeModel t = new UserTypeModel(this, targs);
getPackage().addInstantiatedType(t);
return t;
// TODO Auto-generated method stub
//return super.getOrCreateTemplateInstance(targs);
}
public SourceModel getSource() {
return sourceFile;
}
public Branch getParsed() {
return parsed;
}
@Override
public boolean isSynthetic() {
return false;
}
@Override
public TypeType getTypeType() {
switch(getParsed().getNodeType()) {
case NodeType.CLASS_DECLARATION:
if (getParsed().getSubnode(3).getNodeType() == NodeType.GENERIC_DECLARATIONS) {
return TypeType.CLASS_TEMPLATE;
} else {
return TypeType.CLASS;
}
case NodeType.NEW_CLASS_EXPRESSION:
return TypeType.CLASS;
case NodeType.INTERFACE_DECLARATION:
if (getParsed().getSubnode(3).getNodeType() == NodeType.GENERIC_DECLARATIONS) {
return TypeType.INTERFACE_TEMPLATE;
} else {
return TypeType.INTERFACE;
}
case NodeType.ATTRIBUTE_DECLARATION:
return TypeType.ATTRIBUTE;
case NodeType.ENUM_DECLARATION:
return TypeType.ENUM;
//case NodeType.ATTRIBUTE_DECLARATION:
// return TypeType.ATTRIBUTE;
default:
throw new Error("Internal error/TODO: Unrecognised node type in TypeModel: " + getParsed().getNodeType());
}
}
@Override
public int countInterfaces() {
if (interfaces == null) {
return 0;
} else {
return interfaces.length;
}
}
@Override
public TypeModel getInterface(int n) {
return interfaces[n];
}
@Override
public int countFieldMembers() {
if (fieldMembers == null) {
return 0;
} else {
return fieldMembers.countMembers();
}
}
@Override
public FieldModel getFieldMember(int n) {
return fieldMembers.getMember(n);
}
@Override
public int countMethodMembers() {
if (methodMembers == null) {
return 0;
} else {
return methodMembers.countMembers();
}
}
@Override
public MethodModel getMethodMember(int n) {
return methodMembers.getMember(n);
}
@Override
public int expand() {
switch (getTypeType()) {
case TypeType.CLASS_TEMPLATE:
case TypeType.INTERFACE_TEMPLATE:
if (templateModel == null) {
templateModel = new TemplateModel(this, getParsed().getSubnode(3));
return 1;
} else {
return templateModel.expand();
}
default:
}
// TODO Auto-generated method stub
return 0;
}
public TypeModel getBaseClass() {
return baseClass;
}
public TypeModel resolveBaseClass() {
if (getParsed().getNodeType() == NodeType.NEW_CLASS_EXPRESSION) {
TypeModel t = resolveTypeReference(getParsed().getSubnode(1));
/* We need to do a bit of a fixup if it references an interface instead of a base class. */
if (t != null && (t.getTypeType() == TypeType.INTERFACE || t.getTypeType() == TypeType.INTERFACE_TEMPLATE)) {
/* In this case we assign the default base class, but we also initialise the interfaces here. */
interfaces = new TypeModel[] { t };
return getPackage().getSystem().getDefaultBaseType();
} else {
return t;
}
} else if (getTypeType() == TypeType.ENUM || getTypeType() == TypeType.CLASS || getTypeType() == TypeType.CLASS_TEMPLATE) {
Node baseNode = getParsed().getSubnode(4);
if (baseNode.getNodeType() == NodeType.NO_CLASS_BASE) {
if (getTypeType() == TypeType.ENUM) {
return getPackage().getSystem().getDefaultEnumBaseType();
} else {
return defaultBaseClass();
}
} else if (baseNode.getNodeType() == NodeType.CLASS_BASE) {
//return resolveTypeReference(baseNode);
return resolveTypeReference(((Branch)baseNode).getSubnode(1));
} else {
throw new Error("Internal error/TODO: Unrecognised base class node " + baseNode.getNodeType());
}
} else {
return defaultBaseClass();
}
}
public TypeModel defaultBaseClass() {
TypeModel def = getPackage().getSystem().getDefaultBaseType();
if (def == this) {
return null; // Avoid adding the base type as it's own base type!
} else {
return def;
}
}
public TypeModel[] resolveInterfaces() {
if (getParsed().getNodeType() == NodeType.NEW_CLASS_EXPRESSION) {
return new TypeModel[0];
} else if (getTypeType() == TypeType.CLASS || getTypeType() == TypeType.CLASS_TEMPLATE) {
Node baseNode = getParsed().getSubnode(5);
if (baseNode.getNodeType() == NodeType.NO_CLASS_IMPLEMENTS) {
return new TypeModel[0];
} else {
return resolveClassReferences(getParsed().getSubnode(5));
}
} else if (getTypeType() == TypeType.INTERFACE || getTypeType() == TypeType.INTERFACE_TEMPLATE) {
Node baseNode = getParsed().getSubnode(4);
if (baseNode.getNodeType() == NodeType.NO_INTERFACE_BASES) {
return new TypeModel[0];
} else {
return resolveClassReferences(getParsed().getSubnode(4));
}
} else {
return new TypeModel[0];
}
}
private TypeModel resolveSimpleTypeName(String name) {
TypeModel simpleLookup = super.resolveTypeName(name);
if (simpleLookup != null) {
return simpleLookup;
}
if (innerTypes.hasKey(name)) {
return innerTypes.get(name);
} else {
Object[] models = innerTypes.values().arrayCopy();
for (int mi = 0; mi < models.length; mi++) {
TypeModel m = (TypeModel)models[mi];
if (m.matchesName(name)) {
return m;
}
}
if (owner != null) {
return owner.resolveTypeName(name);
} /*else if (getPackage().hasType(name)) {
return getPackage().getType(name);
} */else {
// TODO: Handle super-types here?
return null;
}
}
}
@Override
public TypeModel resolveTypeName(String name) {
/*Named m = lookupSimpleName(name, true);
if (m instanceof TypeModel) {
return (TypeModel) m;
} else {
return null;
}*/
TypeModel result = super.resolveTypeName(name);
if (result == null && baseClass != null) {
result = baseClass.resolveTypeName(name);
}
if (result == null) {
result = getSource().getImports().lookupExact(name);
if (result != null) {
return result;
}
result = getSource().getImports().lookupLoose(name);
if (result == null && getSource().getPackage().hasType(name)) {
return getSource().getPackage().getType(name);
}
return result;
} else {
return result;
}
}
private void addField(Branch b, Node name) {
fieldMembers.addMember(new FieldModel(this, plainName(((Branch)name).getSubnode(0)), b, (Branch) name));
}
private void addEnumField(Branch b, Node name) {
Token t = (Token) name;
fieldMembers.addMember(new FieldModel(this, t.getSnippet().getSource(), b));
}
private void addFields(Branch b) {
Branch slots = (Branch)b.getSubnode(2);
for (int i = 0; i < slots.countSubnodes(); i++) {
Node n = slots.getSubnode(i);
if (n.getNodeType() != NodeType.COMMA) {
addField(b, n);
}
}
}
private void addMethodOrConstructor(Branch b) {
String n = null;
if (b.getNodeType() == NodeType.CONSTRUCTOR_DECLARATION) {
/* Constructors are given an implicit name of "this", i.e. corresponding with a call
* to the "this" constructor. The name doesn't matter too much (at least not until
* the code generation stage when we have to adhere to an ABI), it just needs to be
* a name that won't conflict with a normal method ("this" is fine because it's a keyword)
*/
n = "this";
} else if (b.getNodeType() == NodeType.STATIC_CONSTRUCTOR_DECLARATION) {
n = "static-init";
} else {
n = plainName(b.getSubnode(3));
}
methodMembers.addMember(new MethodModel(this, n, b));
}
private void unpackMember(Branch b) {
switch (b.getNodeType()) {
case NodeType.CLASS_DECLARATION:
case NodeType.INTERFACE_DECLARATION:
case NodeType.ENUM_DECLARATION:
innerTypeMembers.addMember(new InnerTypeModel(this, plainName(b.getSubnode(2)), b, getInnerType(plainName(b.getSubnode(2)))));
break;
case NodeType.FIELD_DECLARATION:
addFields(b);
break;
case NodeType.CONSTRUCTOR_DECLARATION:
case NodeType.STATIC_CONSTRUCTOR_DECLARATION:
case NodeType.METHOD_DECLARATION:
addMethodOrConstructor(b);
break;
case NodeType.SEMICOLON: // We allow stray semicolons around type members.
break;
case NodeType.CLASS_MEMBERS: // Used as an internal division in enums
{
for (int i = 0; i < b.countSubnodes(); i++) {
Node s = b.getSubnode(i);
//System.out.println("GOT POSSIBLE ENTRY: " + s.getNodeType());
unpackMember((Branch) s);
}
} break;
case NodeType.ENUM_MEMBER:
addEnumField(b, b.getSubnode(1));
break;
case NodeType.COMMA:
break;
default:
throw new Error("Internal error/TODO: Unable to process " + b.getNodeType());
}
}
/** This is only designed to be called when registering alias types for generic arguments. */
void registerInnerType(TypeModel t) {
if (innerTypeMembers == null) {
innerTypeMembers = new InnerTypeSet(this, MemberCategory.INNER_TYPE);
}
// TODO: Should check that it's a sane argument? Or should simplify it early?
innerTypeMembers.addMember(new InnerTypeModel(this, t.getInnerName(), null, t));
//if (innerTypes.hasKey(t.getInnerName())) {
// throw new Error("TODO/internal error: Name collision of " + t.getName());
//}
//innerTypes.put(t.getInnerName(), t);
}
private int unpackMembers() {
int count = 0;
if (innerTypeMembers == null) {
innerTypeMembers = new InnerTypeSet(this, MemberCategory.INNER_TYPE);
}
fieldMembers = new FieldSet(this, MemberCategory.FIELD);
methodMembers = new MethodSet(this, MemberCategory.METHOD);
/* If a type doesn't exist at runtime (i.e. if it's just a template which exists at compile-time) then
* it is just left as though it exists in the type tree (for the sake of later lookup and instantiation,
* error-handling, etc.) but as though it has no members (since it wouldn't make sense to look up members
* of something which isn't instantiated, especially because their type signatures wouldn't exist).
*/
if (!existsAtRuntime()) {
return 0;
}
Node n = getParsed().getSubnode(getParsed().countSubnodes() - 2);
if (n instanceof Branch) {
Branch b = (Branch) n;
for (int i = 0; i < b.countSubnodes(); i++) {
Node s = b.getSubnode(i);
//System.out.println("GOT POSSIBLE ENTRY: " + s.getNodeType());
unpackMember((Branch) s);
count++;
}
}
if (getTypeType() == TypeType.ENUM) {
n = getParsed().getSubnode(getParsed().countSubnodes() - 3);
if (n instanceof Branch) {
Branch b = (Branch) n;
for (int i = 0; i < b.countSubnodes(); i++) {
Node s = b.getSubnode(i);
//System.out.println("GOT POSSIBLE ENUM ENTRY: " + s.getNodeType());
unpackMember((Branch) s);
count++;
}
}
}
return count;
}
@Override
public AttributeSet getAttributes() {
if (attributes == null) {
if (parsed == null || getTypeLevel() == TypeLevel.UNTITLED) {
attributes = new AttributeSet(this, null);
} else {
attributes = new AttributeSet(this, (Branch) parsed.getSubnode(0)); // TODO: Consider how this may impact inner classes (attributes will be decoded here and also with the type, may need to combine both sets)
}
}
return attributes;
}
@Override
public int resolveTypes() {
if (attributes == null) {
getAttributes();
return 1;
} else if (interfaces == null && existsAtRuntime()) {
baseClass = resolveBaseClass();
if (interfaces == null) {
interfaces = resolveInterfaces();
return (baseClass == null ? 0 : 1) + interfaces.length;
} else {
return baseClass == null ? 0 : 1;
}
} else if (fieldMembers == null) {
return 1 + unpackMembers();
} else {
return 0;
}
}
@Override
public int resolveExpressions() {
int nresolved = 0;
try {
if (fieldMembers != null) {
for (int i = 0; i < fieldMembers.countMembers(); i++) {
FieldModel f = fieldMembers.getMember(i);
nresolved += f.resolveExpressions();
}
}
if (methodMembers != null) {
for (int i = 0; i < methodMembers.countMembers(); i++) {
MethodModel m = methodMembers.getMember(i);
nresolved += m.resolveExpressions();
}
}
} catch (Error e) {
throw new Error("Something failed while resolving expressions in type " + toString(), e);
}
return nresolved;
}
@Override
public void dump(Reporter reporter, String indent, String incr) {
super.dump(reporter, indent, incr);
if (statementOrExpression != null) {
reporter.note("DUMP", indent + incr + "> This type is defined within " + statementOrExpression);
}
reporter.note("DUMP", indent + incr + "> Base class is " + baseClass);
if (interfaces != null) {
for (int i = 0; i < interfaces.length; i++) {
TypeModel m = interfaces[i];
reporter.note("DUMP", indent + incr + "> Implements interface " + m);
}
}
if (fieldMembers == null) {
reporter.note("DUMP", indent + incr + "[no members yet]");
} else if (!existsAtRuntime()) {
reporter.note("DUMP", indent + incr + "[doesn't exist at runtime so no members are modelled]");
} else {
for (int i = 0; i < innerTypeMembers.countMembers(); i++) {
innerTypeMembers.getMember(i).dump(reporter, indent + incr, incr);
}
for (int i = 0; i < fieldMembers.countMembers(); i++) {
fieldMembers.getMember(i).dump(reporter, indent + incr, incr);
}
for (int i = 0; i < methodMembers.countMembers(); i++) {
methodMembers.getMember(i).dump(reporter, indent + incr, incr);
}
}
}
@Override
public Named lookupSimpleName(String name, boolean includeOuterScopes) {
if (hasImmediatelyDefinedField(name)) {
return getImmediatelyDefinedField(name);
}
if (hasInnerType(name)) {
return getInnerType(name);
}
if (baseClass != null) {
Named result = baseClass.lookupSimpleName(name, false);
if (result != null) {
return result;
}
}
if (interfaces != null) {
for (int i = 0; i < interfaces.length; i++) {
Named result = interfaces[i].lookupSimpleName(name, false);
if (result != null) {
return result;
}
}
}
if (includeOuterScopes) {
if (statementOrExpression != null) {
Named result = statementOrExpression.lookupSimpleName(name);
if (result instanceof LocalStorageModel) {
return createUpvalueReference((LocalStorageModel)result);
} else {
return result;
}
} else if (getOwner() instanceof TypeModel) {
return ((TypeModel)getOwner()).lookupSimpleName(name, true);
}
Named imported = sourceFile.getImports().lookupExact(name);
if (imported != null) {
return imported;
}
if (getPackage().hasType(name)) {
return getPackage().getType(name);
}
return sourceFile.getImports().lookupLoose(name);
} else {
return null;
}
}
private Named createUpvalueReference(LocalStorageModel target) {
FieldModel upf = new FieldModel(this, target.getName(), target);
fieldMembers.addMember(upf);
return upf;
}
public int countUpvalues() {
int n = 0;
if (getBaseClass() instanceof UserTypeModel) {
n += ((UserTypeModel) getBaseClass()).countUpvalues();
}
for (int i = 0; i < fieldMembers.countMembers(); i++) {
if (fieldMembers.getMember(i).isUpvalue()) {
n++;
}
}
return n;
}
public FieldModel[] getUpvalues() {
FieldModel[] result = new FieldModel[countUpvalues()];
int i = 0;
if (getBaseClass() instanceof UserTypeModel) {
FieldModel[] base = ((UserTypeModel) getBaseClass()).getUpvalues();
for (i = 0; i < base.length; i++) {
result[i] = base[i];
}
}
for (int j = 0; j < fieldMembers.countMembers(); j++) {
if (fieldMembers.getMember(j).isUpvalue()) {
result[i] = fieldMembers.getMember(j);
i++;
}
}
return result;
}
@Override
public MethodModel[] lookupSimpleMethod(String name, boolean includeOuterScopes) {
MethodModel[] result = this.getMethods(name, true);
if (includeOuterScopes) {
if (statementOrExpression != null) {
result = MethodModel.addArrays(result, statementOrExpression.lookupSimpleMethod(name));
} else if (getOwner() instanceof TypeModel) {
result = MethodModel.addArrays(result, ((TypeModel)getOwner()).lookupSimpleMethod(name, true));
}
}
return result;
}
public boolean hasImmediatelyDefinedField(String name) {
return fieldMembers != null && fieldMembers.hasMemberNamed(name);
}
public FieldModel getImmediatelyDefinedField(String name) {
if (!hasImmediatelyDefinedField(name)) {
return null;
}
return fieldMembers.getMemberNamed(name, 0);
}
@Override
public boolean hasField(String name, boolean includeBase) {
if (hasImmediatelyDefinedField(name)) {
return true;
}
if (includeBase && baseClass != null && baseClass.hasField(name, true)) {
return true;
}
if (includeBase && interfaces != null) {
for (int i = 0; i < interfaces.length; i++) {
if (interfaces[i].hasField(name, true)) {
return true;
}
}
}
return false;
}
@Override
public FieldModel getField(String name, boolean includeBase) {
if (hasImmediatelyDefinedField(name)) {
return getImmediatelyDefinedField(name);
}
if (includeBase && baseClass != null && baseClass.hasField(name, true)) {
return baseClass.getField(name, true);
}
if (includeBase && interfaces != null) {
for (int i = 0; i < interfaces.length; i++) {
if (interfaces[i].hasField(name, true)) {
return interfaces[i].getField(name, true);
}
}
}
return null;
}
@Override
public MethodModel[] getMethods(String name, boolean includeBase) {
// TODO: Remove overriden methods?
MethodModel[] result = new MethodModel[0];
if (methodMembers != null) {
MethodModel[] inner = new MethodModel[methodMembers.countMembersNamed(name)];
for (int i = 0; i < inner.length; i++) {
inner[i] = methodMembers.getMemberNamed(name, i);
}
result = MethodModel.addArrays(result, inner);
}
if (includeBase && baseClass != null && baseClass.hasMethods(name, true)) {
result = MethodModel.addArrays(result, baseClass.getMethods(name, true));
}
if (includeBase && interfaces != null) {
for (int i = 0; i < interfaces.length; i++) {
if (interfaces[i].hasMethods(name, true)) {
result = MethodModel.addArrays(result, interfaces[i].getMethods(name, true));
}
}
}
// This will avoid adding any methods which are overridden or duplicated by others on the list
return MethodModel.findRelevantMethods(result, true);
}
private MethodModel createSyntheticConstructor(MethodModel baseConstructor) {
MethodModel result = new MethodModel(this, baseConstructor.getName(), baseConstructor);
return result;
}
@Override
public MethodModel[] getInstanceConstructors() {
MethodModel[] localConstructors = getMethods("this", false);
if (localConstructors.length > 0) {
return localConstructors;
} else if ((getTypeType() == TypeType.CLASS || getTypeType() == TypeType.ENUM || (getTypeType() == TypeType.CLASS_TEMPLATE && existsAtRuntime())) && baseClass != null) {
MethodModel[] baseConstructors = baseClass.getInstanceConstructors();
for (int i = 0; i < baseConstructors.length; i++) {
MethodModel b = baseConstructors[i];
if (b.countParameters() == 0 || ((getTypeType() == TypeType.ENUM || getTypeLevel()==TypeLevel.UNTITLED) && !b.isPrivate())) {
// TODO: Generate anonymous constructors properly
methodMembers.addMember(createSyntheticConstructor(b));
}
/*if (!b.isPrivate()) {
methodMembers.addMember(createSyntheticConstructor(b));
}*/
}
return getMethods("this", false);
} else {
return new MethodModel[0];
}
}
@Override
public boolean hasInnerType(String name, boolean includeBase) {
if (super.hasInnerType(name, includeBase)) {
return true;
}
if (includeBase && baseClass != null && baseClass.hasInnerType(name, true)) {
return true;
}
if (includeBase && interfaces != null) {
for (int i = 0; i < interfaces.length; i++) {
if (interfaces[i].hasInnerType(name, true)) {
return true;
}
}
}
return false;
}
@Override
public TypeModel getInnerType(String name, boolean includeBase) {
if (super.hasInnerType(name, false)) {
return super.getInnerType(name, false);
}
if (includeBase && baseClass != null && baseClass.hasInnerType(name, true)) {
return baseClass.getInnerType(name, true);
}
if (includeBase && interfaces != null) {
for (int i = 0; i < interfaces.length; i++) {
if (interfaces[i].hasInnerType(name, true)) {
return interfaces[i].getInnerType(name, true);
}
}
}
return null;
}
@Override
public boolean inherits(TypeModel otherType) {
otherType = otherType.simplify();
//System.err.println("Checking if " + this + " inherits from " + otherType);
if (baseClass == otherType) {
//System.err.println("Hit this");
return true;
} else if (baseClass != null && baseClass.inherits(otherType)) {
//System.err.println("Hit base");
return true;
} else if (interfaces != null) {
for (int i = 0; i < interfaces.length; i++) {
if (interfaces[i] == otherType || interfaces[i].inherits(otherType)) {
//System.err.println("Hit interface");
return true;
}
}
}
//System.err.println("Check failed");
return false;
}
@Override
public boolean isObjectType() {
return true;
}
public boolean isInnerType() {
// TODO: Handle static declaration
return getTypeLevel() == TypeLevel.INNER
|| getTypeLevel() == TypeLevel.INNER_INNER
|| getTypeLevel() == TypeLevel.UNTITLED;
}
public boolean isNonStaticInnerType() {
return isInnerType() && !isStatic();
}
public boolean isStatic() {
return getTypeType() == TypeType.INTERFACE
|| getTypeType() == TypeType.INTERFACE_TEMPLATE
|| getTypeType() == TypeType.ENUM
|| getTypeLevel() == TypeLevel.OUTER
|| getAttributes().isStatic();
}
@Override
public int getFlags() {
int f = super.getFlags();
if (isStatic()) {
f |= Flags.MASK_STATIC;
}
if (isInnerType()) {
f |= Flags.MASK_INNER;
}
return f;
}
}