Skip to content

Commit d23a0cc

Browse files
author
thk123
committed
Added function for getting the full class name of a type
Skip over the signature when building the class name.
1 parent 34c185e commit d23a0cc

File tree

2 files changed

+192
-0
lines changed

2 files changed

+192
-0
lines changed

src/java_bytecode/java_types.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,40 @@ exprt java_bytecode_promotion(const exprt &expr)
167167
return typecast_exprt(expr, new_type);
168168
}
169169

170+
/// Returns the full class name, skipping over the generics
171+
/// \param src: a type descriptor or signature like LOuterClass<TT;>.Inner;
172+
/// \return The full name of the class like OuterClass.Inner
173+
std::string gather_full_class_name(const std::string &src)
174+
{
175+
PRECONDITION(src[0] == 'L');
176+
PRECONDITION(src[src.size() - 1] == ';');
177+
178+
std::string class_name = src.substr(1, src.size() - 2);
179+
180+
std::size_t f_pos = class_name.find('<', 1);
181+
182+
while(f_pos != std::string::npos)
183+
{
184+
std::size_t e_pos = find_closing_delimiter(class_name, f_pos, '<', '>');
185+
if(e_pos == std::string::npos)
186+
{
187+
throw unsupported_java_class_signature_exceptiont(
188+
"Failed to find generic signature closing delimiter (or recursive "
189+
"generic): " +
190+
src);
191+
}
192+
193+
// erase generic information between brackets
194+
class_name.erase(f_pos, e_pos - f_pos + 1);
195+
196+
// Search the remainder of the string for generic signature
197+
f_pos = class_name.find('<', e_pos + 1);
198+
}
199+
200+
std::replace(class_name.begin(), class_name.end(), '.', '$');
201+
std::replace(class_name.begin(), class_name.end(), '/', '.');
202+
return class_name;
203+
}
170204
/// Transforms a string representation of a Java type into an internal type
171205
/// representation thereof.
172206
///

unit/java_bytecode/java_utils_test.cpp

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include <testing-utils/catch.hpp>
1515

16+
#include <java_bytecode/java_types.cpp>
1617
#include <java_bytecode/java_utils.h>
1718

1819
SCENARIO("Test that the generic signature delimiter lookup works reliably",
@@ -63,3 +64,160 @@ SCENARIO("Test that the generic signature delimiter lookup works reliably",
6364
}
6465
}
6566
}
67+
68+
SCENARIO("gather_full_class_name")
69+
{
70+
GIVEN("Descriptor: class")
71+
{
72+
std::string descriptor = "LClassName;";
73+
THEN("Should get ClassName back")
74+
{
75+
const std::string &class_name = gather_full_class_name(descriptor);
76+
REQUIRE(class_name == "ClassName");
77+
}
78+
}
79+
GIVEN("Descriptor: A packaged class")
80+
{
81+
std::string descriptor = "Ljava/lang/Object;";
82+
THEN("Should get java.lang.Object back")
83+
{
84+
const std::string &class_name = gather_full_class_name(descriptor);
85+
REQUIRE(class_name == "java.lang.Object");
86+
}
87+
}
88+
GIVEN("Descriptor: A inner class")
89+
{
90+
std::string descriptor = "LOuter$Inner;";
91+
THEN("Should get Outer$Inner")
92+
{
93+
const std::string &class_name = gather_full_class_name(descriptor);
94+
REQUIRE(class_name == "Outer$Inner");
95+
}
96+
}
97+
GIVEN("Descriptor: a doubly nested inner class")
98+
{
99+
std::string descriptor = "LOuter$Inner$Inner2;";
100+
THEN("Should get Outer$Inner$Inner2")
101+
{
102+
const std::string &class_name = gather_full_class_name(descriptor);
103+
REQUIRE(class_name == "Outer$Inner$Inner2");
104+
}
105+
}
106+
107+
GIVEN("Signature: An generic class")
108+
{
109+
std::string signature = "LClassName<TT;>;";
110+
THEN("Should get ClassName back")
111+
{
112+
const std::string &class_name = gather_full_class_name(signature);
113+
REQUIRE(class_name == "ClassName");
114+
}
115+
}
116+
GIVEN("Signature: An inner class in a generic class")
117+
{
118+
std::string signature = "LClassName<TT;>.Inner;";
119+
THEN("Should get ClassName$Inner back")
120+
{
121+
const std::string &class_name = gather_full_class_name(signature);
122+
REQUIRE(class_name == "ClassName$Inner");
123+
}
124+
}
125+
GIVEN("Signature: An generic inner class in a generic class")
126+
{
127+
std::string signature = "LClassName<TT;>.Inner<TV;>;";
128+
THEN("Should get ClassName$Inner back")
129+
{
130+
const std::string &class_name = gather_full_class_name(signature);
131+
REQUIRE(class_name == "ClassName$Inner");
132+
}
133+
}
134+
GIVEN("Signature: A generic inner class in a non generic class")
135+
{
136+
std::string signature = "LClassName.Inner<TV;>;";
137+
THEN("Should get ClassName$Inner back")
138+
{
139+
const std::string &class_name = gather_full_class_name(signature);
140+
REQUIRE(class_name == "ClassName$Inner");
141+
}
142+
}
143+
GIVEN(
144+
"Signature: A generic inner class in a non generic class in a non "
145+
"generic "
146+
"class")
147+
{
148+
std::string signature = "LClassName.Inner.Inner2<TT;>;";
149+
THEN("Should get ClassName$Inner$Inner2 back")
150+
{
151+
const std::string &class_name = gather_full_class_name(signature);
152+
REQUIRE(class_name == "ClassName$Inner$Inner2");
153+
}
154+
}
155+
GIVEN(
156+
"Signature: A generic inner class in a generic class in a non generic "
157+
"class")
158+
{
159+
std::string signature = "LClassName.Inner<UU;>.Inner2<TT;>;";
160+
THEN("Should get ClassName$Inner$Inner2 back")
161+
{
162+
const std::string &class_name = gather_full_class_name(signature);
163+
REQUIRE(class_name == "ClassName$Inner$Inner2");
164+
}
165+
}
166+
GIVEN(
167+
"Signature: A generic inner class in a generic class in a generic "
168+
"class")
169+
{
170+
std::string signature = "LClassName<TV;>.Inner<UU;>.Inner2<TT;>;";
171+
THEN("Should get ClassName$Inner$Inner2 back")
172+
{
173+
const std::string &class_name = gather_full_class_name(signature);
174+
REQUIRE(class_name == "ClassName$Inner$Inner2");
175+
}
176+
}
177+
GIVEN(
178+
"Signature: A non-generic inner class in a generic class in a non "
179+
"generic "
180+
"class")
181+
{
182+
std::string signature = "LClassName.Inner<UU;>.Inner2;";
183+
THEN("Should get ClassName$Inner$Inner2 back")
184+
{
185+
const std::string &class_name = gather_full_class_name(signature);
186+
REQUIRE(class_name == "ClassName$Inner$Inner2");
187+
}
188+
}
189+
GIVEN(
190+
"Signature: A non-generic inner class in a generic class in a generic "
191+
"class")
192+
{
193+
std::string signature = "LClassName<TV;>.Inner<UU;>.Inner2;";
194+
THEN("Should get ClassName$Inner$Inner2 back")
195+
{
196+
const std::string &class_name = gather_full_class_name(signature);
197+
REQUIRE(class_name == "ClassName$Inner$Inner2");
198+
}
199+
}
200+
GIVEN(
201+
"Signature: A non-generic inner class in a non-generic class in a "
202+
"generic "
203+
"class")
204+
{
205+
std::string signature = "LClassName<TV;>.Inner.Inner2;";
206+
THEN("Should get ClassName$Inner$Inner2 back")
207+
{
208+
const std::string &class_name = gather_full_class_name(signature);
209+
REQUIRE(class_name == "ClassName$Inner$Inner2");
210+
}
211+
}
212+
GIVEN(
213+
"Signature: A generic inner class in a non-generic class in a generic "
214+
"class")
215+
{
216+
std::string signature = "LClassName<TV;>.Inner.Inner2<TT;>;";
217+
THEN("Should get ClassName$Inner$Inner2 back")
218+
{
219+
const std::string &class_name = gather_full_class_name(signature);
220+
REQUIRE(class_name == "ClassName$Inner$Inner2");
221+
}
222+
}
223+
}

0 commit comments

Comments
 (0)