/* * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.protolog.tool import com.android.json.stream.JsonWriter import com.github.javaparser.ast.CompilationUnit import com.android.protolog.tool.Constants.VERSION import com.github.javaparser.ast.expr.MethodCallExpr import java.io.StringWriter class ViewerConfigBuilder( private val processor: ProtoLogCallProcessor ) { private fun addLogCall(logCall: LogCall, context: ParsingContext) { val group = logCall.logGroup val messageString = logCall.messageString if (group.enabled) { val key = logCall.key() if (statements.containsKey(key)) { if (statements[key] != logCall) { throw HashCollisionException( "Please modify the log message \"$messageString\" " + "or \"${statements[key]}\" - their hashes are equal.", context) } } else { groups.add(group) statements[key] = logCall } } } private val statements: MutableMap = mutableMapOf() private val groups: MutableSet = mutableSetOf() fun findLogCalls( unit: CompilationUnit, path: String, packagePath: String ): List> { val calls = mutableListOf>() val visitor = object : ProtoLogCallVisitor { override fun processCall( call: MethodCallExpr, messageString: String, level: LogLevel, group: LogGroup ) { val logCall = LogCall(messageString, level, group, packagePath) val context = ParsingContext(path, call) calls.add(logCall to context) } } processor.process(unit, visitor, path) return calls } fun addLogCalls(calls: List>) { calls.forEach { (logCall, context) -> addLogCall(logCall, context) } } fun build(): String { val stringWriter = StringWriter() val writer = JsonWriter(stringWriter) writer.setIndent(" ") writer.beginObject() writer.name("version") writer.value(VERSION) writer.name("messages") writer.beginObject() statements.toSortedMap().forEach { (key, value) -> writer.name(key.toString()) writer.beginObject() writer.name("message") writer.value(value.messageString) writer.name("level") writer.value(value.logLevel.name) writer.name("group") writer.value(value.logGroup.name) writer.name("at") writer.value(value.position) writer.endObject() } writer.endObject() writer.name("groups") writer.beginObject() groups.toSortedSet(Comparator { o1, o2 -> o1.name.compareTo(o2.name) }).forEach { group -> writer.name(group.name) writer.beginObject() writer.name("tag") writer.value(group.tag) writer.endObject() } writer.endObject() writer.endObject() stringWriter.buffer.append('\n') return stringWriter.toString() } data class LogCall( val messageString: String, val logLevel: LogLevel, val logGroup: LogGroup, val position: String ) { fun key() = CodeUtils.hash(position, messageString, logLevel, logGroup) } }