Merge "Workaround a bug in the JavaParser 3p library"
This commit is contained in:
committed by
Android (Google) Code Review
commit
09d29af6f2
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
@@ -180,9 +204,51 @@ class SourceTransformerTest {
|
||||
assertEquals(TRANSFORMED_CODE_TEXT_ENABLED, out)
|
||||
}
|
||||
|
||||
@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)
|
||||
|
||||
Reference in New Issue
Block a user