Skip to content

Commit 789777d

Browse files
bengt-GSOberon Swings
authored andcommitted
Add support for <clinit> in ConfigurationParser
1 parent e76e479 commit 789777d

File tree

4 files changed

+95
-11
lines changed

4 files changed

+95
-11
lines changed

base/src/main/java/proguard/ConfigurationParser.java

Lines changed: 24 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1183,24 +1183,29 @@ else if (isMethods)
11831183
// Did we get just one word before the opening parenthesis?
11841184
if (ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD.equals(name))
11851185
{
1186-
// This must be a constructor then.
1187-
// Make sure the type is a proper constructor name.
1188-
if (!(type.equals(ClassConstants.METHOD_NAME_INIT) ||
1189-
type.equals(externalClassName) ||
1190-
type.equals(ClassUtil.externalShortClassName(externalClassName))))
1186+
// This must be an initializer then.
1187+
// Make sure the type is a proper initializer name.
1188+
if (ClassUtil.isInitializer(type))
1189+
{
1190+
name = type; // This is either `<init>` or `<clinit>`.
1191+
type = JavaTypeConstants.VOID;
1192+
}
1193+
else if (type.equals(externalClassName) ||
1194+
type.equals(ClassUtil.externalShortClassName(externalClassName)))
1195+
{
1196+
name = ClassConstants.METHOD_NAME_INIT;
1197+
type = JavaTypeConstants.VOID;
1198+
}
1199+
else
11911200
{
11921201
throw new ParseException("Expecting type and name " +
11931202
"instead of just '" + type +
11941203
"' before " + reader.locationDescription());
11951204
}
1196-
1197-
// Assign the fixed constructor type and name.
1198-
type = JavaTypeConstants.VOID;
1199-
name = ClassConstants.METHOD_NAME_INIT;
12001205
}
12011206
else
12021207
{
1203-
// It's not a constructor.
1208+
// It's not an initializer.
12041209
// Make sure we have a proper name.
12051210
checkNextWordIsJavaIdentifier("class member name");
12061211

@@ -1211,7 +1216,7 @@ else if (isMethods)
12111216
}
12121217

12131218
// Check if the type actually contains the use of generics.
1214-
// Can not do it right away as we also support "<init>" as a type (see case above).
1219+
// Can not do it right away as we also support "<init>" and "<clinit>" as a type (see case above).
12151220
if (containsGenerics(type))
12161221
{
12171222
throw new ParseException("Generics are not allowed (erased) for java type" + typeLocation);
@@ -1292,6 +1297,14 @@ else if (ConfigurationConstants.OPEN_ARGUMENTS_KEYWORD.equals(nextWord))
12921297
"' before " + reader.locationDescription());
12931298
}
12941299

1300+
// Class initializers are not supposed to have any parameters.
1301+
if (ClassConstants.METHOD_NAME_CLINIT.equals(name) &&
1302+
ClassUtil.internalMethodParameterCount(descriptor) > 0)
1303+
{
1304+
throw new ParseException("Not expecting method parameters with initializer '" + ClassConstants.METHOD_NAME_CLINIT +
1305+
"' before " + reader.locationDescription());
1306+
}
1307+
12951308
// Read the separator after the closing parenthesis.
12961309
readNextWord("separator '" + ConfigurationConstants.SEPARATOR_KEYWORD + "'");
12971310

base/src/test/kotlin/proguard/ConfigurationParserTest.kt

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,31 @@ class ConfigurationParserTest : FreeSpec({
6464
parseConfiguration("-keep class * { public protected <methods>; }")
6565
}
6666

67+
"Keep rule with ClassName should be valid" {
68+
val configuration = parseConfiguration("-keep class ClassName { ClassName(); }")
69+
val keep = configuration.keep.single().methodSpecifications.single()
70+
keep.name shouldBe "<init>"
71+
keep.descriptor shouldBe "()V"
72+
}
73+
74+
"Keep rule with ClassName and external class com.example.ClassName should be valid" {
75+
val configuration = parseConfiguration("-keep class com.example.ClassName { ClassName(); }")
76+
val keep = configuration.keep.single().methodSpecifications.single()
77+
keep.name shouldBe "<init>"
78+
keep.descriptor shouldBe "()V"
79+
}
80+
81+
"Keep rule with <clinit> should be valid" {
82+
val configuration = parseConfiguration("-keep class ** { <clinit>(); }")
83+
val keep = configuration.keep.single().methodSpecifications.single()
84+
keep.name shouldBe "<clinit>"
85+
keep.descriptor shouldBe "()V"
86+
}
87+
88+
"Keep rule with <clinit> and non-empty argument list should throw ParseException" {
89+
shouldThrow<ParseException> { parseConfiguration("-keep class * { void <clinit>(int) }") }
90+
}
91+
6792
"Keep rule with * member wildcard and return type should be valid" {
6893
parseConfiguration("-keep class * { java.lang.String *; }")
6994
}

base/src/test/kotlin/proguard/ConfigurationWriterTest.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,48 @@ class ConfigurationWriterTest : FreeSpec({
2626
return out.toString().trim()
2727
}
2828

29+
"Keep rules tests" - {
30+
"Keep class constructor should be kept" {
31+
val rules = """
32+
-keep class * {
33+
<init>();
34+
}
35+
""".trimIndent()
36+
val out = printConfiguration(rules)
37+
out shouldBe rules
38+
}
39+
40+
"Keep class initializer should be kept" {
41+
val rules = """
42+
-keep class * {
43+
<clinit>();
44+
}
45+
""".trimIndent()
46+
val out = printConfiguration(rules)
47+
val expected = """
48+
-keep class * {
49+
void <clinit>();
50+
}
51+
""".trimIndent()
52+
out shouldBe expected
53+
}
54+
55+
"Keep class initializer should respect allowobfuscation flag" {
56+
val rules = """
57+
-keep,allowobfuscation class ** extends com.example.A {
58+
<clinit>();
59+
}
60+
""".trimIndent()
61+
val out = printConfiguration(rules)
62+
val expected = """
63+
-keep,allowobfuscation class ** extends com.example.A {
64+
void <clinit>();
65+
}
66+
""".trimIndent()
67+
out shouldBe expected
68+
}
69+
}
70+
2971
"Hash character handling tests" - {
3072
"Option parameters with hash characters should be quoted" {
3173
printConfiguration("-keystorepassword '#tester'") shouldBe "-keystorepassword '#tester'"

docs/md/manual/releasenotes.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@
44

55
- Fix inadvertent closing of System.out when printing configuration. (#365)
66

7+
### Added
8+
9+
- Support for parsing of `<clinit>` methods without specifying the return type in class specifications.
10+
711
## Version 7.4
812

913
### Java support

0 commit comments

Comments
 (0)