/** * 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