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.android.json.stream.JsonWriter 20 import com.github.javaparser.ast.CompilationUnit 21 import com.android.protolog.tool.Constants.VERSION 22 import com.github.javaparser.ast.expr.MethodCallExpr 23 import java.io.StringWriter 24 25 class ViewerConfigBuilder( 26 private val processor: ProtoLogCallProcessor 27 ) { 28 private fun addLogCall(logCall: LogCall, context: ParsingContext) { 29 val group = logCall.logGroup 30 val messageString = logCall.messageString 31 if (group.enabled) { 32 val key = logCall.key() 33 if (statements.containsKey(key)) { 34 if (statements[key] != logCall) { 35 throw HashCollisionException( 36 "Please modify the log message \"$messageString\" " + 37 "or \"${statements[key]}\" - their hashes are equal.", context) 38 } 39 } else { 40 groups.add(group) 41 statements[key] = logCall 42 } 43 } 44 } 45 46 private val statements: MutableMap<Int, LogCall> = mutableMapOf() 47 private val groups: MutableSet<LogGroup> = mutableSetOf() 48 49 fun findLogCalls( 50 unit: CompilationUnit, 51 path: String, 52 packagePath: String 53 ): List<Pair<LogCall, ParsingContext>> { 54 val calls = mutableListOf<Pair<LogCall, ParsingContext>>() 55 val visitor = object : ProtoLogCallVisitor { 56 override fun processCall( 57 call: MethodCallExpr, 58 messageString: String, 59 level: LogLevel, 60 group: LogGroup 61 ) { 62 val logCall = LogCall(messageString, level, group, packagePath) 63 val context = ParsingContext(path, call) 64 calls.add(logCall to context) 65 } 66 } 67 processor.process(unit, visitor, path) 68 69 return calls 70 } 71 72 fun addLogCalls(calls: List<Pair<LogCall, ParsingContext>>) { 73 calls.forEach { (logCall, context) -> 74 addLogCall(logCall, context) 75 } 76 } 77 78 fun build(): String { 79 val stringWriter = StringWriter() 80 val writer = JsonWriter(stringWriter) 81 writer.setIndent(" ") 82 writer.beginObject() 83 writer.name("version") 84 writer.value(VERSION) 85 writer.name("messages") 86 writer.beginObject() 87 statements.toSortedMap().forEach { (key, value) -> 88 writer.name(key.toString()) 89 writer.beginObject() 90 writer.name("message") 91 writer.value(value.messageString) 92 writer.name("level") 93 writer.value(value.logLevel.name) 94 writer.name("group") 95 writer.value(value.logGroup.name) 96 writer.name("at") 97 writer.value(value.position) 98 writer.endObject() 99 } 100 writer.endObject() 101 writer.name("groups") 102 writer.beginObject() 103 groups.toSortedSet(Comparator { o1, o2 -> o1.name.compareTo(o2.name) }).forEach { group -> 104 writer.name(group.name) 105 writer.beginObject() 106 writer.name("tag") 107 writer.value(group.tag) 108 writer.endObject() 109 } 110 writer.endObject() 111 writer.endObject() 112 stringWriter.buffer.append('\n') 113 return stringWriter.toString() 114 } 115 116 data class LogCall( 117 val messageString: String, 118 val logLevel: LogLevel, 119 val logGroup: LogGroup, 120 val position: String 121 ) { 122 fun key() = CodeUtils.hash(position, messageString, logLevel, logGroup) 123 } 124 } 125