summaryrefslogtreecommitdiff
path: root/tools/protologtool
diff options
context:
space:
mode:
authorAdam Pardyl <apardyl@google.com>2019-09-12 14:19:48 +0200
committerAdam Pardyl <apardyl@google.com>2019-09-12 16:37:55 +0200
commit3c6f3387cfc930138bdf2210b17210529d2e4314 (patch)
treea6e1b37f0eb1c4588ec023247f29c0b70b4da74c /tools/protologtool
parentf986b4e9bb3763cad0e318a82908290814826ff0 (diff)
Workaround a bug in the JavaParser 3p library
A bug in the JavaParser LexicalPreservingPrinter prevents the ProtoLogTool from correctly handling multiple subsequent ProtoLog calls. This bug is a known issue, no fix is worked on at this moment (https://github.com/javaparser/javaparser/issues/2290). Bug: Test: atest protologtool-tests Change-Id: I919527a31c5ed21b17e5f3e271c2758d35896ea5
Diffstat (limited to 'tools/protologtool')
-rw-r--r--tools/protologtool/src/com/android/protologtool/ProtoLogTool.kt5
-rw-r--r--tools/protologtool/src/com/android/protologtool/SourceTransformer.kt36
-rw-r--r--tools/protologtool/tests/com/android/protologtool/SourceTransformerTest.kt102
3 files changed, 124 insertions, 19 deletions
diff --git a/tools/protologtool/src/com/android/protologtool/ProtoLogTool.kt b/tools/protologtool/src/com/android/protologtool/ProtoLogTool.kt
index 485a0479cbd9..618e4b14e4c5 100644
--- a/tools/protologtool/src/com/android/protologtool/ProtoLogTool.kt
+++ b/tools/protologtool/src/com/android/protologtool/ProtoLogTool.kt
@@ -42,8 +42,9 @@ object ProtoLogTool {
command.javaSourceArgs.forEach { path ->
val file = File(path)
- val code = StaticJavaParser.parse(file)
- val outSrc = transformer.processClass(code)
+ val text = file.readText()
+ val code = StaticJavaParser.parse(text)
+ val outSrc = transformer.processClass(text, code)
val pack = if (code.packageDeclaration.isPresent) code.packageDeclaration
.get().nameAsString else ""
val newPath = pack.replace('.', '/') + '/' + file.name
diff --git a/tools/protologtool/src/com/android/protologtool/SourceTransformer.kt b/tools/protologtool/src/com/android/protologtool/SourceTransformer.kt
index 319a8170dca8..f915ea6eb186 100644
--- a/tools/protologtool/src/com/android/protologtool/SourceTransformer.kt
+++ b/tools/protologtool/src/com/android/protologtool/SourceTransformer.kt
@@ -130,6 +130,8 @@ class SourceTransformer(
// Append blank lines to preserve line numbering in file (to allow debugging)
val newLines = LexicalPreservingPrinter.print(parentStmt).count { c -> c == '\n' }
val newStmt = printedIfStmt.substringBeforeLast('}') + ("\n".repeat(newLines)) + '}'
+ // pre-workaround code, see explanation below
+ /*
val inlinedIfStmt = StaticJavaParser.parseStatement(newStmt)
LexicalPreservingPrinter.setup(inlinedIfStmt)
// Replace the original call.
@@ -138,6 +140,27 @@ class SourceTransformer(
throw RuntimeException("Unable to process log call $call " +
"- unable to replace the call.")
}
+ */
+ /** Workaround for a bug in JavaParser (AST tree invalid after replacing a node when using
+ * LexicalPreservingPrinter (https://github.com/javaparser/javaparser/issues/2290).
+ * Replace the code below with the one commended-out above one the issue is resolved. */
+ if (!parentStmt.range.isPresent) {
+ // Should never happen
+ throw RuntimeException("Unable to process log call $call " +
+ "- unable to replace the call.")
+ }
+ val range = parentStmt.range.get()
+ val begin = range.begin.line - 1
+ val oldLines = processedCode.subList(begin, range.end.line)
+ val oldCode = oldLines.joinToString("\n")
+ val newCode = oldCode.replaceRange(
+ offsets[begin] + range.begin.column - 1,
+ oldCode.length - oldLines.lastOrNull()!!.length +
+ range.end.column + offsets[range.end.line - 1], newStmt)
+ newCode.split("\n").forEachIndexed { idx, line ->
+ offsets[begin + idx] += line.length - processedCode[begin + idx].length
+ processedCode[begin + idx] = line
+ }
}
private val inlinePrinter: PrettyPrinter
@@ -153,10 +176,19 @@ class SourceTransformer(
private val protoLogImplClassNode =
StaticJavaParser.parseExpression<FieldAccessExpr>(protoLogImplClassName)
+ private var processedCode: MutableList<String> = mutableListOf()
+ private var offsets: IntArray = IntArray(0)
- fun processClass(compilationUnit: CompilationUnit): String {
+ fun processClass(
+ code: String,
+ compilationUnit: CompilationUnit =
+ StaticJavaParser.parse(code)
+ ): String {
+ processedCode = code.split('\n').toMutableList()
+ offsets = IntArray(processedCode.size)
LexicalPreservingPrinter.setup(compilationUnit)
protoLogCallProcessor.process(compilationUnit, this)
- return LexicalPreservingPrinter.print(compilationUnit)
+ // return LexicalPreservingPrinter.print(compilationUnit)
+ return processedCode.joinToString("\n")
}
}
diff --git a/tools/protologtool/tests/com/android/protologtool/SourceTransformerTest.kt b/tools/protologtool/tests/com/android/protologtool/SourceTransformerTest.kt
index 7b8dd9a73fa9..2cd85627b94b 100644
--- a/tools/protologtool/tests/com/android/protologtool/SourceTransformerTest.kt
+++ b/tools/protologtool/tests/com/android/protologtool/SourceTransformerTest.kt
@@ -28,6 +28,8 @@ import org.mockito.Mockito
class SourceTransformerTest {
companion object {
private const val PROTO_LOG_IMPL_PATH = "org.example.ProtoLogImpl"
+
+ /* ktlint-disable max-line-length */
private val TEST_CODE = """
package org.example;
@@ -50,6 +52,17 @@ class SourceTransformerTest {
}
""".trimIndent()
+ private val TEST_CODE_MULTICALLS = """
+ package org.example;
+
+ class Test {
+ void test() {
+ ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1);
+ ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1);
+ }
+ }
+ """.trimIndent()
+
private val TEST_CODE_NO_PARAMS = """
package org.example;
@@ -60,7 +73,6 @@ class SourceTransformerTest {
}
""".trimIndent()
- /* ktlint-disable max-line-length */
private val TRANSFORMED_CODE_TEXT_ENABLED = """
package org.example;
@@ -83,6 +95,17 @@ class SourceTransformerTest {
}
""".trimIndent()
+ private val TRANSFORMED_CODE_MULTICALL_TEXT_ENABLED = """
+ package org.example;
+
+ class Test {
+ void test() {
+ if (TEST_GROUP.isLogToAny()) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 835524026, 9, "test %d %f", protoLogParam0, protoLogParam1); } /* ProtoLog.w(TEST_GROUP, "test %d %f", 100, 0.1); */ if (TEST_GROUP.isLogToAny()) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 835524026, 9, "test %d %f", protoLogParam0, protoLogParam1); }
+ if (TEST_GROUP.isLogToAny()) { long protoLogParam0 = 100; double protoLogParam1 = 0.1; org.example.ProtoLogImpl.w(TEST_GROUP, 835524026, 9, "test %d %f", protoLogParam0, protoLogParam1); }
+ }
+ }
+ """.trimIndent()
+
private val TRANSFORMED_CODE_NO_PARAMS = """
package org.example;
@@ -146,7 +169,7 @@ class SourceTransformerTest {
@Test
fun processClass_textEnabled() {
- val code = StaticJavaParser.parse(TEST_CODE)
+ var code = StaticJavaParser.parse(TEST_CODE)
Mockito.`when`(processor.process(any(CompilationUnit::class.java),
any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
@@ -158,7 +181,8 @@ class SourceTransformerTest {
invocation.arguments[0] as CompilationUnit
}
- val out = sourceJarWriter.processClass(code)
+ val out = sourceJarWriter.processClass(TEST_CODE, code)
+ code = StaticJavaParser.parse(out)
val ifStmts = code.findAll(IfStmt::class.java)
assertEquals(1, ifStmts.size)
@@ -181,8 +205,50 @@ class SourceTransformerTest {
}
@Test
+ fun processClass_textEnabledMulticalls() {
+ var code = StaticJavaParser.parse(TEST_CODE_MULTICALLS)
+
+ Mockito.`when`(processor.process(any(CompilationUnit::class.java),
+ any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
+ val visitor = invocation.arguments[1] as ProtoLogCallVisitor
+
+ val calls = code.findAll(MethodCallExpr::class.java)
+ visitor.processCall(calls[0], "test %d %f",
+ LogLevel.WARN, LogGroup("TEST_GROUP", true, true, "WM_TEST"))
+ visitor.processCall(calls[1], "test %d %f",
+ LogLevel.WARN, LogGroup("TEST_GROUP", true, true, "WM_TEST"))
+ visitor.processCall(calls[2], "test %d %f",
+ LogLevel.WARN, LogGroup("TEST_GROUP", true, true, "WM_TEST"))
+
+ invocation.arguments[0] as CompilationUnit
+ }
+
+ val out = sourceJarWriter.processClass(TEST_CODE_MULTICALLS, code)
+ code = StaticJavaParser.parse(out)
+
+ val ifStmts = code.findAll(IfStmt::class.java)
+ assertEquals(3, ifStmts.size)
+ val ifStmt = ifStmts[1]
+ assertEquals("TEST_GROUP.${Constants.IS_LOG_TO_ANY_METHOD}()",
+ ifStmt.condition.toString())
+ assertFalse(ifStmt.elseStmt.isPresent)
+ assertEquals(3, ifStmt.thenStmt.childNodes.size)
+ val methodCall = ifStmt.thenStmt.findAll(MethodCallExpr::class.java)[0] as MethodCallExpr
+ assertEquals(PROTO_LOG_IMPL_PATH, methodCall.scope.get().toString())
+ assertEquals("w", methodCall.name.asString())
+ assertEquals(6, methodCall.arguments.size)
+ assertEquals("TEST_GROUP", methodCall.arguments[0].toString())
+ assertEquals("835524026", methodCall.arguments[1].toString())
+ assertEquals(0b1001.toString(), methodCall.arguments[2].toString())
+ assertEquals("\"test %d %f\"", methodCall.arguments[3].toString())
+ assertEquals("protoLogParam0", methodCall.arguments[4].toString())
+ assertEquals("protoLogParam1", methodCall.arguments[5].toString())
+ assertEquals(TRANSFORMED_CODE_MULTICALL_TEXT_ENABLED, out)
+ }
+
+ @Test
fun processClass_textEnabledMultiline() {
- val code = StaticJavaParser.parse(TEST_CODE_MULTILINE)
+ var code = StaticJavaParser.parse(TEST_CODE_MULTILINE)
Mockito.`when`(processor.process(any(CompilationUnit::class.java),
any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
@@ -195,7 +261,8 @@ class SourceTransformerTest {
invocation.arguments[0] as CompilationUnit
}
- val out = sourceJarWriter.processClass(code)
+ val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, code)
+ code = StaticJavaParser.parse(out)
val ifStmts = code.findAll(IfStmt::class.java)
assertEquals(1, ifStmts.size)
@@ -219,7 +286,7 @@ class SourceTransformerTest {
@Test
fun processClass_noParams() {
- val code = StaticJavaParser.parse(TEST_CODE_NO_PARAMS)
+ var code = StaticJavaParser.parse(TEST_CODE_NO_PARAMS)
Mockito.`when`(processor.process(any(CompilationUnit::class.java),
any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
@@ -231,7 +298,8 @@ class SourceTransformerTest {
invocation.arguments[0] as CompilationUnit
}
- val out = sourceJarWriter.processClass(code)
+ val out = sourceJarWriter.processClass(TEST_CODE_NO_PARAMS, code)
+ code = StaticJavaParser.parse(out)
val ifStmts = code.findAll(IfStmt::class.java)
assertEquals(1, ifStmts.size)
@@ -252,7 +320,7 @@ class SourceTransformerTest {
@Test
fun processClass_textDisabled() {
- val code = StaticJavaParser.parse(TEST_CODE)
+ var code = StaticJavaParser.parse(TEST_CODE)
Mockito.`when`(processor.process(any(CompilationUnit::class.java),
any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
@@ -264,7 +332,8 @@ class SourceTransformerTest {
invocation.arguments[0] as CompilationUnit
}
- val out = sourceJarWriter.processClass(code)
+ val out = sourceJarWriter.processClass(TEST_CODE, code)
+ code = StaticJavaParser.parse(out)
val ifStmts = code.findAll(IfStmt::class.java)
assertEquals(1, ifStmts.size)
@@ -288,7 +357,7 @@ class SourceTransformerTest {
@Test
fun processClass_textDisabledMultiline() {
- val code = StaticJavaParser.parse(TEST_CODE_MULTILINE)
+ var code = StaticJavaParser.parse(TEST_CODE_MULTILINE)
Mockito.`when`(processor.process(any(CompilationUnit::class.java),
any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
@@ -301,7 +370,8 @@ class SourceTransformerTest {
invocation.arguments[0] as CompilationUnit
}
- val out = sourceJarWriter.processClass(code)
+ val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, code)
+ code = StaticJavaParser.parse(out)
val ifStmts = code.findAll(IfStmt::class.java)
assertEquals(1, ifStmts.size)
@@ -326,7 +396,7 @@ class SourceTransformerTest {
@Test
fun processClass_disabled() {
- val code = StaticJavaParser.parse(TEST_CODE)
+ var code = StaticJavaParser.parse(TEST_CODE)
Mockito.`when`(processor.process(any(CompilationUnit::class.java),
any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
@@ -338,7 +408,8 @@ class SourceTransformerTest {
invocation.arguments[0] as CompilationUnit
}
- val out = sourceJarWriter.processClass(code)
+ val out = sourceJarWriter.processClass(TEST_CODE, code)
+ code = StaticJavaParser.parse(out)
val ifStmts = code.findAll(IfStmt::class.java)
assertEquals(1, ifStmts.size)
@@ -349,7 +420,7 @@ class SourceTransformerTest {
@Test
fun processClass_disabledMultiline() {
- val code = StaticJavaParser.parse(TEST_CODE_MULTILINE)
+ var code = StaticJavaParser.parse(TEST_CODE_MULTILINE)
Mockito.`when`(processor.process(any(CompilationUnit::class.java),
any(ProtoLogCallVisitor::class.java))).thenAnswer { invocation ->
@@ -362,7 +433,8 @@ class SourceTransformerTest {
invocation.arguments[0] as CompilationUnit
}
- val out = sourceJarWriter.processClass(code)
+ val out = sourceJarWriter.processClass(TEST_CODE_MULTILINE, code)
+ code = StaticJavaParser.parse(out)
val ifStmts = code.findAll(IfStmt::class.java)
assertEquals(1, ifStmts.size)