Skip to content

Commit 819c683

Browse files
author
Thomas Kiley
authored
Merge pull request #2493 from jeannielynnmoulton/jeannie/InnerClasses
[TG-3694] Parse and store inner class information
2 parents 6e554d9 + 5350133 commit 819c683

32 files changed

+476
-0
lines changed

jbmc/src/java_bytecode/java_bytecode_convert_class.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,7 @@ void java_bytecode_convert_classt::convert(
276276
class_type.set(ID_interface, c.is_interface);
277277
class_type.set(ID_synthetic, c.is_synthetic);
278278
class_type.set_final(c.is_final);
279+
class_type.set_is_inner_class(c.is_inner_class);
279280
if(c.is_enum)
280281
{
281282
if(max_array_length != 0 && c.enum_elements > max_array_length)

jbmc/src/java_bytecode/java_bytecode_parse_tree.h

+1
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ class java_bytecode_parse_treet
217217
bool is_interface = false;
218218
bool is_synthetic = false;
219219
bool is_annotation = false;
220+
bool is_inner_class = false;
220221
bool attribute_bootstrapmethods_read = false;
221222
size_t enum_elements=0;
222223

jbmc/src/java_bytecode/java_bytecode_parser.cpp

+78
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,8 @@ class java_bytecode_parsert:public parsert
119119
void rfields(classt &parsed_class);
120120
void rmethods(classt &parsed_class);
121121
void rmethod(classt &parsed_class);
122+
void
123+
rinner_classes_attribute(classt &parsed_class, const u4 &attribute_length);
122124
void rclass_attribute(classt &parsed_class);
123125
void rRuntimeAnnotation_attribute(annotationst &);
124126
void rRuntimeAnnotation(annotationt &);
@@ -1576,6 +1578,77 @@ void java_bytecode_parsert::relement_value_pair(
15761578
}
15771579
}
15781580

1581+
/// Corresponds to the element_value structure
1582+
/// Described in Java 8 specification 4.7.6
1583+
/// https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.6
1584+
/// Parses the InnerClasses attribute for the current parsed class,
1585+
/// which contains an array of information about its inner classes. We are
1586+
/// interested in getting information only for inner classes, which is
1587+
/// determined by checking if the parsed class matches any of the inner classes
1588+
/// in its inner class array. If the parsed class is not an inner class, then it
1589+
/// is ignored. When a parsed class is an inner class, the accessibility
1590+
/// information for the parsed class is overwritten, and the parsed class is
1591+
/// marked as an inner class.
1592+
void java_bytecode_parsert::rinner_classes_attribute(
1593+
classt &parsed_class,
1594+
const u4 &attribute_length)
1595+
{
1596+
std::string name = parsed_class.name.c_str();
1597+
u2 number_of_classes = read_u2();
1598+
u4 number_of_bytes_to_be_read = number_of_classes * 8 + 2;
1599+
INVARIANT(
1600+
number_of_bytes_to_be_read == attribute_length,
1601+
"The number of bytes to be read for the InnerClasses attribute does not "
1602+
"match the attribute length.");
1603+
1604+
const auto pool_entry_lambda = [this](u2 index) -> pool_entryt & {
1605+
return pool_entry(index);
1606+
};
1607+
const auto remove_separator_char = [](std::string str, char ch) {
1608+
str.erase(std::remove(str.begin(), str.end(), ch), str.end());
1609+
return str;
1610+
};
1611+
1612+
for(int i = 0; i < number_of_classes; i++)
1613+
{
1614+
u2 inner_class_info_index = read_u2();
1615+
u2 outer_class_info_index = read_u2();
1616+
UNUSED u2 inner_name_index = read_u2();
1617+
u2 inner_class_access_flags = read_u2();
1618+
1619+
std::string inner_class_info_name =
1620+
class_infot(pool_entry(inner_class_info_index))
1621+
.get_name(pool_entry_lambda);
1622+
bool is_private = (inner_class_access_flags & ACC_PRIVATE) != 0;
1623+
bool is_public = (inner_class_access_flags & ACC_PUBLIC) != 0;
1624+
bool is_protected = (inner_class_access_flags & ACC_PROTECTED) != 0;
1625+
1626+
// If the original parsed class name matches the inner class name,
1627+
// the parsed class is an inner class, so overwrite the parsed class'
1628+
// access information and mark it as an inner class.
1629+
bool is_inner_class = remove_separator_char(id2string(parsed_class.name), '.') ==
1630+
remove_separator_char(inner_class_info_name, '/');
1631+
if(is_inner_class)
1632+
parsed_class.is_inner_class = is_inner_class;
1633+
if(!is_inner_class)
1634+
continue;
1635+
// Note that if outer_class_info_index == 0, the inner class is an anonymous
1636+
// or local class, and is treated as private.
1637+
if(outer_class_info_index == 0)
1638+
{
1639+
parsed_class.is_private = true;
1640+
parsed_class.is_protected = false;
1641+
parsed_class.is_public = false;
1642+
}
1643+
else
1644+
{
1645+
parsed_class.is_private = is_private;
1646+
parsed_class.is_protected = is_protected;
1647+
parsed_class.is_public = is_public;
1648+
}
1649+
}
1650+
}
1651+
15791652
void java_bytecode_parsert::rclass_attribute(classt &parsed_class)
15801653
{
15811654
u2 attribute_name_index=read_u2();
@@ -1640,6 +1713,11 @@ void java_bytecode_parsert::rclass_attribute(classt &parsed_class)
16401713
parsed_class.attribute_bootstrapmethods_read = true;
16411714
read_bootstrapmethods_entry(parsed_class);
16421715
}
1716+
else if(attribute_name == "InnerClasses")
1717+
{
1718+
java_bytecode_parsert::rinner_classes_attribute(
1719+
parsed_class, attribute_length);
1720+
}
16431721
else
16441722
skip_bytes(attribute_length);
16451723
}

jbmc/src/java_bytecode/java_types.h

+10
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,16 @@ class java_class_typet:public class_typet
111111
return set(ID_access, access);
112112
}
113113

114+
const bool get_is_inner_class() const
115+
{
116+
return get_bool(ID_is_inner_class);
117+
}
118+
119+
void set_is_inner_class(const bool &is_inner_class)
120+
{
121+
return set(ID_is_inner_class, is_inner_class);
122+
}
123+
114124
bool get_final()
115125
{
116126
return get_bool(ID_final);

jbmc/unit/Makefile

+1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ SRC += java_bytecode/goto-programs/class_hierarchy_output.cpp \
1212
java_bytecode/java_bytecode_convert_class/convert_java_annotations.cpp \
1313
java_bytecode/java_bytecode_convert_method/convert_invoke_dynamic.cpp \
1414
java_bytecode/java_bytecode_parse_generics/parse_generic_class.cpp \
15+
java_bytecode/java_bytecode_parser/parse_java_attributes.cpp \
1516
java_bytecode/java_object_factory/gen_nondet_string_init.cpp \
1617
java_bytecode/java_bytecode_parse_lambdas/java_bytecode_parse_lambda_method_table.cpp \
1718
java_bytecode/java_bytecode_parse_lambdas/java_bytecode_convert_class_lambda_method_handles.cpp \
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
public class InnerClasses {
2+
public class PublicInnerClass {
3+
public int i;
4+
public PublicInnerClass(int i) {
5+
this.i = i;
6+
}
7+
}
8+
class DefaultInnerClass {
9+
int i;
10+
DefaultInnerClass(int i) {
11+
this.i = i;
12+
}
13+
}
14+
protected class ProtectedInnerClass {
15+
protected int i;
16+
protected ProtectedInnerClass(int i) {
17+
this.i = i;
18+
}
19+
}
20+
private class PrivateInnerClass {
21+
private int i;
22+
private PrivateInnerClass(int i) {
23+
this.i = i;
24+
}
25+
}
26+
}
27+
28+
class InnerClassesDefault {
29+
public class PublicInnerClass {
30+
public int i;
31+
public PublicInnerClass(int i) {
32+
this.i = i;
33+
}
34+
}
35+
class DefaultInnerClass {
36+
int i;
37+
DefaultInnerClass(int i) {
38+
this.i = i;
39+
}
40+
}
41+
protected class ProtectedInnerClass {
42+
protected int i;
43+
protected ProtectedInnerClass(int i) {
44+
this.i = i;
45+
}
46+
}
47+
private class PrivateInnerClass {
48+
private int i;
49+
private PrivateInnerClass(int i) {
50+
this.i = i;
51+
}
52+
}
53+
}
54+
55+
class InnerClassesDeeplyNested {
56+
class SinglyNestedClass {
57+
int i;
58+
SinglyNestedClass(int i) {
59+
this.i = i;
60+
}
61+
public class PublicDoublyNestedInnerClass {
62+
public int i;
63+
public PublicDoublyNestedInnerClass(int i) {
64+
this.i = i;
65+
}
66+
}
67+
class DefaultDoublyNestedInnerClass {
68+
int i;
69+
DefaultDoublyNestedInnerClass(int i) {
70+
this.i = i;
71+
}
72+
}
73+
protected class ProtectedDoublyNestedInnerClass {
74+
protected int i;
75+
protected ProtectedDoublyNestedInnerClass(int i) {
76+
this.i = i;
77+
}
78+
}
79+
private class PrivateDoublyNestedInnerClass {
80+
private int i;
81+
private PrivateDoublyNestedInnerClass(int i) {
82+
this.i = i;
83+
}
84+
}
85+
}
86+
}
87+
88+
class ContainsAnonymousClass {
89+
interface InnerInterface {
90+
int i = 0;
91+
}
92+
public InnerInterface anonymousPublic = new InnerInterface() {
93+
int i = 1;
94+
};
95+
InnerInterface anonymousDefault = new InnerInterface() {
96+
int i = 2;
97+
};
98+
protected InnerInterface anonymousProtected = new InnerInterface() {
99+
int i = 3;
100+
};
101+
private InnerInterface anonymousPrivate = new InnerInterface() {
102+
int i = 4;
103+
};
104+
}
105+
106+
class ContainsLocalClass {
107+
public void test() {
108+
class LocalClass {
109+
int i = 55;
110+
LocalClass(int i) {
111+
this.i = i;
112+
}
113+
}
114+
}
115+
}
Binary file not shown.
Binary file not shown.

0 commit comments

Comments
 (0)