-
Notifications
You must be signed in to change notification settings - Fork 273
/
Copy pathresolve_inherited_component.cpp
150 lines (132 loc) · 5.55 KB
/
resolve_inherited_component.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
/*******************************************************************\
Module: GOTO Program Utilities
Author: Diffblue Ltd.
\*******************************************************************/
#include "resolve_inherited_component.h"
#include <util/range.h>
#include <util/std_types.h>
#include <util/symbol_table_base.h>
/// See the operator() method comment
/// \param symbol_table: The symbol table to resolve the component against
resolve_inherited_componentt::resolve_inherited_componentt(
const symbol_table_baset &symbol_table)
: symbol_table(symbol_table)
{
}
/// Given a class and a component, identify the concrete field or method it is
/// resolved to. For example, a reference Child.abc refers to Child's method or
/// field if it exists, or else Parent.abc, and so on regarding Parent's
/// ancestors. If none are found, an empty string will be returned.
/// \param class_id: The name of the class the function is being called on
/// \param component_name: The base name of the component (i.e. without the
/// class specifier)
/// \param include_interfaces: If true, consider inheritance from interfaces
/// (parent types other than the first listed)
/// \param user_filter: Predicate that should return true for symbols that can
/// be returned. Those for which it returns false will be ignored.
/// \return The concrete component that has been resolved
std::optional<resolve_inherited_componentt::inherited_componentt>
resolve_inherited_componentt::operator()(
const irep_idt &class_id,
const irep_idt &component_name,
bool include_interfaces,
const std::function<bool(const symbolt &)> user_filter)
{
PRECONDITION(!class_id.empty());
PRECONDITION(!component_name.empty());
std::vector<irep_idt> classes_to_visit;
classes_to_visit.push_back(class_id);
while(!classes_to_visit.empty())
{
irep_idt current_class = classes_to_visit.back();
classes_to_visit.pop_back();
const irep_idt &full_component_identifier=
build_full_component_identifier(current_class, component_name);
const symbolt *symbol = symbol_table.lookup(full_component_identifier);
if(symbol && user_filter(*symbol))
{
return inherited_componentt(current_class, component_name);
}
const auto current_class_symbol_it =
symbol_table.symbols.find(current_class);
if(current_class_symbol_it != symbol_table.symbols.end())
{
const auto parents =
make_range(to_struct_type(current_class_symbol_it->second.type).bases())
.map([](const struct_typet::baset &base) {
return base.type().get_identifier();
});
if(include_interfaces)
{
classes_to_visit.insert(
classes_to_visit.end(), parents.begin(), parents.end());
}
else
{
if(!parents.empty())
classes_to_visit.push_back(*parents.begin());
}
}
}
return {};
}
/// Build a component name as found in a GOTO symbol table equivalent to the
/// name of a concrete component component_name on class class_name
/// \param component_name: The name of the component
/// \param class_name: The class the implementation would be found on.
/// \return A name for looking up in the symbol table for classes `class_name`'s
/// component `component_name`
irep_idt resolve_inherited_componentt::build_full_component_identifier(
const irep_idt &class_name, const irep_idt &component_name)
{
// Verify the parameters are called in the correct order.
PRECONDITION(id2string(class_name).find("::")!=std::string::npos);
PRECONDITION(id2string(component_name).find("::")==std::string::npos);
return id2string(class_name)+'.'+id2string(component_name);
}
/// Get the full name of this function
/// \return The symbol name for this function call
irep_idt resolve_inherited_componentt::inherited_componentt::
get_full_component_identifier() const
{
return resolve_inherited_componentt::build_full_component_identifier(
class_identifier, component_identifier);
}
/// Given a class and a component, identify the concrete method it is
/// resolved to. For example, a reference Child.abc refers to Child's method or
/// field if it exists, or else Parent.abc, and so on regarding Parent's
/// ancestors. If none are found, an empty string will be returned.
/// This looks first for non-abstract methods inherited from the first base
/// (i.e., for Java the superclass), then for non-abstract methods inherited
/// otherwise (for Java, interface default methods), then for any abstract
/// declaration.
/// \param classname: The name of the class the function is being called on
/// \param call_basename: The base name of the component (i.e. without the
/// class specifier)
/// \param symbol_table: Global symbol table
/// \return The concrete component that has been resolved
std::optional<resolve_inherited_componentt::inherited_componentt>
get_inherited_method_implementation(
const irep_idt &call_basename,
const irep_idt &classname,
const symbol_table_baset &symbol_table)
{
resolve_inherited_componentt call_resolver{symbol_table};
auto exclude_abstract_methods = [&](const symbolt &symbol) {
return !symbol.type.get_bool(ID_C_abstract);
};
auto resolved_call =
call_resolver(classname, call_basename, false, exclude_abstract_methods);
if(!resolved_call)
{
// Check for a default implementation:
resolved_call =
call_resolver(classname, call_basename, true, exclude_abstract_methods);
}
if(!resolved_call)
{
// Finally accept any abstract definition, which will likely get stubbed:
resolved_call = call_resolver(classname, call_basename, true);
}
return resolved_call;
}