Skip to content

Commit 168c2a8

Browse files
committed
Generalise get_inherited_method
This can now resolve fields too, and is moved into java_utils so it can be used more widely.
1 parent f3160e1 commit 168c2a8

File tree

3 files changed

+90
-49
lines changed

3 files changed

+90
-49
lines changed

src/java_bytecode/java_bytecode_convert_method.cpp

Lines changed: 3 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -2806,55 +2806,9 @@ void java_bytecode_convert_method(
28062806
bool java_bytecode_convert_methodt::is_method_inherited(
28072807
const irep_idt &classname, const irep_idt &methodid) const
28082808
{
2809-
resolve_inherited_componentt call_resolver(symbol_table);
2810-
const resolve_inherited_componentt::inherited_componentt resolved_call =
2811-
call_resolver(classname, methodid);
2812-
2813-
// resolved_call is a pair (class-name, method-name) found by walking the
2814-
// chain of class inheritance (not interfaces!) and stopping on the first
2815-
// class that contains a method of equal name and type to `methodid`
2816-
2817-
if(resolved_call.is_valid())
2818-
{
2819-
const symbolt &function_symbol=
2820-
*symbol_table.lookup(resolved_call.get_full_component_identifier());
2821-
2822-
INVARIANT(function_symbol.type.id()==ID_code, "Function must be code");
2823-
2824-
const auto &access=function_symbol.type.get(ID_access);
2825-
if(access==ID_public || access==ID_protected)
2826-
{
2827-
// since the method is public, it is a public method of `classname`, it is
2828-
// inherited
2829-
return true;
2830-
}
2831-
2832-
// methods with the default access modifier are only
2833-
// accessible within the same package.
2834-
if(access==ID_default)
2835-
{
2836-
const std::string &class_package=
2837-
java_class_to_package(id2string(classname));
2838-
const std::string &method_package=
2839-
java_class_to_package(id2string(resolved_call.get_class_identifier()));
2840-
return method_package==class_package;
2841-
}
2842-
2843-
if(access==ID_private)
2844-
{
2845-
// We return false because the method found by the call_resolver above
2846-
// proves that `methodid` cannot be inherited (assuming that the original
2847-
// Java code compiles). This is because, as we walk the inheritance chain
2848-
// for `classname` from Object to `classname`, a method can only become
2849-
// "more accessible". So, if the last occurrence is private, all others
2850-
// before must be private as well, and none is inherited in `classname`.
2851-
return false;
2852-
}
2853-
2854-
INVARIANT(false, "Unexpected access modifier.");
2855-
}
2856-
2857-
return false;
2809+
resolve_inherited_componentt::inherited_componentt inherited_method =
2810+
get_inherited_component(classname, methodid, classname, symbol_table);
2811+
return inherited_method.is_valid();
28582812
}
28592813

28602814
/// create temporary variables if a write instruction can have undesired side-

src/java_bytecode/java_utils.cpp

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,3 +325,82 @@ std::string pretty_print_java_type(const std::string &fqn_java_type)
325325
result = result.substr(java_lang_string.length());
326326
return result;
327327
}
328+
329+
/// Finds an inherited component (method or field), taking component visibility
330+
/// into account.
331+
/// \param component_class_id: class to start searching from. For example, if
332+
/// trying to resolve a reference to A.b, component_class_id is "A".
333+
/// \param component_name: component basename to search for. If searching for
334+
/// A.b, this is "b".
335+
/// \param user_class_id: class identifier making reference to the sought
336+
/// component. The user class is relevant when determining whether package-
337+
/// scoped components are visible from a particular use site.
338+
/// \param symbol_table: global symbol table.
339+
/// \return the concrete component referred to if any is found, or an invalid
340+
/// resolve_inherited_componentt::inherited_componentt otherwise.
341+
resolve_inherited_componentt::inherited_componentt get_inherited_component(
342+
const irep_idt &component_class_id,
343+
const irep_idt &component_name,
344+
const irep_idt &user_class_id,
345+
const symbol_tablet &symbol_table)
346+
{
347+
resolve_inherited_componentt component_resolver(symbol_table);
348+
const resolve_inherited_componentt::inherited_componentt resolved_component =
349+
component_resolver(component_class_id, component_name);
350+
351+
// resolved_component is a pair (class-name, component-name) found by walking
352+
// the chain of class inheritance (not interfaces!) and stopping on the first
353+
// class that contains a component of equal name and type to `component_name`
354+
355+
if(resolved_component.is_valid())
356+
{
357+
// Directly defined on the class referred to?
358+
if(component_class_id == resolved_component.get_class_identifier())
359+
return resolved_component;
360+
361+
// No, may be inherited from some parent class; check it is visible:
362+
const symbolt &component_symbol=
363+
*symbol_table.lookup(resolved_component.get_full_component_identifier());
364+
365+
const auto &access=component_symbol.type.get(ID_access);
366+
if(access==ID_public || access==ID_protected)
367+
{
368+
// since the component is public, it is inherited
369+
return resolved_component;
370+
}
371+
372+
// components with the default access modifier are only
373+
// accessible within the same package.
374+
if(access==ID_default)
375+
{
376+
const std::string &class_package=
377+
java_class_to_package(id2string(component_class_id));
378+
const std::string &component_package=
379+
java_class_to_package(
380+
id2string(
381+
resolved_component.get_class_identifier()));
382+
if(component_package == class_package)
383+
return resolved_component;
384+
else
385+
return resolve_inherited_componentt::inherited_componentt();
386+
}
387+
388+
if(access==ID_private)
389+
{
390+
// We return not-found because the component found by the
391+
// component_resolver above proves that `component_name` cannot be
392+
// inherited (assuming that the original Java code compiles). This is
393+
// because, as we walk the inheritance chain for `classname` from Object
394+
// to `classname`, a component can only become "more accessible". So, if
395+
// the last occurrence is private, all others before must be private as
396+
// well, and none is inherited in `classname`.
397+
return resolve_inherited_componentt::inherited_componentt();
398+
}
399+
400+
UNREACHABLE; // Unexpected access modifier
401+
}
402+
else
403+
{
404+
return resolve_inherited_componentt::inherited_componentt();
405+
}
406+
}

src/java_bytecode/java_utils.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ Author: Daniel Kroening, [email protected]
1313
#include <util/std_expr.h>
1414
#include <util/symbol_table.h>
1515

16+
#include <goto-programs/resolve_inherited_component.h>
17+
1618
bool java_is_array_type(const typet &type);
1719

1820
void generate_class_stub(
@@ -96,4 +98,10 @@ irep_idt strip_java_namespace_prefix(const irep_idt &to_strip);
9698

9799
std::string pretty_print_java_type(const std::string &fqn_java_type);
98100

101+
resolve_inherited_componentt::inherited_componentt get_inherited_component(
102+
const irep_idt &component_class_id,
103+
const irep_idt &component_name,
104+
const irep_idt &user_class_id,
105+
const symbol_tablet &symbol_table);
106+
99107
#endif // CPROVER_JAVA_BYTECODE_JAVA_UTILS_H

0 commit comments

Comments
 (0)