/**
* Abstract class that represents a Java Class.
*
* Concrete implementations of this class are for example bytecode-class and source-class.
*
* @author Martin Bravenboer <martin@cs.uu.nl>
*/
module dryad/model/class
imports
dryad/model/member
dryad/model/repository
dryad/lib-ext/oo/classes
dryad/jls/types/Erasure
/**
* Names
*/
strategies
/**
* Returns the simple name of this class.
*
* @type Class Object -> String
*/
get-simple-name = instanceof-JavaClass;
classes_get-instance-field(|"simple-name")
/**
* Returns the canonical name of this class.
*
* @type Class Object -> TypeName
*/
get-name = instanceof-JavaClass;
get-canonical-name
/**
* Returns the canonical name of this class.
*
* Canonical names (see section 6.7) are fully qualified names
* that uniquely identify a class. There are no two different
* canonical names that refer to the same class.
*
* @type Class Object -> TypeName
*/
get-canonical-name = instanceof-JavaClass; ?this;
if get-declaring-class => class then
!TypeName(<get-canonical-name> class, Id(<get-simple-name> this))
else
!TypeName(<get-package; get-canonical-name> this, Id(<get-simple-name> this))
end
/**
* Returns the canonical name of this class, which is a fully qualified name.
*
* @type Class Object -> TypeName
*/
get-fully-qualified-name = instanceof-JavaClass;
get-canonical-name
/**
* Formal type parameters
*/
strategies
/**
* Succeeds if this class has a type parameter of the given name.
*
* @param Simple name of the type parameter (String)
* @type Class Object -> TypeParam
*/
has-formal-type-parameter(|name) = instanceof-JavaClass;
where(get-formal-type-parameter(|name))
/**
* Returns the type parameter of the given name, or fails
* if this class thus have a type parameter with this name.
*
* @param Simple name of the type parameter (String)
* @type Class Object -> TypeParam
*/
get-formal-type-parameter(|name) = instanceof-JavaClass;
get-formal-type-parameters
; fetch-elem(?TypeParam(Id(name), _))
/**
* Abstract method. Has to declared in subclasses.
*
* @type Class Object -> List(TypeParam)
*/
get-formal-type-parameters =
fail
/**
* Succeeds if this is a generic class (i.e. has formal type parameters).
*/
is-generic = instanceof-JavaClass;
where(get-formal-type-parameters => [_ | _])
/**
* Superclass
*/
strategies
/**
* Returns the super class of this class.
* Fails if this class has no superclass (i.e. this class is java.lang.Object)
*
* @type Class Object -> Class Object
*/
get-superclass =
get-superclass-as-type
; lookup-class
/**
* Returns the super class of this class as a type.
*
* Abstract method. Must be implemented by the subclass.
*
* @type Class Object -> Source Type
*/
get-superclass-as-type =
fail
get-superclass-type =
get-superclass-as-type
/**
* Succeeds if this class is subclass of the given class.
*
* @param The possible superclass.
* @type Class Object -> Class Object
*/
is-subclass(|class) =
where(
get-superclass
; if ?class then
true
else
is-subclass(|class)
end
)
strategies
/**
* Superclass of a parameterized types.
*
* @param Type
* @type Class Object -> Source Type
*/
get-superclass(|intype) = ?this;
where(is-generic)
; where(!intype; (?ClassType(_, Some(TypeArgs(args))) + ?InterfaceType(_, Some(TypeArgs(args)))))
; get-superclass-as-type
; apply-type-substitution(|this, args)
/**
* Superclass of a raw type.
*/
get-superclass(|intype) = ?this;
where(is-generic)
; where(!intype; (?ClassType(_, None()) + ?InterfaceType(_, None())))
; get-superclass-as-type
; type-erasure
/**
* Superclass of a unparameterized type.
*/
get-superclass(|intype) =
where(not(is-generic))
; get-superclass-as-type
/**
* Superinterfaces
*/
strategies
/**
* Returns the direct super interfaces
*
* @type Class Object -> Class Object
*/
get-superinterfaces =
get-superinterfaces-as-type
; map(lookup-class)
/**
* Returns the interfaces implemented by this class as types.
*
* Abstract method. Must be implemented by the subclass.
*
* @type Class Object -> List(Source Type)
*/
get-superinterfaces-as-type =
fail
strategies
/**
* @param Type
* @type Class Object -> List(Source Type)
*/
get-superinterfaces(|intype) = ?this;
where(is-generic)
; where(!intype; (?ClassType(_, Some(TypeArgs(args))) + ?InterfaceType(_, Some(TypeArgs(args)))))
; get-superinterfaces-as-type
; apply-type-substitution(|this, args)
/**
* Superclass of a raw type.
*/
get-superinterfaces(|intype) = ?this;
where(is-generic)
; where(!intype; (?ClassType(_, None()) + ?InterfaceType(_, None())))
; get-superinterfaces-as-type
; map(type-erasure)
/**
* Superclass of a unparameterized type.
*/
get-superinterfaces(|intype) =
where(not(is-generic))
; get-superinterfaces-as-type
/**
* Fields.
*/
strategies
/**
* Returns all fields of this class, including those inherited from
* superclasses and superinterfaces.
*
* For array classes, this method does return the length field (java.lang.getFields does
* not return the length field for an array class).
*
* @type Class Object -> List(Field Object)
*/
get-fields =
<conc> (<get-declared-fields>, <get-inherited-fields>)
/**
* Returns the field for the given name.
*
* If multiple fields are accessible, then an access of this field ambiguous
* and this strategy will fail. Use get-fields(|name) if you need all
* the field declarations of the given name.
*
* If the class is an array class, then this method will succeed and
* return a field if
*
* @param String
* @type Class Object -> Field Object
*/
get-field(|name) =
get-fields(|name)
; ?[<id>]
/**
* Returns all the visible fields with the given name.
*
* For valid Java classes, this should return a singleton
* list. For invalid Java classes, there might be multiple
* declarations with the same name.
*
* @todo Optimize by not retrieving all the fields first.
* @param String
* @type Class Object -> List(Field Object)
*/
get-fields(|name) =
get-fields
; retain-all(where(get-simple-name => name))
/**
* Succeeds if the current class has a field with this name.
* The field might be inherited.
*
* @param String
* @type Class Object -> Class Object
*/
has-field(|name) =
where(get-field(|name))
/**
* Declared fields
*/
strategies
/**
* @type Class Object -> List(Field Object)
*/
get-declared-fields =
get-declared-field-table
; hashtable-values
/**
* Returns the field 'name', which must be declared in this class.
*
* @param String
* @type Class Object -> Field Object
*/
get-declared-field(|name) =
get-declared-field-table
; hashtable-get(|name)
/**
* Succeeds if the current class declares a field with this name.
*
* @param String
* @type Class Object -> Class Object
*/
has-declared-field(|name) =
where(get-declared-field(|name))
/**
* Inherited fields
*/
strategies
/**
* Returns all fields of this class that are inherited from superclasses and superinterfaces.
*
* @type Class Object -> List(Fields Object)
*/
get-inherited-fields = ?this;
<concat> [
<get-superclass < get-fields + ![]>
| <get-superinterfaces; map(get-fields)>
]
; remove-all(is-not-inherited(|this))
; make-set
/**
* Returns all fields of this class that are inherited from superclasses and superinterfaces.
*
* @param Simple name of the field (String)
* @type Class Object -> List(Field Object)
*/
get-inherited-fields(|name) = ?this;
<concat> [
<get-superclass < get-fields(|name) + ![]>
| <get-superinterfaces; map(get-fields(|name))>
]
; remove-all(is-not-inherited(|this))
; make-set
/**
* Succeeds if the current class inherits a field with this name.
*
* @param Simple name of the class (String)
* @type Class Object -> Class Object
*/
has-inherited-field(|name) = instanceof-JavaClass;
where(
get-inherited-fields(|name)
; ?[_ | _]
)
/**
* Private helpers for fields.
*/
strategies
/**
* Private. Do not invoke.
*/
get-declared-field-table =
classes_get-instance-field(init-declared-field-table; get-declared-field-table |"declared-field-table")
/**
* Abstract strategy. Must be implemented by subclasses.
*/
init-declared-field-table =
fail
/**
* Default implementation of init-declared-field-table, which requires the
* subclass to implement init-get-declared-field-list.
*/
init-declared-field-table =
where(
init-get-declared-field-list
; where(<new-hashtable> () => fieldtbl)
; map({field, name:
?field
; get-simple-name => name
; <hashtable-put(|name, field)> fieldtbl
})
)
; classes_set-instance-field(|"declared-field-table", fieldtbl)
/**
* Abstract strategy. Must be implemented by subclasses if the default
* init-declared-field-table is used.
*/
init-get-declared-field-list =
fail
/**
* Abstract support for constructors
*
* All classes must have a constructor hashtable.
*/
strategies
/**
* Returns a list of the constructors declared in this class.
*
* @type Class Object -> List(Constructor Object)
*/
get-declared-constructors =
get-declared-constructor-list
/**
* Returns all constructors of this class, including superclasses.
*
* @type Class Object -> List(Constructor Object)
*/
get-constructors =
<conc> (<get-declared-constructors>, <get-superclass < get-constructors + ![]>)
/**
* Returns a list of the constructors declared in this class.
*
* Don't invoke directly: use get-declared-constructors
*
* @type Class Object -> List(Constructor Object)
* @todo Is a list the most efficient way for storing constructors?
*/
get-declared-constructor-list =
classes_get-instance-field(init-declared-constructor-list; get-declared-constructor-list |"declared-constructor-list")
/**
* Must be implemented by subclasses.
*/
init-declared-constructor-list =
fail
/**
* Default implementation (not required to use this).
*/
init-declared-constructor-list =
where(
init-get-declared-constructor-list
; ?cons
)
; classes_set-instance-field(|"declared-constructor-list", cons)
/**
* Declared methods
*/
strategies
/**
* Returns a list of the methods declared in this class.
*
* @type Class Object -> List(Method Object)
*/
get-declared-methods =
get-declared-method-table
; hashtable-values
; concat
/**
* Returns the methods 'name', which must be declared in this class.
* If no such method exits, the empty list is returned.
*
* @param String
* @type Class Object -> List(Method Object)
*/
get-declared-methods(|name) = instanceof-JavaClass;
get-declared-method-table
; (hashtable-get(|name) <+ ![])
/**
* Succeeds if the current class declares a method with this name.
*
* @param String
* @type Class Object -> Class Object
*/
has-declared-method(|name) = instanceof-JavaClass;
where(
get-declared-methods(|name)
; ?[_ | _]
)
/**
* Methods
*/
strategies
/**
* Returns all member methods of this class.
* Including superclasses and superinterfaces.
*
* @type Class Object -> List(Method Object)
*/
get-methods =
<conc> (<get-declared-methods>, <get-inherited-methods>)
/**
* Returns all member methods of this class with this name.
* Including superclasses and superinterfaces.
*
* @param String
* @type Class Object -> List(Method Object)
*/
get-methods(|name) =
<conc> (<get-declared-methods(|name)>, <get-inherited-methods(|name)>)
/**
* Succeeds if this has a member method with the given name.
*
* @type Class Object -> Class Object
* @type name String
*/
has-method(|name) =
has-declared-method(|name)
<+ has-inherited-method(|name)
/**
* Inherited methods
*/
strategies
/**
* Returns all methods of this class that are inherited from superclasses and superinterfaces.
*
* @type Class Object -> List(Method Object)
*/
get-inherited-methods = ?this;
<concat> [
<get-superclass < get-methods + ![]>
| <get-superinterfaces; map(get-methods)>
]
; remove-all(is-not-inherited(|this))
; make-set
/**
* Returns all methods of this class with this name that are inherited
* from superclasses and superinterfaces.
*
* @type Class Object -> List(Method Object)
*/
get-inherited-methods(|name) = ?this;
<concat> [
<get-superclass < get-methods(|name) + ![]>
| <get-superinterfaces; map(get-methods(|name))>
]
; remove-all(is-not-inherited(|this))
; make-set
/**
* Succeeds if the current class inherits a method with this name.
*
* @param String
* @type Class Object -> Class Object
*/
has-inherited-method(|name) = instanceof-JavaClass;
where(
get-inherited-methods(|name)
; ?[_ | _]
)
/**
* Private helpers for methods.
*/
strategies
/**
* Returns a hashtable of the methods declared in this class.
*
* @type Class Object -> HashTable(String, Method Object)
*/
get-declared-method-table =
classes_get-instance-field(init-declared-method-table; get-declared-method-table |"declared-method-table")
/**
* Abstract strategy. Must be implemented by subclasses.
*/
init-declared-method-table =
fail
/**
* Default implementation.
*/
init-declared-method-table =
where(
init-get-declared-method-list
; where(new-hashtable => methodtbl)
; map({name, method:
?method
; get-simple-name => name
; <hashtable-push(|name, method)> methodtbl
})
)
; classes_set-instance-field(|"declared-method-table", methodtbl)
init-get-declared-method-list =
fail
/**
* Inheritance
*/
strategies
/**
* Private methods are not inherited.
*
* This strategy is defined as not-inherited to allow overloading.
*
* @param Class Object
* @type Method Object -> Method Object
*/
is-not-inherited(|inclass) =
is-private
/**
* Hidden fields are not inherited.
*
* @param Class Object
* @type Field Object -> Field Object
*/
is-not-inherited(|inclass) =
where(
instanceof-JavaField
; get-simple-name => name
; <has-declared-field(|name)> inclass
)
/**
* Hidden member types are not inherited.
*
* @param Class Object
* @type Field Object -> Field Object
*/
is-not-inherited(|inclass) =
where(
instanceof-JavaClass
; get-simple-name => name
; <has-declared-member-type(|name)> inclass
)
/**
* Members with default access are not inherited into classes defined in a different package.
*/
is-not-inherited(|inclass) = ?this;
where(
<get-declaring-class; get-package> this => decpackage
; <get-package> inclass => package
; if not(!decpackage => package) then
<get-access> this => DefaultAccess()
else
/**
* This is a bit confusing: the strategy must succeed if the method is not inherited.
*/
fail
end
)
/**
* Member Types
*/
strategies
/**
* Returns all member types of this class.
*
* @type Class Object -> List(Class Object)
*/
get-member-types =
<conc> (<get-declared-member-types>, <get-inherited-member-types>)
/**
* Returns the member type of this class with this name.
*
* @param String
* @type Class Object -> Class Object
*/
get-member-type(|name) =
get-member-types(|name)
; ?[<id>]
/**
* Returns the member types of this class with this name.
* For valid classes, this always returns a singleton list.
*
* @param String
* @type Class Object -> List(Class Object)
* @todo Store member types in a list an remove the ![<id>]?
*/
get-member-types(|name) =
get-declared-member-type(|name); ![<id>]
<+ get-inherited-member-types(|name)
/**
* Succeeds if this has a member type with the given name.
*
* @type Class Object -> Class Object
* @type name String
*/
has-member-type(|name) =
has-declared-member-type(|name)
<+ has-inherited-member-type(|name)
/**
* Declared Member Types
*/
strategies
/**
* Returns all the member types declared in this class.
*
* @type Class Object -> List(Class Object)
*/
get-declared-member-types =
get-declared-member-type-table
; hashtable-values
/**
* Returns the type 'name', which must be declared in this class.
*
* @param name String
* @type Class Object -> Class Object
*/
get-declared-member-type(|name) =
get-declared-member-type-table
; hashtable-get(|name)
/**
* Succeeds if the current class declares a class with this name.
*
* @type Class Object -> Class Object
*/
has-declared-member-type(|name) =
where(get-declared-member-type(|name))
/**
* @todo Maybe this should be in the subclasses, since the implementation is different
* for source and bytecode classes.
*/
add-declared-member-type(|class) = ?this;
where(
where(<get-simple-name> class => name)
; get-declared-member-type-table
; hashtable-put(|name, class)
)
/**
* Inherited Member Types
*/
strategies
/**
* Returns all member types of this class that are inherited from superclasses and superinterfaces.
*
* @type Class Object -> List(Class Object)
*/
get-inherited-member-types = ?this;
<concat> [
<get-superclass < get-member-types + ![]>
| <get-superinterfaces; map(get-member-types)>
]
; remove-all(is-not-inherited(|this))
; make-set
/**
* Returns all member types of this class with the given name
* that are inherited from superclasses and superinterfaces.
*
* @param Simple name of the class (String)
* @type Class Object -> List(Class Object)
*/
get-inherited-member-types(|name) = ?this;
<concat> [
<get-superclass < get-member-types(|name) + ![]>
| <get-superinterfaces; map(get-member-types(|name))>
]
; remove-all(is-not-inherited(|this))
; make-set
/**
* Succeeds if the current class inherits a member type with this name.
*
* @param Simple name of the class (String)
* @type Class Object -> Class Object
*/
has-inherited-member-type(|name) = instanceof-JavaClass;
where(
get-inherited-member-types(|name)
; ?[_ | _]
)
/**
* Private member type utils.
*/
strategies
/**
* Private. Do not invoke directly.
*
* @type Hashtable(String, Class Object)
*/
get-declared-member-type-table =
classes_get-instance-field(
init-declared-member-type-table
; get-declared-member-type-table
| "declared-member-type-table")
/**
* Should be overridden by a subclass.
*/
init-declared-member-type-table = fail
/**
* Abstract support for member classes.
*/
strategies
/**
* Succeeds if this is a top level class.
*/
is-top-level-class =
not(is-nested-class)
/**
* Succeeds if this is a nested class.
*/
is-nested-class =
is-member-type
+ is-local-class
+ is-anonymous-class
/**
* @todo Stub: implement.
*/
is-anonymous-class =
fail
/**
* Succeeds if this class is a member of an enclosing class.
*/
is-member-type =
where(get-declaring-class)
/**
* @todo Implement: Stub
*/
is-local-class =
fail
/**
* @todo Anonymous classes don't have a declaring class.
*/
get-enclosing-class =
get-declaring-class
/**
* Stratego class support.
*/
strategies
/**
* Checks if current term is an instance of JavaClass.
* Subclasses of class implement this strategy.
*/
instanceof-JavaClass =
fail
/**
* Succeeds if the current term is an instance of a Java member.
* This alternative declares a JavaClass to be a JavaMember.
*
* @todo Make a member class a separate subclass?
*/
instanceof-JavaMember =
instanceof-JavaClass