diff options
author | tromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-08-12 20:34:51 +0000 |
---|---|---|
committer | tromey <tromey@138bc75d-0d04-0410-961f-82ee72b054a4> | 2003-08-12 20:34:51 +0000 |
commit | af74ab68ba5a2073bc66e570f938e11d3e71c0fe (patch) | |
tree | b0eccc2bad8dc4ad0fc0c2540ee347467640fdec /gcc/java | |
parent | e50c12fc93d9d59f81785ba705c7f80dce7845de (diff) | |
download | gcc-af74ab68ba5a2073bc66e570f938e11d3e71c0fe.tar.gz |
* parse.y (java_check_regular_methods): Typo fixes. Call
check_interface_throws_clauses. Use
check_concrete_throws_clauses.
(check_interface_throws_clauses): New function.
(check_concrete_throws_clauses): New function.
(hack_is_accessible_p): New function.
(find_most_specific_methods_list): Added FIXME.
* typeck.c (lookup_do): Use `flags' argument to decide what to
do. Reimplemented.
(lookup_argument_method_generic): New function.
(lookup_argument_method2): Removed.
* jcf.h (ACC_INVISIBLE): New define.
* jcf-write.c (generate_classfile): Skip invisible methods.
* class.c (add_miranda_methods): New function.
(layout_class_methods): Use it.
(get_access_flags_from_decl): Use ACC_INVISIBLE.
* java-tree.h (METHOD_INVISIBLE): New define.
(lang_decl_func) [invisible]: New field.
(lookup_argument_method_generic): Declare.
(SEARCH_INTERFACE): New define.
(SEARCH_SUPER): Likewise.
(SEARCH_ONLY_INTERFACE): Likewise.
(SEARCH_VISIBLE): Likewise.
(lookup_argument_method2): Removed declaration.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@70388 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/java')
-rw-r--r-- | gcc/java/ChangeLog | 27 | ||||
-rw-r--r-- | gcc/java/class.c | 74 | ||||
-rw-r--r-- | gcc/java/java-tree.h | 12 | ||||
-rw-r--r-- | gcc/java/jcf-write.c | 6 | ||||
-rw-r--r-- | gcc/java/jcf.h | 3 | ||||
-rw-r--r-- | gcc/java/parse.y | 156 | ||||
-rw-r--r-- | gcc/java/typeck.c | 184 |
7 files changed, 349 insertions, 113 deletions
diff --git a/gcc/java/ChangeLog b/gcc/java/ChangeLog index 0d6578ceaed..10358153bf0 100644 --- a/gcc/java/ChangeLog +++ b/gcc/java/ChangeLog @@ -1,3 +1,30 @@ +2003-08-11 Tom Tromey <tromey@redhat.com> + + * parse.y (java_check_regular_methods): Typo fixes. Call + check_interface_throws_clauses. Use + check_concrete_throws_clauses. + (check_interface_throws_clauses): New function. + (check_concrete_throws_clauses): New function. + (hack_is_accessible_p): New function. + (find_most_specific_methods_list): Added FIXME. + * typeck.c (lookup_do): Use `flags' argument to decide what to + do. Reimplemented. + (lookup_argument_method_generic): New function. + (lookup_argument_method2): Removed. + * jcf.h (ACC_INVISIBLE): New define. + * jcf-write.c (generate_classfile): Skip invisible methods. + * class.c (add_miranda_methods): New function. + (layout_class_methods): Use it. + (get_access_flags_from_decl): Use ACC_INVISIBLE. + * java-tree.h (METHOD_INVISIBLE): New define. + (lang_decl_func) [invisible]: New field. + (lookup_argument_method_generic): Declare. + (SEARCH_INTERFACE): New define. + (SEARCH_SUPER): Likewise. + (SEARCH_ONLY_INTERFACE): Likewise. + (SEARCH_VISIBLE): Likewise. + (lookup_argument_method2): Removed declaration. + 2003-08-05 Tom Tromey <tromey@redhat.com> Fix for PR java/11600: diff --git a/gcc/java/class.c b/gcc/java/class.c index fbec8d0a9ca..620a8a2e6c9 100644 --- a/gcc/java/class.c +++ b/gcc/java/class.c @@ -57,6 +57,7 @@ static tree get_dispatch_table (tree, tree); static int supers_all_compiled (tree type); static void add_interface_do (tree, tree, int); static tree maybe_layout_super_class (tree, tree); +static void add_miranda_methods (tree, tree); static int assume_compiled (const char *); static tree build_method_symbols_entry (tree); @@ -1034,6 +1035,8 @@ get_access_flags_from_decl (tree decl) access_flags |= ACC_ABSTRACT; if (METHOD_STRICTFP (decl)) access_flags |= ACC_STRICT; + if (METHOD_INVISIBLE (decl)) + access_flags |= ACC_INVISIBLE; return access_flags; } abort (); @@ -1747,14 +1750,14 @@ layout_class (tree this_class) { tree super_class = CLASSTYPE_SUPER (this_class); tree field; - + class_list = tree_cons (this_class, NULL_TREE, class_list); if (CLASS_BEING_LAIDOUT (this_class)) { char buffer [1024]; char *report; tree current; - + sprintf (buffer, " with `%s'", IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (this_class)))); obstack_grow (&temporary_obstack, buffer, strlen (buffer)); @@ -1808,8 +1811,9 @@ layout_class (tree this_class) layout_type (this_class); - /* Also recursively load/layout any superinterfaces, but only if class was - loaded from bytecode. The source parser will take care of this itself. */ + /* Also recursively load/layout any superinterfaces, but only if + class was loaded from bytecode. The source parser will take care + of this itself. */ if (!CLASS_FROM_SOURCE_P (this_class)) { tree basetype_vec = TYPE_BINFO_BASETYPES (this_class); @@ -1837,14 +1841,61 @@ layout_class (tree this_class) } } - /* Convert the size back to an SI integer value */ - TYPE_SIZE_UNIT (this_class) = + /* Convert the size back to an SI integer value. */ + TYPE_SIZE_UNIT (this_class) = fold (convert (int_type_node, TYPE_SIZE_UNIT (this_class))); CLASS_BEING_LAIDOUT (this_class) = 0; class_list = TREE_CHAIN (class_list); } +static void +add_miranda_methods (tree base_class, tree search_class) +{ + tree basetype_vec = TYPE_BINFO_BASETYPES (search_class); + int i, n = TREE_VEC_LENGTH (basetype_vec); + for (i = 1; i < n; ++i) + { + tree method_decl; + tree elt = TREE_VEC_ELT (basetype_vec, i); + if (elt == NULL_TREE) + break; + elt = BINFO_TYPE (elt); + + /* Note that order matters here. However, all the base classes + will have been laid out at this point, so the order will + always be correct. Also, this code must match similar layout + code in the runtime. */ + for (method_decl = TYPE_METHODS (elt); + method_decl; method_decl = TREE_CHAIN (method_decl)) + { + tree sig, override; + + /* An interface can have <clinit>. */ + if (ID_CLINIT_P (DECL_NAME (method_decl))) + continue; + + sig = build_java_argument_signature (TREE_TYPE (method_decl)); + override = lookup_argument_method (base_class, + DECL_NAME (method_decl), sig); + if (override == NULL_TREE) + { + /* Found a Miranda method. Add it. */ + tree new_method; + sig = build_java_signature (TREE_TYPE (method_decl)); + new_method + = add_method (base_class, + get_access_flags_from_decl (method_decl), + DECL_NAME (method_decl), sig); + METHOD_INVISIBLE (new_method) = 1; + } + } + + /* Try superinterfaces. */ + add_miranda_methods (base_class, elt); + } +} + void layout_class_methods (tree this_class) { @@ -1866,11 +1917,20 @@ layout_class_methods (tree this_class) else dtable_count = integer_zero_node; + if (CLASS_ABSTRACT (TYPE_NAME (this_class))) + { + /* An abstract class can have methods which are declared only in + an implemented interface. These are called "Miranda + methods". We make a dummy method entry for such methods + here. */ + add_miranda_methods (this_class, this_class); + } + TYPE_METHODS (this_class) = nreverse (TYPE_METHODS (this_class)); for (method_decl = TYPE_METHODS (this_class); method_decl; method_decl = TREE_CHAIN (method_decl)) - dtable_count = layout_class_method (this_class, super_class, + dtable_count = layout_class_method (this_class, super_class, method_decl, dtable_count); TYPE_NVIRTUALS (this_class) = dtable_count; diff --git a/gcc/java/java-tree.h b/gcc/java/java-tree.h index 920d2886653..0a7a542a9f5 100644 --- a/gcc/java/java-tree.h +++ b/gcc/java/java-tree.h @@ -977,6 +977,9 @@ struct lang_decl_func GTY(()) unsigned int fixed_ctor : 1; unsigned int init_calls_this : 1; unsigned int strictfp : 1; + unsigned int invisible : 1; /* Set for methods we generate + internally but which shouldn't be + written to the .class file. */ }; struct treetreehash_entry GTY(()) @@ -1071,6 +1074,12 @@ struct lang_type GTY(()) #define JCF_u4 unsigned long #define JCF_u2 unsigned short +/* Possible values to pass to lookup_argument_method_generic. */ +#define SEARCH_INTERFACE 1 +#define SEARCH_SUPER 2 +#define SEARCH_ONLY_INTERFACE 4 +#define SEARCH_VISIBLE 8 + extern void java_parse_file (int); extern bool java_mark_addressable (tree); extern tree java_type_for_mode (enum machine_mode, int); @@ -1084,7 +1093,7 @@ extern tree lookup_class (tree); extern tree lookup_java_constructor (tree, tree); extern tree lookup_java_method (tree, tree, tree); extern tree lookup_argument_method (tree, tree, tree); -extern tree lookup_argument_method2 (tree, tree, tree); +extern tree lookup_argument_method_generic (tree, tree, tree, int); extern int has_method (tree, tree); extern tree promote_type (tree); extern tree get_constant (struct JCF*, int); @@ -1302,6 +1311,7 @@ extern void init_resource_processing (void); #define METHOD_NATIVE(DECL) (DECL_LANG_SPECIFIC(DECL)->u.f.native) #define METHOD_ABSTRACT(DECL) DECL_LANG_FLAG_5 (DECL) #define METHOD_STRICTFP(DECL) (DECL_LANG_SPECIFIC (DECL)->u.f.strictfp) +#define METHOD_INVISIBLE(DECL) (DECL_LANG_SPECIFIC (DECL)->u.f.invisible) #define JAVA_FILE_P(NODE) TREE_LANG_FLAG_2 (NODE) #define CLASS_FILE_P(NODE) TREE_LANG_FLAG_3 (NODE) diff --git a/gcc/java/jcf-write.c b/gcc/java/jcf-write.c index 44c9ec1cf80..3609807a410 100644 --- a/gcc/java/jcf-write.c +++ b/gcc/java/jcf-write.c @@ -2919,6 +2919,12 @@ generate_classfile (tree clas, struct jcf_partial *state) tree type = TREE_TYPE (part); tree save_function = current_function_decl; int synthetic_p = 0; + + /* Invisible Miranda methods shouldn't end up in the .class + file. */ + if (METHOD_INVISIBLE (part)) + continue; + current_function_decl = part; ptr = append_chunk (NULL, 8, state); i = get_access_flags (part); PUT2 (i); diff --git a/gcc/java/jcf.h b/gcc/java/jcf.h index 970656732c0..5b97fec9525 100644 --- a/gcc/java/jcf.h +++ b/gcc/java/jcf.h @@ -230,6 +230,9 @@ typedef struct JCF GTY(()) { #define ACC_INTERFACE 0x0200 #define ACC_ABSTRACT 0x0400 #define ACC_STRICT 0x0800 +/* "Invisible" refers to Miranda methods inserted into an abstract + #class. It is also used in the runtime. */ +#define ACC_INVISIBLE 0x1000 #define ACC_VISIBILITY (ACC_PUBLIC | ACC_PRIVATE | ACC_PROTECTED) diff --git a/gcc/java/parse.y b/gcc/java/parse.y index 6ca734aa684..a9f8d6ecc6b 100644 --- a/gcc/java/parse.y +++ b/gcc/java/parse.y @@ -224,6 +224,7 @@ static void check_thrown_exceptions (int, tree, tree); static int check_thrown_exceptions_do (tree); static void purge_unchecked_exceptions (tree); static bool ctors_unchecked_throws_clause_p (tree); +static void check_concrete_throws_clauses (tree, tree, tree, tree); static void check_throws_clauses (tree, tree, tree); static void finish_method_declaration (tree); static tree build_super_invocation (tree); @@ -244,7 +245,9 @@ static void start_artificial_method_body (tree); static void end_artificial_method_body (tree); static int check_method_redefinition (tree, tree); static int check_method_types_complete (tree); +static bool hack_is_accessible_p (tree, tree); static void java_check_regular_methods (tree); +static void check_interface_throws_clauses (tree, tree); static void java_check_abstract_methods (tree); static void unreachable_stmt_error (tree); static tree find_expr_with_wfl (tree); @@ -6244,11 +6247,35 @@ java_check_methods (tree class_decl) CLASS_METHOD_CHECKED_P (TREE_TYPE (class_decl)) = 1; } +/* Like not_accessible_p, but doesn't refer to the current class at + all. */ +static bool +hack_is_accessible_p (tree member, tree from_where) +{ + int flags = get_access_flags_from_decl (member); + + if (from_where == DECL_CONTEXT (member) + || (flags & ACC_PUBLIC)) + return true; + + if ((flags & ACC_PROTECTED)) + { + if (inherits_from_p (from_where, DECL_CONTEXT (member))) + return true; + } + + if ((flags & ACC_PRIVATE)) + return false; + + /* Package private, or protected. */ + return in_same_package (TYPE_NAME (from_where), + TYPE_NAME (DECL_CONTEXT (member))); +} + /* Check all the methods of CLASS_DECL. Methods are first completed then checked according to regular method existence rules. If no constructor for CLASS_DECL were encountered, then build its declaration. */ - static void java_check_regular_methods (tree class_decl) { @@ -6298,7 +6325,8 @@ java_check_regular_methods (tree class_decl) } sig = build_java_argument_signature (TREE_TYPE (method)); - found = lookup_argument_method2 (class, DECL_NAME (method), sig); + found = lookup_argument_method_generic (class, DECL_NAME (method), sig, + SEARCH_SUPER | SEARCH_INTERFACE); /* Inner class can't declare static methods */ if (METHOD_STATIC (method) && !TOPLEVEL_CLASS_DECL_P (class_decl)) @@ -6357,7 +6385,7 @@ java_check_regular_methods (tree class_decl) continue; parse_error_context (method_wfl, - "%s methods can't be overriden. Method `%s' is %s in class `%s'", + "%s methods can't be overridden. Method `%s' is %s in class `%s'", (METHOD_FINAL (found) ? "Final" : "Static"), lang_printable_name (found, 0), (METHOD_FINAL (found) ? "final" : "static"), @@ -6371,7 +6399,7 @@ java_check_regular_methods (tree class_decl) { parse_error_context (method_wfl, - "Instance methods can't be overriden by a static method. Method `%s' is an instance method in class `%s'", + "Instance methods can't be overridden by a static method. Method `%s' is an instance method in class `%s'", lang_printable_name (found, 0), IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found))))); @@ -6380,7 +6408,7 @@ java_check_regular_methods (tree class_decl) /* - Overriding/hiding public must be public - Overriding/hiding protected must be protected or public - - If the overriden or hidden method has default (package) + - If the overridden or hidden method has default (package) access, then the overriding or hiding method must not be private; otherwise, a compile-time error occurs. If `found' belongs to an interface, things have been already @@ -6402,13 +6430,20 @@ java_check_regular_methods (tree class_decl) continue; } - /* Overriding methods must have compatible `throws' clauses on checked - exceptions, if any */ - check_throws_clauses (method, method_wfl, found); - - /* Inheriting multiple methods with the same signature. FIXME */ + /* Check this method against all the other implementations it + overrides. Here we only check the class hierarchy; the rest + of the checking is done later. If this method is just a + Miranda method, we can skip the check. */ + if (! METHOD_INVISIBLE (method)) + check_concrete_throws_clauses (class, method, DECL_NAME (method), sig); } + /* The above throws clause check only looked at superclasses. Now + we must also make sure that all methods declared in interfaces + have compatible throws clauses. FIXME: there are more efficient + ways to organize this checking; we should implement one. */ + check_interface_throws_clauses (class, class); + if (!TYPE_NVIRTUALS (class)) TYPE_METHODS (class) = nreverse (TYPE_METHODS (class)); @@ -6420,13 +6455,83 @@ java_check_regular_methods (tree class_decl) abort (); } -/* Return a nonzero value if the `throws' clause of METHOD (if any) - is incompatible with the `throws' clause of FOUND (if any). */ +/* Check to make sure that all the methods in all the interfaces + implemented by CLASS_DECL are compatible with the concrete + implementations available in CHECK_CLASS_DECL. */ +static void +check_interface_throws_clauses (tree check_class_decl, tree class_decl) +{ + for (; class_decl != NULL_TREE; class_decl = CLASSTYPE_SUPER (class_decl)) + { + tree bases = TYPE_BINFO_BASETYPES (class_decl); + int iface_len = TREE_VEC_LENGTH (bases) - 1; + int i; + + for (i = iface_len; i > 0; --i) + { + tree interface = BINFO_TYPE (TREE_VEC_ELT (bases, i)); + tree iface_method; + for (iface_method = TYPE_METHODS (interface); + iface_method != NULL_TREE; + iface_method = TREE_CHAIN (iface_method)) + { + tree sig, method; + + /* First look for a concrete method implemented or + inherited by this class. No need to search + interfaces here, since we're already looking through + all of them. */ + sig = build_java_argument_signature (TREE_TYPE (iface_method)); + method + = lookup_argument_method_generic (check_class_decl, + DECL_NAME (iface_method), + sig, SEARCH_VISIBLE); + /* If we don't find an implementation, that is ok. Any + potential errors from that are diagnosed elsewhere. + Also, multiple inheritance with conflicting throws + clauses is fine in the absence of a concrete + implementation. */ + if (method != NULL_TREE && !METHOD_ABSTRACT (method)) + { + tree method_wfl = DECL_FUNCTION_WFL (method); + check_throws_clauses (method, method_wfl, iface_method); + } + } + + /* Now check superinterfaces. */ + check_interface_throws_clauses (check_class_decl, interface); + } + } +} + +/* Check throws clauses of a method against the clauses of all the + methods it overrides. We do this by searching up the class + hierarchy, examining all matching accessible methods. */ +static void +check_concrete_throws_clauses (tree class, tree self_method, + tree name, tree signature) +{ + tree method = lookup_argument_method_generic (class, name, signature, + SEARCH_SUPER | SEARCH_VISIBLE); + while (method != NULL_TREE) + { + if (! METHOD_INVISIBLE (method) && hack_is_accessible_p (method, class)) + check_throws_clauses (self_method, DECL_FUNCTION_WFL (self_method), + method); + + method = lookup_argument_method_generic (DECL_CONTEXT (method), + name, signature, + SEARCH_SUPER | SEARCH_VISIBLE); + } +} + +/* Generate an error if the `throws' clause of METHOD (if any) is + incompatible with the `throws' clause of FOUND (if any). */ static void check_throws_clauses (tree method, tree method_wfl, tree found) { - tree mthrows, fthrows; + tree mthrows; /* Can't check these things with class loaded from bytecode. FIXME */ if (!CLASS_FROM_SOURCE_P (DECL_CONTEXT (found))) @@ -6435,28 +6540,31 @@ check_throws_clauses (tree method, tree method_wfl, tree found) for (mthrows = DECL_FUNCTION_THROWS (method); mthrows; mthrows = TREE_CHAIN (mthrows)) { + tree fthrows; + /* We don't verify unchecked expressions */ if (IS_UNCHECKED_EXCEPTION_P (TREE_VALUE (mthrows))) continue; /* Checked expression must be compatible */ for (fthrows = DECL_FUNCTION_THROWS (found); fthrows; fthrows = TREE_CHAIN (fthrows)) - if (inherits_from_p (TREE_VALUE (mthrows), TREE_VALUE (fthrows))) - break; + { + if (inherits_from_p (TREE_VALUE (mthrows), TREE_VALUE (fthrows))) + break; + } if (!fthrows) { parse_error_context - (method_wfl, "Invalid checked exception class `%s' in `throws' clause. The exception must be a subclass of an exception thrown by `%s' from class `%s'", + (method_wfl, "Invalid checked exception class `%s' in `throws' clause. The exception must be a subclass of an exception thrown by `%s' from class `%s'", IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (TREE_VALUE (mthrows)))), lang_printable_name (found, 0), IDENTIFIER_POINTER - (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found))))); + (DECL_NAME (TYPE_NAME (DECL_CONTEXT (found))))); } } } /* Check abstract method of interface INTERFACE */ - static void java_check_abstract_methods (tree interface_decl) { @@ -6470,8 +6578,7 @@ java_check_abstract_methods (tree interface_decl) if (check_method_redefinition (interface, method)) continue; - /* 3- Overriding is OK as far as we preserve the return type and - the thrown exceptions (FIXME) */ + /* 3- Overriding is OK as far as we preserve the return type. */ found = lookup_java_interface_method2 (interface, method); if (found) { @@ -10100,7 +10207,7 @@ patch_method_invocation (tree patch, tree primary, tree where, int from_super, tree this_arg = NULL_TREE; int is_array_clone_call = 0; - /* Should be overriden if everything goes well. Otherwise, if + /* Should be overridden if everything goes well. Otherwise, if something fails, it should keep this value. It stop the evaluation of a bogus assignment. See java_complete_tree, MODIFY_EXPR: for the reasons why we sometimes want to keep on @@ -11057,10 +11164,15 @@ find_most_specific_methods_list (tree list) /* If we have several and they're all abstract, just pick the closest one. */ - if (candidates > 0 && (candidates == abstract)) + if (candidates > 0 && candidates == abstract) { + /* FIXME: merge the throws clauses. There is no convenient way + to do this in gcj right now, since ideally we'd like to + introduce a new METHOD_DECL here, but that is really not + possible. */ new_list = nreverse (new_list); TREE_CHAIN (new_list) = NULL_TREE; + return new_list; } /* We have several (we couldn't find a most specific), all but one diff --git a/gcc/java/typeck.c b/gcc/java/typeck.c index 468de74cbb6..972cb8b3686 100644 --- a/gcc/java/typeck.c +++ b/gcc/java/typeck.c @@ -42,7 +42,7 @@ The Free Software Foundation is independent of Sun Microsystems, Inc. */ static tree convert_ieee_real_to_integer (tree, tree); static tree parse_signature_type (const unsigned char **, const unsigned char *); -static tree lookup_do (tree, tree, tree, tree, tree (*)(tree)); +static tree lookup_do (tree, int, tree, tree, tree (*)(tree)); static tree build_null_signature (tree); tree * type_map; @@ -687,124 +687,142 @@ set_java_signature (tree type, tree sig) #endif } -/* Search in class SEARCHED_CLASS (and its superclasses) for a method - matching METHOD_NAME and signature SIGNATURE. If SEARCHED_INTERFACE is - not NULL_TREE then first search its superinterfaces for a similar match. - Return the matched method DECL or NULL_TREE. SIGNATURE_BUILDER is - used on method candidates to build their (sometimes partial) - signature. */ - +/* Search in SEARCHED_CLASS and its superclasses for a method matching + METHOD_NAME and signature METHOD_SIGNATURE. This function will + only search for methods declared in the class hierarchy; interfaces + will not be considered. Returns NULL_TREE if the method is not + found. */ tree -lookup_argument_method (tree searched_class, tree method_name, tree method_signature) +lookup_argument_method (tree searched_class, tree method_name, + tree method_signature) { - return lookup_do (searched_class, NULL_TREE, method_name, method_signature, + return lookup_do (searched_class, 0, + method_name, method_signature, build_java_argument_signature); } -/* Search in class SEARCHED_CLASS (and its superclasses and - implemented interfaces) for a method matching METHOD_NAME and - argument signature METHOD_SIGNATURE. Return a FUNCTION_DECL on - success, or NULL_TREE if none found. (Contrast lookup_java_method, - which takes into account return type.) */ - +/* Like lookup_argument_method, but lets the caller set any flags + desired. */ tree -lookup_argument_method2 (tree searched_class, tree method_name, tree method_signature) +lookup_argument_method_generic (tree searched_class, tree method_name, + tree method_signature, int flags) { - return lookup_do (CLASSTYPE_SUPER (searched_class), searched_class, + return lookup_do (searched_class, flags, method_name, method_signature, build_java_argument_signature); } + /* Search in class SEARCHED_CLASS (and its superclasses) for a method matching METHOD_NAME and signature METHOD_SIGNATURE. Return a FUNCTION_DECL on success, or NULL_TREE if none found. (Contrast - lookup_argument_method, which ignores return type.) If + lookup_argument_method, which ignores return type.) If SEARCHED_CLASS is an interface, search it too. */ - tree -lookup_java_method (tree searched_class, tree method_name, tree method_signature) +lookup_java_method (tree searched_class, tree method_name, + tree method_signature) { - tree searched_interface; - - /* If this class is an interface class, search its superinterfaces - * first. A superinterface is not an interface's superclass: a super - * interface is implemented by the interface. */ - - searched_interface = (CLASS_INTERFACE (TYPE_NAME (searched_class)) ? - searched_class : NULL_TREE); - return lookup_do (searched_class, searched_interface, method_name, + return lookup_do (searched_class, SEARCH_INTERFACE, method_name, method_signature, build_java_signature); } -/* Return true iff CLASS (or its ancestors) has a method METHOD_NAME. */ - +/* Return true iff CLASS (or its ancestors) has a method METHOD_NAME. */ int has_method (tree class, tree method_name) { - return lookup_do (class, class, method_name, - NULL_TREE, build_null_signature) != NULL_TREE; + return lookup_do (class, SEARCH_INTERFACE, + method_name, NULL_TREE, + build_null_signature) != NULL_TREE; } /* Search in class SEARCHED_CLASS (and its superclasses) for a method - matching METHOD_NAME and signature SIGNATURE. Also search in - SEARCHED_INTERFACE (and its superinterfaces) for a similar match. + matching METHOD_NAME and signature SIGNATURE. FLAGS control some + parameters of the search. + + SEARCH_INTERFACE means also search interfaces and superinterfaces + of SEARCHED_CLASS. + + SEARCH_SUPER means skip SEARCHED_CLASS and start with its + superclass. + + SEARCH_ONLY_INTERFACE means don't search ordinary classes, but + instead only search interfaces and superinterfaces. + + SEARCH_VISIBLE means skip methods for which METHOD_INVISIBLE is + set. + Return the matched method DECL or NULL_TREE. SIGNATURE_BUILDER is used on method candidates to build their (sometimes partial) signature. */ - static tree -lookup_do (tree searched_class, tree searched_interface, tree method_name, +lookup_do (tree searched_class, int flags, tree method_name, tree signature, tree (*signature_builder) (tree)) { tree method; - - if (searched_interface) - { - int i; - int interface_len = - TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (searched_interface)) - 1; - - for (i = interface_len; i > 0; i--) - { - tree child = - TREE_VEC_ELT (TYPE_BINFO_BASETYPES (searched_interface), i); - tree iclass = BINFO_TYPE (child); - - /* If the superinterface hasn't been loaded yet, do so now. */ - if (CLASS_FROM_SOURCE_P (iclass)) - safe_layout_class (iclass); - else if (!CLASS_LOADED_P (iclass)) - load_class (iclass, 1); - - for (method = TYPE_METHODS (iclass); - method != NULL_TREE; method = TREE_CHAIN (method)) - { - tree method_sig = (*signature_builder) (TREE_TYPE (method)); - - if (DECL_NAME (method) == method_name && method_sig == signature) - return method; - } - - /* it could be defined in a supersuperinterface */ - if (CLASS_INTERFACE (TYPE_NAME (iclass))) - { - method = lookup_do (iclass, iclass, method_name, - signature, signature_builder); - if (method != NULL_TREE) - return method; - } - } - } + int first_time = 1; + + /* If the incoming class is an interface, then we will only return + a method declared in an interface context. */ + if (searched_class != NULL_TREE + && CLASS_INTERFACE (TYPE_NAME (searched_class))) + flags |= SEARCH_ONLY_INTERFACE; while (searched_class != NULL_TREE) { - for (method = TYPE_METHODS (searched_class); - method != NULL_TREE; method = TREE_CHAIN (method)) - { - tree method_sig = (*signature_builder) (TREE_TYPE (method)); - if (DECL_NAME (method) == method_name && method_sig == signature) - return method; - } + /* First search this class. If we're only searching the + superclass, skip this. */ + if (! ((flags & SEARCH_SUPER) && first_time)) + { + for (method = TYPE_METHODS (searched_class); + method != NULL_TREE; method = TREE_CHAIN (method)) + { + tree method_sig = (*signature_builder) (TREE_TYPE (method)); + if (DECL_NAME (method) == method_name && method_sig == signature) + { + /* If the caller requires a visible method, then we + skip invisible methods here. */ + if (! (flags & SEARCH_VISIBLE) + || ! METHOD_INVISIBLE (method)) + return method; + } + } + } + first_time = 0; + + /* Search interfaces, if required. */ + if ((flags & SEARCH_INTERFACE)) + { + int i; + int interface_len = + TREE_VEC_LENGTH (TYPE_BINFO_BASETYPES (searched_class)) - 1; + + for (i = interface_len; i > 0; i--) + { + tree child = + TREE_VEC_ELT (TYPE_BINFO_BASETYPES (searched_class), i); + tree iclass = BINFO_TYPE (child); + + /* If the superinterface hasn't been loaded yet, do so now. */ + if (CLASS_FROM_SOURCE_P (iclass)) + safe_layout_class (iclass); + else if (!CLASS_LOADED_P (iclass)) + load_class (iclass, 1); + + /* Note that we don't care about SEARCH_VISIBLE here, + since an interface can never have an invisible + method. */ + method = lookup_do (iclass, SEARCH_INTERFACE, + method_name, signature, signature_builder); + if (method != NULL_TREE) + return method; + } + } + + /* If we're only searching for interface methods, then we've + already searched all the superinterfaces. Our superclass is + Object, but we don't want to search that. */ + if ((flags & SEARCH_ONLY_INTERFACE)) + break; searched_class = CLASSTYPE_SUPER (searched_class); } |