Loading tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt +1 −1 Original line number Diff line number Diff line Loading @@ -24,5 +24,5 @@ interface ProtoLogCallProcessor { logCallVisitor: ProtoLogCallVisitor?, otherCallVisitor: MethodCallVisitor?, fileName: String ): CompilationUnit ): Collection<CodeProcessingException> } tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt +42 −29 Original line number Diff line number Diff line Loading @@ -74,7 +74,7 @@ class ProtoLogCallProcessorImpl( } fun process(code: CompilationUnit, logCallVisitor: ProtoLogCallVisitor?, fileName: String): CompilationUnit { Collection<CodeProcessingException> { return process(code, logCallVisitor, null, fileName) } Loading @@ -83,7 +83,7 @@ class ProtoLogCallProcessorImpl( logCallVisitor: ProtoLogCallVisitor?, otherCallVisitor: MethodCallVisitor?, fileName: String ): CompilationUnit { ): Collection<CodeProcessingException> { CodeUtils.checkWildcardStaticImported(code, protoLogClassName, fileName) CodeUtils.checkWildcardStaticImported(code, protoLogGroupClassName, fileName) Loading @@ -93,50 +93,63 @@ class ProtoLogCallProcessorImpl( protoLogGroupClassName) val staticGroupImports = CodeUtils.staticallyImportedMethods(code, protoLogGroupClassName) val errors = mutableListOf<CodeProcessingException>() code.findAll(MethodCallExpr::class.java) .filter { call -> isProtoCall(call, isLogClassImported, staticLogImports) }.forEach { call -> val context = ParsingContext(fileName, call) try { val logMethods = LogLevel.entries.map { it.shortCode } if (logMethods.contains(call.name.id)) { // Process a log call if (call.arguments.size < 2) { throw InvalidProtoLogCallException("Method signature does not match " + "any ProtoLog method: $call", context) errors.add(InvalidProtoLogCallException( "Method signature does not match " + "any ProtoLog method: $call", context )) return@forEach } val messageString = CodeUtils.concatMultilineString(call.getArgument(1), context) val messageString = CodeUtils.concatMultilineString( call.getArgument(1), context ) val groupNameArg = call.getArgument(0) val groupName = getLogGroupName(groupNameArg, isGroupClassImported, staticGroupImports, fileName) getLogGroupName( groupNameArg, isGroupClassImported, staticGroupImports, fileName ) if (groupName !in groupMap) { throw InvalidProtoLogCallException("Unknown group argument " + "- not a ProtoLogGroup enum member: $call", context) errors.add(InvalidProtoLogCallException( "Unknown group argument " + "- not a ProtoLogGroup enum member: $call", context )) return@forEach } try { logCallVisitor?.processCall( call, messageString, getLevelForMethodName( call.name.toString(), call, context ), groupMap.getValue(groupName), context.lineNumber ) } catch (e: Throwable) { throw InvalidProtoLogCallException("Error processing log call: $call", context, e) } } else if (call.name.id == "init") { // No processing } else { // Process non-log message calls otherCallVisitor?.processCall(call) } } catch (e: Throwable) { errors.add(InvalidProtoLogCallException( "Error processing log call: $call", context, e )) } } return code return errors } private fun getLevelForMethodName( Loading tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt +19 −6 Original line number Diff line number Diff line Loading @@ -130,14 +130,16 @@ object ProtoLogTool { val outSrc = try { val code = tryParse(text, path) if (containsProtoLogText(text, PROTOLOG_CLASS_NAME)) { transformer.processClass(text, path, packagePath(file, code), code) val (processedText, errors) = transformer.processClass(text, path, packagePath(file, code), code) errors.forEach { injector.reportProcessingError(it) } processedText } else { text } } catch (ex: ParsingException) { // If we cannot parse this file, skip it (and log why). Compilation will // fail in a subsequent build step. injector.reportParseError(ex) injector.reportProcessingError(ex) text } path to outSrc Loading Loading @@ -405,7 +407,7 @@ object ProtoLogTool { } catch (ex: ParsingException) { // If we cannot parse this file, skip it (and log why). Compilation will // fail in a subsequent build step. injector.reportParseError(ex) injector.reportProcessingError(ex) null } } else { Loading Loading @@ -466,6 +468,14 @@ object ProtoLogTool { try { val command = CommandOptions(args) invoke(command) if (injector.processingErrors.isNotEmpty()) { injector.processingErrors.forEachIndexed { index, it -> println("CodeProcessingException " + "(${index + 1}/${injector.processingErrors.size}): \n${it.message}\n") } exitProcess(1) } } catch (ex: InvalidCommandException) { println("InvalidCommandException: \n${ex.message}\n") showHelpAndExit() Loading @@ -489,12 +499,14 @@ object ProtoLogTool { } var injector = object : Injector { override val processingErrors: MutableList<CodeProcessingException> get() = mutableListOf() override fun fileOutputStream(file: String) = FileOutputStream(file) override fun readText(file: File) = file.readText() override fun readLogGroups(jarPath: String, className: String) = ProtoLogGroupReader().loadFromJar(jarPath, className) override fun reportParseError(ex: ParsingException) { println("\n${ex.message}\n") override fun reportProcessingError(ex: CodeProcessingException) { processingErrors.add(ex) } } Loading @@ -502,7 +514,8 @@ object ProtoLogTool { fun fileOutputStream(file: String): OutputStream fun readText(file: File): String fun readLogGroups(jarPath: String, className: String): Map<String, LogGroup> fun reportParseError(ex: ParsingException) fun reportProcessingError(ex: CodeProcessingException) val processingErrors: Collection<CodeProcessingException> } } Loading tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt +3 −3 Original line number Diff line number Diff line Loading @@ -66,13 +66,13 @@ class SourceTransformer( packagePath: String, compilationUnit: CompilationUnit = StaticJavaParser.parse(code) ): String { ): Pair<String, Collection<CodeProcessingException>> { this.path = path this.packagePath = packagePath processedCode = code.split('\n').toMutableList() offsets = IntArray(processedCode.size) protoLogCallProcessor.process(compilationUnit, protoLogCallVisitor, otherCallVisitor, path) return processedCode.joinToString("\n") val processingErrors = protoLogCallProcessor.process(compilationUnit, protoLogCallVisitor, otherCallVisitor, path) return Pair(processedCode.joinToString("\n"), processingErrors) } private val protoLogImplClassNode = Loading tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt +42 −1 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.protolog.tool import com.android.protolog.tool.ProtoLogTool.PROTOLOG_IMPL_SRC_PATH import com.android.protolog.tool.ProtoLogTool.injector import com.google.common.truth.Truth import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream Loading Loading @@ -102,6 +103,42 @@ class EndToEndTest { """.trimIndent()) } @Test fun e2e_transform_withErrors() { val srcs = mapOf( "frameworks/base/org/example/Example.java" to """ package org.example; import com.android.internal.protolog.ProtoLog; import static com.android.internal.protolog.ProtoLogGroup.GROUP; class Example { void method() { String argString = "hello"; int argInt = 123; ProtoLog.d(GROUP, "Invalid format: %s %d %9 %", argString, argInt); } } """.trimIndent()) val output = run( srcs = srcs, logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"), commandOptions = CommandOptions(arrayOf("transform-protolog-calls", "--protolog-class", "com.android.internal.protolog.ProtoLog", "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup", "--loggroups-jar", "not_required.jar", "--viewer-config-file-path", "not_required.pb", "--output-srcjar", "out.srcjar", "frameworks/base/org/example/Example.java")) ) val outSrcJar = assertLoadSrcJar(output, "out.srcjar") // No change to source code on failure to process Truth.assertThat(outSrcJar["frameworks/base/org/example/Example.java"]) .contains(srcs["frameworks/base/org/example/Example.java"]) Truth.assertThat(injector.processingErrors).hasSize(1) Truth.assertThat(injector.processingErrors.first().message).contains("Invalid format") } private fun assertLoadSrcJar( outputs: Map<String, ByteArray>, path: String Loading Loading @@ -172,7 +209,11 @@ class EndToEndTest { override fun readLogGroups(jarPath: String, className: String) = mapOf( logGroup.name to logGroup) override fun reportParseError(ex: ParsingException) = throw AssertionError(ex) override fun reportProcessingError(ex: CodeProcessingException) { processingErrors.add(ex) } override val processingErrors: MutableList<CodeProcessingException> = mutableListOf() } ProtoLogTool.invoke(commandOptions) Loading Loading
tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessor.kt +1 −1 Original line number Diff line number Diff line Loading @@ -24,5 +24,5 @@ interface ProtoLogCallProcessor { logCallVisitor: ProtoLogCallVisitor?, otherCallVisitor: MethodCallVisitor?, fileName: String ): CompilationUnit ): Collection<CodeProcessingException> }
tools/protologtool/src/com/android/protolog/tool/ProtoLogCallProcessorImpl.kt +42 −29 Original line number Diff line number Diff line Loading @@ -74,7 +74,7 @@ class ProtoLogCallProcessorImpl( } fun process(code: CompilationUnit, logCallVisitor: ProtoLogCallVisitor?, fileName: String): CompilationUnit { Collection<CodeProcessingException> { return process(code, logCallVisitor, null, fileName) } Loading @@ -83,7 +83,7 @@ class ProtoLogCallProcessorImpl( logCallVisitor: ProtoLogCallVisitor?, otherCallVisitor: MethodCallVisitor?, fileName: String ): CompilationUnit { ): Collection<CodeProcessingException> { CodeUtils.checkWildcardStaticImported(code, protoLogClassName, fileName) CodeUtils.checkWildcardStaticImported(code, protoLogGroupClassName, fileName) Loading @@ -93,50 +93,63 @@ class ProtoLogCallProcessorImpl( protoLogGroupClassName) val staticGroupImports = CodeUtils.staticallyImportedMethods(code, protoLogGroupClassName) val errors = mutableListOf<CodeProcessingException>() code.findAll(MethodCallExpr::class.java) .filter { call -> isProtoCall(call, isLogClassImported, staticLogImports) }.forEach { call -> val context = ParsingContext(fileName, call) try { val logMethods = LogLevel.entries.map { it.shortCode } if (logMethods.contains(call.name.id)) { // Process a log call if (call.arguments.size < 2) { throw InvalidProtoLogCallException("Method signature does not match " + "any ProtoLog method: $call", context) errors.add(InvalidProtoLogCallException( "Method signature does not match " + "any ProtoLog method: $call", context )) return@forEach } val messageString = CodeUtils.concatMultilineString(call.getArgument(1), context) val messageString = CodeUtils.concatMultilineString( call.getArgument(1), context ) val groupNameArg = call.getArgument(0) val groupName = getLogGroupName(groupNameArg, isGroupClassImported, staticGroupImports, fileName) getLogGroupName( groupNameArg, isGroupClassImported, staticGroupImports, fileName ) if (groupName !in groupMap) { throw InvalidProtoLogCallException("Unknown group argument " + "- not a ProtoLogGroup enum member: $call", context) errors.add(InvalidProtoLogCallException( "Unknown group argument " + "- not a ProtoLogGroup enum member: $call", context )) return@forEach } try { logCallVisitor?.processCall( call, messageString, getLevelForMethodName( call.name.toString(), call, context ), groupMap.getValue(groupName), context.lineNumber ) } catch (e: Throwable) { throw InvalidProtoLogCallException("Error processing log call: $call", context, e) } } else if (call.name.id == "init") { // No processing } else { // Process non-log message calls otherCallVisitor?.processCall(call) } } catch (e: Throwable) { errors.add(InvalidProtoLogCallException( "Error processing log call: $call", context, e )) } } return code return errors } private fun getLevelForMethodName( Loading
tools/protologtool/src/com/android/protolog/tool/ProtoLogTool.kt +19 −6 Original line number Diff line number Diff line Loading @@ -130,14 +130,16 @@ object ProtoLogTool { val outSrc = try { val code = tryParse(text, path) if (containsProtoLogText(text, PROTOLOG_CLASS_NAME)) { transformer.processClass(text, path, packagePath(file, code), code) val (processedText, errors) = transformer.processClass(text, path, packagePath(file, code), code) errors.forEach { injector.reportProcessingError(it) } processedText } else { text } } catch (ex: ParsingException) { // If we cannot parse this file, skip it (and log why). Compilation will // fail in a subsequent build step. injector.reportParseError(ex) injector.reportProcessingError(ex) text } path to outSrc Loading Loading @@ -405,7 +407,7 @@ object ProtoLogTool { } catch (ex: ParsingException) { // If we cannot parse this file, skip it (and log why). Compilation will // fail in a subsequent build step. injector.reportParseError(ex) injector.reportProcessingError(ex) null } } else { Loading Loading @@ -466,6 +468,14 @@ object ProtoLogTool { try { val command = CommandOptions(args) invoke(command) if (injector.processingErrors.isNotEmpty()) { injector.processingErrors.forEachIndexed { index, it -> println("CodeProcessingException " + "(${index + 1}/${injector.processingErrors.size}): \n${it.message}\n") } exitProcess(1) } } catch (ex: InvalidCommandException) { println("InvalidCommandException: \n${ex.message}\n") showHelpAndExit() Loading @@ -489,12 +499,14 @@ object ProtoLogTool { } var injector = object : Injector { override val processingErrors: MutableList<CodeProcessingException> get() = mutableListOf() override fun fileOutputStream(file: String) = FileOutputStream(file) override fun readText(file: File) = file.readText() override fun readLogGroups(jarPath: String, className: String) = ProtoLogGroupReader().loadFromJar(jarPath, className) override fun reportParseError(ex: ParsingException) { println("\n${ex.message}\n") override fun reportProcessingError(ex: CodeProcessingException) { processingErrors.add(ex) } } Loading @@ -502,7 +514,8 @@ object ProtoLogTool { fun fileOutputStream(file: String): OutputStream fun readText(file: File): String fun readLogGroups(jarPath: String, className: String): Map<String, LogGroup> fun reportParseError(ex: ParsingException) fun reportProcessingError(ex: CodeProcessingException) val processingErrors: Collection<CodeProcessingException> } } Loading
tools/protologtool/src/com/android/protolog/tool/SourceTransformer.kt +3 −3 Original line number Diff line number Diff line Loading @@ -66,13 +66,13 @@ class SourceTransformer( packagePath: String, compilationUnit: CompilationUnit = StaticJavaParser.parse(code) ): String { ): Pair<String, Collection<CodeProcessingException>> { this.path = path this.packagePath = packagePath processedCode = code.split('\n').toMutableList() offsets = IntArray(processedCode.size) protoLogCallProcessor.process(compilationUnit, protoLogCallVisitor, otherCallVisitor, path) return processedCode.joinToString("\n") val processingErrors = protoLogCallProcessor.process(compilationUnit, protoLogCallVisitor, otherCallVisitor, path) return Pair(processedCode.joinToString("\n"), processingErrors) } private val protoLogImplClassNode = Loading
tools/protologtool/tests/com/android/protolog/tool/EndToEndTest.kt +42 −1 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.protolog.tool import com.android.protolog.tool.ProtoLogTool.PROTOLOG_IMPL_SRC_PATH import com.android.protolog.tool.ProtoLogTool.injector import com.google.common.truth.Truth import java.io.ByteArrayInputStream import java.io.ByteArrayOutputStream Loading Loading @@ -102,6 +103,42 @@ class EndToEndTest { """.trimIndent()) } @Test fun e2e_transform_withErrors() { val srcs = mapOf( "frameworks/base/org/example/Example.java" to """ package org.example; import com.android.internal.protolog.ProtoLog; import static com.android.internal.protolog.ProtoLogGroup.GROUP; class Example { void method() { String argString = "hello"; int argInt = 123; ProtoLog.d(GROUP, "Invalid format: %s %d %9 %", argString, argInt); } } """.trimIndent()) val output = run( srcs = srcs, logGroup = LogGroup("GROUP", true, false, "TAG_GROUP"), commandOptions = CommandOptions(arrayOf("transform-protolog-calls", "--protolog-class", "com.android.internal.protolog.ProtoLog", "--loggroups-class", "com.android.internal.protolog.ProtoLogGroup", "--loggroups-jar", "not_required.jar", "--viewer-config-file-path", "not_required.pb", "--output-srcjar", "out.srcjar", "frameworks/base/org/example/Example.java")) ) val outSrcJar = assertLoadSrcJar(output, "out.srcjar") // No change to source code on failure to process Truth.assertThat(outSrcJar["frameworks/base/org/example/Example.java"]) .contains(srcs["frameworks/base/org/example/Example.java"]) Truth.assertThat(injector.processingErrors).hasSize(1) Truth.assertThat(injector.processingErrors.first().message).contains("Invalid format") } private fun assertLoadSrcJar( outputs: Map<String, ByteArray>, path: String Loading Loading @@ -172,7 +209,11 @@ class EndToEndTest { override fun readLogGroups(jarPath: String, className: String) = mapOf( logGroup.name to logGroup) override fun reportParseError(ex: ParsingException) = throw AssertionError(ex) override fun reportProcessingError(ex: CodeProcessingException) { processingErrors.add(ex) } override val processingErrors: MutableList<CodeProcessingException> = mutableListOf() } ProtoLogTool.invoke(commandOptions) Loading