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.ImportDeclaration
21 import com.github.javaparser.ast.expr.BinaryExpr
22 import com.github.javaparser.ast.expr.Expression
23 import com.github.javaparser.ast.expr.StringLiteralExpr
24 
25 object CodeUtils {
26     /**
27      * Returns a stable hash of a string.
28      * We reimplement String::hashCode() for readability reasons.
29      */
30     fun hash(position: String, messageString: String, logLevel: LogLevel, logGroup: LogGroup): Int {
31         return (position + messageString + logLevel.name + logGroup.name)
32                 .map { c -> c.toInt() }.reduce { h, c -> h * 31 + c }
33     }
34 
35     fun checkWildcardStaticImported(code: CompilationUnit, className: String, fileName: String) {
36         code.findAll(ImportDeclaration::class.java)
37                 .forEach { im ->
38                     if (im.isStatic && im.isAsterisk && im.name.toString() == className) {
39                         throw IllegalImportException("Wildcard static imports of $className " +
40                                 "methods are not supported.", ParsingContext(fileName, im))
41                     }
42                 }
43     }
44 
45     fun isClassImportedOrSamePackage(code: CompilationUnit, className: String): Boolean {
46         val packageName = className.substringBeforeLast('.')
47         return code.packageDeclaration.isPresent &&
48                 code.packageDeclaration.get().nameAsString == packageName ||
49                 code.findAll(ImportDeclaration::class.java)
50                         .any { im ->
51                             !im.isStatic &&
52                                     ((!im.isAsterisk && im.name.toString() == className) ||
53                                             (im.isAsterisk && im.name.toString() == packageName))
54                         }
55     }
56 
57     fun staticallyImportedMethods(code: CompilationUnit, className: String): Set<String> {
58         return code.findAll(ImportDeclaration::class.java)
59                 .filter { im ->
60                     im.isStatic &&
61                             im.name.toString().substringBeforeLast('.') == className
62                 }
63                 .map { im -> im.name.toString().substringAfterLast('.') }.toSet()
64     }
65 
66     fun concatMultilineString(expr: Expression, context: ParsingContext): String {
67         return when (expr) {
68             is StringLiteralExpr -> expr.asString()
69             is BinaryExpr -> when {
70                 expr.operator == BinaryExpr.Operator.PLUS ->
71                     concatMultilineString(expr.left, context) +
72                             concatMultilineString(expr.right, context)
73                 else -> throw InvalidProtoLogCallException(
74                         "expected a string literal " +
75                                 "or concatenation of string literals, got: $expr", context)
76             }
77             else -> throw InvalidProtoLogCallException("expected a string literal " +
78                     "or concatenation of string literals, got: $expr", context)
79         }
80     }
81 }
82