static tree lookup_field_wrapper PARAMS ((tree, tree));
static int duplicate_declaration_error_p PARAMS ((tree, tree, tree));
static void register_fields PARAMS ((int, tree, tree));
-static tree parser_qualified_classname PARAMS ((int, tree));
+static tree parser_qualified_classname PARAMS ((tree));
static int parser_check_super PARAMS ((tree, tree, tree));
static int parser_check_super_interface PARAMS ((tree, tree, tree));
static void check_modifiers_consistency PARAMS ((int));
simple_name:
identifier /* Default rule */
+ {
+ if (strchr (IDENTIFIER_POINTER (EXPR_WFL_NODE ($$)), '$'))
+ parse_error_context ($$, "Invalid type name `%s'",
+ IDENTIFIER_POINTER (EXPR_WFL_NODE ($$)));
+ }
;
qualified_name:
{
tree acc = NULL_TREE, decl = NULL_TREE, ptr;
- for(qual = EXPR_WFL_QUALIFICATION (cl); qual && !decl;
- qual = TREE_CHAIN (qual))
+ for (qual = EXPR_WFL_QUALIFICATION (cl); qual && !decl;
+ qual = TREE_CHAIN (qual))
{
acc = merge_qualified_name (acc,
EXPR_WFL_NODE (TREE_PURPOSE (qual)));
else
qual = build_tree_list (build_expr_wfl (name, NULL, 0, 0), NULL_TREE);
- return find_as_inner_class_do (qual, enclosing);
+ if (!(to_return = find_as_inner_class_do (qual, enclosing)))
+ {
+ /* It might be the case that the enclosing class was loaded as
+ bytecode, in which case it will be missing the
+ DECL_INNER_CLASS_LIST. We build a fully qualified internal
+ innerclass name and we try to load it. */
+ tree fqin = identifier_subst (name, "", '.', '$', "");
+ tree ptr;
+ BUILD_PTR_FROM_NAME (ptr, fqin);
+ to_return = resolve_class (NULL_TREE, ptr, NULL_TREE, cl);
+ }
+ return to_return;
}
/* We go inside the list of sub classes and try to find a way
tree id, super;
{
tree raw_name = EXPR_WFL_NODE (id);
- tree q_name = parser_qualified_classname (flags & ACC_STATIC, raw_name);
+ tree q_name = parser_qualified_classname (raw_name);
tree decl = IDENTIFIER_CLASS_VALUE (q_name);
EXPR_WFL_NODE (id) = q_name; /* Keep source location, even if refined. */
tree class_id, decl;
tree super_decl_type;
- class_id = parser_qualified_classname (0, raw_name);
+ class_id = parser_qualified_classname (raw_name);
decl = IDENTIFIER_CLASS_VALUE (class_id);
EXPR_WFL_NODE (id) = class_id;
CLASS_COMPLETE_P (decl) = 1;
add_superinterfaces (decl, interfaces);
- /* If the class is a top level inner class, install an alias. */
- if (INNER_CLASS_DECL_P (decl) && CLASS_STATIC (decl))
- {
- tree alias = parser_qualified_classname (1, raw_name);
- IDENTIFIER_GLOBAL_VALUE (alias) = decl;
- }
-
/* Add the private this$<n> field, Replicate final locals still in
scope as private final fields mangled like val$<local_name>.
This doesn't not occur for top level (static) inner classes. */
&& !CLASS_INTERFACE (TYPE_NAME (this_class)))
parse_error_context
(id, "Class `%s' must be declared abstract to define abstract method `%s'",
- IDENTIFIER_POINTER (DECL_NAME (ctxp->current_parsed_class)),
+ IDENTIFIER_POINTER (DECL_NAME (GET_CPC ())),
IDENTIFIER_POINTER (EXPR_WFL_NODE (id)));
}
qualification from the current package definition. */
static tree
-parser_qualified_classname (is_static, name)
- int is_static;
+parser_qualified_classname (name)
tree name;
{
tree nested_class_name;
- if (!is_static
- && (nested_class_name = maybe_make_nested_class_name (name)))
+ if ((nested_class_name = maybe_make_nested_class_name (name)))
return nested_class_name;
if (ctxp->package)
if (!decl)
complete_class_report_errors (dep);
- check_inner_class_access (decl, JDEP_ENCLOSING (dep), JDEP_WFL (dep));
+ if (PURE_INNER_CLASS_DECL_P (decl))
+ check_inner_class_access (decl, JDEP_ENCLOSING (dep), JDEP_WFL (dep));
return decl;
}
if ((new_class_decl = find_as_inner_class (enclosing, class_type, cl)))
return new_class_decl;
+ /* Explore enclosing contexts. */
+ while (INNER_CLASS_DECL_P (enclosing))
+ {
+ enclosing = DECL_CONTEXT (enclosing);
+ if ((new_class_decl = find_as_inner_class (enclosing,
+ class_type, cl)))
+ return new_class_decl;
+ }
+
/* Now go to the upper classes, bail out if necessary. */
enclosing = CLASSTYPE_SUPER (TREE_TYPE (enclosing));
if (!enclosing || enclosing == object_type_node)
}
if (TREE_CODE (enclosing) == IDENTIFIER_NODE)
- {
- BUILD_PTR_FROM_NAME (name, enclosing);
- }
+ BUILD_PTR_FROM_NAME (name, enclosing);
else
name = enclosing;
enclosing = do_resolve_class (NULL, name, NULL, NULL);
}
static void
-check_inner_class_access (decl, enclosing_type, cl)
- tree decl, enclosing_type, cl;
+check_inner_class_access (decl, enclosing_decl, cl)
+ tree decl, enclosing_decl, cl;
{
+ int access = 0;
+
/* We don't issue an error message when CL is null. CL can be null
- as a result of processing a JDEP crafted by
- source_start_java_method for the purpose of patching its parm
- decl. But the error would have been already trapped when fixing
- the method's signature. */
- if (!(cl && PURE_INNER_CLASS_DECL_P (decl) && CLASS_PRIVATE (decl))
- || (PURE_INNER_CLASS_DECL_P (enclosing_type)
- && common_enclosing_context_p (TREE_TYPE (enclosing_type),
- TREE_TYPE (decl)))
- || enclosing_context_p (TREE_TYPE (enclosing_type), TREE_TYPE (decl)))
+ as a result of processing a JDEP crafted by source_start_java_method
+ for the purpose of patching its parm decl. But the error would
+ have been already trapped when fixing the method's signature.
+ DECL can also be NULL in case of earlier errors. */
+ if (!decl || !cl)
return;
- parse_error_context (cl, "Can't access nested %s %s. Only public classes and interfaces in other packages can be accessed",
+ /* We grant access to private and protected inner classes if the
+ location from where we're trying to access DECL is an enclosing
+ context for DECL or if both have a common enclosing context. */
+ if (CLASS_PRIVATE (decl))
+ access = 1;
+ if (CLASS_PROTECTED (decl))
+ access = 2;
+ if (!access)
+ return;
+
+ if (common_enclosing_context_p (TREE_TYPE (enclosing_decl),
+ TREE_TYPE (decl))
+ || enclosing_context_p (TREE_TYPE (enclosing_decl),
+ TREE_TYPE (decl)))
+ return;
+
+ parse_error_context (cl, "Can't access %s nested %s %s. Only public classes and interfaces in other packages can be accessed",
+ (access == 1 ? "private" : "protected"),
(CLASS_INTERFACE (decl) ? "interface" : "class"),
lang_printable_name (decl, 0));
}
/* We build the assignment expression that will initialize the
field to its value. There are strict rules on static
initializers (8.5). FIXME */
- if (TREE_CODE (stmt) != BLOCK)
+ if (TREE_CODE (stmt) != BLOCK && stmt != empty_stmt_node)
stmt = build_debugable_stmt (EXPR_WFL_LINECOL (stmt), stmt);
java_method_add_stmt (mdecl, stmt);
}
for (sdecl = TYPE_METHODS (class); sdecl; sdecl = TREE_CHAIN (sdecl))
if (DECL_CONSTRUCTOR_P (sdecl))
{
+ tree m_arg_type;
tree arg_type = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (sdecl)));
if (super_inner)
arg_type = TREE_CHAIN (arg_type);
- for (; (arg_type != end_params_node
- && mdecl_arg_type != end_params_node);
+ for (m_arg_type = mdecl_arg_type;
+ (arg_type != end_params_node
+ && m_arg_type != end_params_node);
arg_type = TREE_CHAIN (arg_type),
- mdecl_arg_type = TREE_CHAIN (mdecl_arg_type))
- if (TREE_VALUE (arg_type) != TREE_VALUE (mdecl_arg_type))
+ m_arg_type = TREE_CHAIN (m_arg_type))
+ if (TREE_VALUE (arg_type) != TREE_VALUE (m_arg_type))
break;
- if (arg_type == end_params_node &&
- mdecl_arg_type == end_params_node)
+ if (arg_type == end_params_node && m_arg_type == end_params_node)
return 0;
}
}
/* Resolve the LENGTH field of an array here */
if (DECL_P (decl) && DECL_NAME (decl) == length_identifier_node
- && TYPE_ARRAY_P (type_found)
+ && type_found && TYPE_ARRAY_P (type_found)
&& ! flag_emit_class_files && ! flag_emit_xref)
{
tree length = build_java_array_length_access (where_found);
if (!type_found)
type_found = DECL_CONTEXT (decl);
is_static = JDECL_P (decl) && FIELD_STATIC (decl);
- if (FIELD_FINAL (decl)
+ if (FIELD_FINAL (decl) && FIELD_STATIC (decl)
&& JPRIMITIVE_TYPE_P (TREE_TYPE (decl))
&& DECL_INITIAL (decl))
{
- field_ref = java_complete_tree (DECL_INITIAL (decl));
+ /* When called on a FIELD_DECL of the right (primitive)
+ type, java_complete_tree will try to substitue the decl
+ for it's initial value. */
+ field_ref = java_complete_tree (decl);
static_final_found = 1;
}
else
*where_found = decl = current_this;
*type_found = type = QUAL_DECL_TYPE (decl);
}
- /* We're trying to access the this from somewhere else... */
+ /* We're trying to access the this from somewhere else. Make sure
+ it's allowed before doing so. */
else
{
+ if (!enclosing_context_p (type, current_class))
+ {
+ char *p = xstrdup (lang_printable_name (type, 0));
+ parse_error_context (qual_wfl, "Can't use variable `%s.this': type `%s' isn't an outer type of type `%s'",
+ p, p,
+ lang_printable_name (current_class, 0));
+ free (p);
+ return 1;
+ }
*where_found = decl = build_current_thisn (type);
from_qualified_this = 1;
}
field_decl = lookup_field_wrapper (type,
EXPR_WFL_NODE (qual_wfl));
+
+ /* Maybe what we're trying to access an inner class. */
+ if (!field_decl)
+ {
+ tree ptr, inner_decl;
+
+ BUILD_PTR_FROM_NAME (ptr, EXPR_WFL_NODE (qual_wfl));
+ inner_decl = resolve_class (decl, ptr, NULL_TREE, qual_wfl);
+ if (inner_decl)
+ {
+ check_inner_class_access (inner_decl, decl, qual_wfl);
+ type = TREE_TYPE (inner_decl);
+ decl = inner_decl;
+ from_type = 1;
+ continue;
+ }
+ }
+
if (field_decl == NULL_TREE)
{
parse_error_context
}
/* 6.6 Qualified name and access control. Returns 1 if MEMBER (a decl)
- can't be accessed from REFERENCE (a record type). */
+ can't be accessed from REFERENCE (a record type). This should be
+ used when decl is a field or a method.*/
static int
not_accessible_p (reference, member, from_super)
{
int access_flag = get_access_flags_from_decl (member);
+ /* Inner classes are processed by check_inner_class_access */
+ if (INNER_CLASS_TYPE_P (reference))
+ return 0;
+
/* Access always granted for members declared public */
if (access_flag & ACC_PUBLIC)
return 0;
return 0;
/* Otherwise, access is granted if occuring from the class where
- member is declared or a subclass of it */
+ member is declared or a subclass of it. Find the right
+ context to perform the check */
+ if (PURE_INNER_CLASS_TYPE_P (reference))
+ {
+ while (INNER_CLASS_TYPE_P (reference))
+ {
+ if (inherits_from_p (reference, DECL_CONTEXT (member)))
+ return 0;
+ reference = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (reference)));
+ }
+ }
if (inherits_from_p (reference, DECL_CONTEXT (member)))
return 0;
return 1;
/* Check access on private members. Access is granted only if it
occurs from within the class in which it is declared. Exceptions
- are accesses from inner-classes. This section is probably not
- complete. FIXME */
+ are accesses from inner-classes. */
if (access_flag & ACC_PRIVATE)
return (current_class == DECL_CONTEXT (member) ? 0 :
(INNER_CLASS_TYPE_P (current_class) ? 0 : 1));
maybe_use_access_method returns a non zero value if the
this_arg has to be moved into the (then generated) stub
- argument list. In the mean time, the selected function
+ argument list. In the meantime, the selected function
might have be replaced by a generated stub. */
if (maybe_use_access_method (is_super_init, &list, &this_arg))
args = tree_cons (NULL_TREE, this_arg, args);
if (non_static_context)
{
ctx = TREE_TYPE (DECL_CONTEXT (TYPE_NAME (current_class)));
- if (ctx == DECL_CONTEXT (md))
+ if (inherits_from_p (ctx, DECL_CONTEXT (md)))
{
ta = build_current_thisn (current_class);
ta = build_wfl_node (ta);
while (type)
{
maybe_build_thisn_access_method (type);
- if (type == DECL_CONTEXT (md))
+ if (inherits_from_p (type, DECL_CONTEXT (md)))
{
ta = build_access_to_thisn (ctx, type, 0);
break;
int lc;
tree class, name, arglist;
{
- static int object_done = 0;
+ static struct hash_table t, *searched_classes = NULL;
+ static int search_not_done = 0;
tree list = NULL_TREE, all_list = NULL_TREE;
+ /* Check the hash table to determine if this class has been searched
+ already. */
+ if (searched_classes)
+ {
+ if (hash_lookup (searched_classes,
+ (const hash_table_key) class, FALSE, NULL))
+ return NULL;
+ }
+ else
+ {
+ hash_table_init (&t, hash_newfunc, java_hash_hash_tree_node,
+ java_hash_compare_tree_node);
+ searched_classes = &t;
+ }
+
+ search_not_done++;
+ hash_lookup (searched_classes,
+ (const hash_table_key) class, TRUE, NULL);
+
if (!CLASS_LOADED_P (class) && !CLASS_FROM_SOURCE_P (class))
{
load_class (class, 1);
if (TREE_CODE (TYPE_NAME (class)) == TYPE_DECL
&& CLASS_INTERFACE (TYPE_NAME (class)))
{
- static struct hash_table t, *searched_interfaces = NULL;
- static int search_not_done = 0;
int i, n;
tree basetype_vec = TYPE_BINFO_BASETYPES (class);
-
- /* Search in the hash table, otherwise create a new one if
- necessary and insert the new entry. */
-
- if (searched_interfaces)
- {
- if (hash_lookup (searched_interfaces,
- (const hash_table_key) class, FALSE, NULL))
- return NULL;
- }
- else
- {
- hash_table_init (&t, hash_newfunc, java_hash_hash_tree_node,
- java_hash_compare_tree_node);
- searched_interfaces = &t;
- }
-
- hash_lookup (searched_interfaces,
- (const hash_table_key) class, TRUE, NULL);
-
search_applicable_methods_list (lc, TYPE_METHODS (class),
name, arglist, &list, &all_list);
n = TREE_VEC_LENGTH (basetype_vec);
tree t = BINFO_TYPE (TREE_VEC_ELT (basetype_vec, i));
tree rlist;
- search_not_done++;
rlist = find_applicable_accessible_methods_list (lc, t, name,
arglist);
list = chainon (rlist, list);
- search_not_done--;
- }
-
- /* We're done. Reset the searched interfaces list and finally search
- java.lang.Object */
- if (!search_not_done)
- {
- if (!object_done)
- search_applicable_methods_list (lc,
- TYPE_METHODS (object_type_node),
- name, arglist, &list, &all_list);
- hash_table_free (searched_interfaces);
- searched_interfaces = NULL;
}
}
/* Search classes */
{
tree basetype_vec = TYPE_BINFO_BASETYPES (sc);
int n = TREE_VEC_LENGTH (basetype_vec), i;
- object_done = 1;
for (i = 1; i < n; i++)
{
tree t = BINFO_TYPE (TREE_VEC_ELT (basetype_vec, i));
list = chainon (rlist, list);
}
}
- object_done = 0;
}
/* Search enclosing context of inner classes before looking
else
class = sc;
- for (class = (lc ? NULL_TREE : CLASSTYPE_SUPER (class));
- class; class = CLASSTYPE_SUPER (class))
- search_applicable_methods_list (lc, TYPE_METHODS (class),
- name, arglist, &list, &all_list);
+ /* Search superclass */
+ if (!lc && CLASSTYPE_SUPER (class) != NULL_TREE)
+ {
+ tree rlist;
+ class = CLASSTYPE_SUPER (class);
+ rlist = find_applicable_accessible_methods_list (lc, class,
+ name, arglist);
+ list = chainon (rlist, list);
+ }
+ }
+
+ search_not_done--;
+
+ /* We're done. Reset the searched classes list and finally search
+ java.lang.Object if it wasn't searched already. */
+ if (!search_not_done)
+ {
+ if (!lc
+ && TYPE_METHODS (object_type_node)
+ && !hash_lookup (searched_classes,
+ (const hash_table_key) object_type_node,
+ FALSE, NULL))
+ {
+ search_applicable_methods_list (lc,
+ TYPE_METHODS (object_type_node),
+ name, arglist, &list, &all_list);
+ }
+ hash_table_free (searched_classes);
+ searched_classes = NULL;
}
/* Either return the list obtained or all selected (but
return (!list ? all_list : list);
}
-/* Effectively search for the approriate method in method */
+/* Effectively search for the appropriate method in method */
static void
search_applicable_methods_list (lc, method, name, arglist, list, all_list)
*all_list = tree_cons (NULL_TREE, method, *list);
}
}
-}
+}
/* 15.11.2.2 Choose the Most Specific Method */
for (method = list; method; method = TREE_CHAIN (method))
{
+ tree method_v, current_v;
/* Don't test a method against itself */
if (method == current)
continue;
- /* Compare arguments and location where method where declared */
- if (argument_types_convertible (TREE_VALUE (method),
- TREE_VALUE (current))
- && valid_method_invocation_conversion_p
- (DECL_CONTEXT (TREE_VALUE (method)),
- DECL_CONTEXT (TREE_VALUE (current))))
+ method_v = TREE_VALUE (method);
+ current_v = TREE_VALUE (current);
+
+ /* Compare arguments and location where methods where declared */
+ if (argument_types_convertible (method_v, current_v))
{
- int v = ++DECL_SPECIFIC_COUNT (TREE_VALUE (current));
- max = (v > max ? v : max);
+ if (valid_method_invocation_conversion_p
+ (DECL_CONTEXT (method_v), DECL_CONTEXT (current_v))
+ || (INNER_CLASS_TYPE_P (DECL_CONTEXT (current_v))
+ && enclosing_context_p (DECL_CONTEXT (method_v),
+ DECL_CONTEXT (current_v))))
+ {
+ int v = (DECL_SPECIFIC_COUNT (current_v) +=
+ (INNER_CLASS_TYPE_P (DECL_CONTEXT (current_v)) ? 2 : 1));
+ max = (v > max ? v : max);
+ }
}
}
}
tree node;
{
node = java_complete_lhs (node);
- if (TREE_CODE (node) == VAR_DECL && FIELD_STATIC (node)
- && FIELD_FINAL (node) && DECL_INITIAL (node) != NULL_TREE
+ if (JDECL_P (node) && FIELD_STATIC (node) && FIELD_FINAL (node)
+ && DECL_INITIAL (node) != NULL_TREE
&& !flag_emit_xref)
{
tree value = DECL_INITIAL (node);
else
node = patch_switch_statement (node);
- if (TREE_OPERAND (node, 0) == error_mark_node)
+ if (node == error_mark_node || TREE_OPERAND (node, 0) == error_mark_node)
nn = error_mark_node;
else
{
(type == string_ptr_type_node && ! flag_emit_class_files))
return empty_stmt_node;
}
- DECL_INITIAL (nn) = NULL_TREE;
+ if (! flag_emit_class_files)
+ DECL_INITIAL (nn) = NULL_TREE;
}
wfl_op2 = TREE_OPERAND (node, 1);
if (TYPE_CLASS_P (dest))
return (source == dest
|| inherits_from_p (source, dest)
- || enclosing_context_p (source, dest)
|| (cast && inherits_from_p (dest, source)));
if (TYPE_INTERFACE_P (dest))
{
{
if (unresolved_type_p (type, NULL))
{
- tree type_decl = resolve_no_layout (EXPR_WFL_NODE (type), NULL_TREE);
+ tree type_decl = resolve_no_layout (EXPR_WFL_NODE (type), type);
if (!type_decl)
{
parse_error_context (type,
tree op0, op1, val;
enum tree_code code = TREE_CODE (node);
- if (code == STRING_CST)
+ if (code == STRING_CST || code == INTEGER_CST || code == REAL_CST)
return node;
- if (code == INTEGER_CST || code == REAL_CST)
- return convert (TREE_TYPE (context), node);
-
switch (code)
{
case PLUS_EXPR: