1 /* <lambda>null2 * Copyright (C) 2019 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.protolog.tool 18 19 import com.github.javaparser.ast.CompilationUnit 20 import com.github.javaparser.ast.expr.Expression 21 import com.github.javaparser.ast.expr.FieldAccessExpr 22 import com.github.javaparser.ast.expr.MethodCallExpr 23 import com.github.javaparser.ast.expr.NameExpr 24 25 /** 26 * Helper class for visiting all ProtoLog calls. 27 * For every valid call in the given {@code CompilationUnit} a {@code ProtoLogCallVisitor} callback 28 * is executed. 29 */ 30 open class ProtoLogCallProcessor( 31 private val protoLogClassName: String, 32 private val protoLogGroupClassName: String, 33 private val groupMap: Map<String, LogGroup> 34 ) { 35 private val protoLogSimpleClassName = protoLogClassName.substringAfterLast('.') 36 private val protoLogGroupSimpleClassName = protoLogGroupClassName.substringAfterLast('.') 37 38 private fun getLogGroupName( 39 expr: Expression, 40 isClassImported: Boolean, 41 staticImports: Set<String>, 42 fileName: String 43 ): String { 44 val context = ParsingContext(fileName, expr) 45 return when (expr) { 46 is NameExpr -> when { 47 expr.nameAsString in staticImports -> expr.nameAsString 48 else -> 49 throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr", 50 context) 51 } 52 is FieldAccessExpr -> when { 53 expr.scope.toString() == protoLogGroupClassName 54 || isClassImported && 55 expr.scope.toString() == protoLogGroupSimpleClassName -> expr.nameAsString 56 else -> 57 throw InvalidProtoLogCallException("Unknown/not imported ProtoLogGroup: $expr", 58 context) 59 } 60 else -> throw InvalidProtoLogCallException("Invalid group argument " + 61 "- must be ProtoLogGroup enum member reference: $expr", context) 62 } 63 } 64 65 private fun isProtoCall( 66 call: MethodCallExpr, 67 isLogClassImported: Boolean, 68 staticLogImports: Collection<String> 69 ): Boolean { 70 return call.scope.isPresent && call.scope.get().toString() == protoLogClassName || 71 isLogClassImported && call.scope.isPresent && 72 call.scope.get().toString() == protoLogSimpleClassName || 73 !call.scope.isPresent && staticLogImports.contains(call.name.toString()) 74 } 75 76 open fun process(code: CompilationUnit, callVisitor: ProtoLogCallVisitor?, fileName: String): 77 CompilationUnit { 78 CodeUtils.checkWildcardStaticImported(code, protoLogClassName, fileName) 79 CodeUtils.checkWildcardStaticImported(code, protoLogGroupClassName, fileName) 80 81 val isLogClassImported = CodeUtils.isClassImportedOrSamePackage(code, protoLogClassName) 82 val staticLogImports = CodeUtils.staticallyImportedMethods(code, protoLogClassName) 83 val isGroupClassImported = CodeUtils.isClassImportedOrSamePackage(code, 84 protoLogGroupClassName) 85 val staticGroupImports = CodeUtils.staticallyImportedMethods(code, protoLogGroupClassName) 86 87 code.findAll(MethodCallExpr::class.java) 88 .filter { call -> 89 isProtoCall(call, isLogClassImported, staticLogImports) 90 }.forEach { call -> 91 val context = ParsingContext(fileName, call) 92 if (call.arguments.size < 2) { 93 throw InvalidProtoLogCallException("Method signature does not match " + 94 "any ProtoLog method: $call", context) 95 } 96 97 val messageString = CodeUtils.concatMultilineString(call.getArgument(1), 98 context) 99 val groupNameArg = call.getArgument(0) 100 val groupName = 101 getLogGroupName(groupNameArg, isGroupClassImported, 102 staticGroupImports, fileName) 103 if (groupName !in groupMap) { 104 throw InvalidProtoLogCallException("Unknown group argument " + 105 "- not a ProtoLogGroup enum member: $call", context) 106 } 107 108 callVisitor?.processCall(call, messageString, LogLevel.getLevelForMethodName( 109 call.name.toString(), call, context), groupMap.getValue(groupName)) 110 } 111 return code 112 } 113 } 114