1 /*
2 * Copyright (C) 2024 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.tools.metalava.model.turbine
18
19 import com.google.turbine.binder.bound.EnumConstantValue
20 import com.google.turbine.binder.bound.TurbineClassValue
21 import com.google.turbine.binder.sym.ClassSymbol
22 import com.google.turbine.model.Const
23 import com.google.turbine.model.Const.Kind
24 import com.google.turbine.model.Const.Value
25 import com.google.turbine.tree.Tree.CompUnit
26 import com.google.turbine.tree.Tree.Ident
27
28 /**
29 * Extracts the package name from a provided compilation unit.
30 *
31 * @param unit The compilation unit from which to extract the package.
32 * @return The extracted package name (e.g., "com.example.project"), or an empty string if no
33 * package is present.
34 */
getPackageNamenull35 internal fun getPackageName(unit: CompUnit): String {
36 val optPkg = unit.pkg()
37 val pkg = if (optPkg.isPresent()) optPkg.get() else null
38 return pkg?.name()?.dotSeparatedName ?: ""
39 }
40
41 /**
42 * Creates a dot-separated name from a list of [Ident] objects.
43 *
44 * This is often used for constructing fully qualified names or package structures.
45 *
46 * @param this@extractNameFromIdent The list of [Ident] objects representing name segments.
47 * @return The combined name with segments joined by "." (e.g., "java.util.List")
48 */
49 internal val List<Ident>.dotSeparatedName: String
50 get() {
<lambda>null51 val nameList = map { it.value() }
52 return nameList.joinToString(separator = ".")
53 }
54
55 /**
56 * Extracts header comments from a source file string. Header comments are defined as any content
57 * appearing before the "package" keyword.
58 *
59 * @param source The source file string.
60 * @return The extracted header comments, or an empty string if no "package" keyword or comments are
61 * found.
62 */
getHeaderCommentsnull63 internal fun getHeaderComments(source: String): String {
64 val packageIndex = source.indexOf("package")
65 // Return everything before "package" keyword
66 return if (packageIndex == -1) "" else source.substring(0, packageIndex)
67 }
68
69 /**
70 * Get the qualified name, i.e. what would be used in an `import` statement, for this [ClassSymbol].
71 */
72 internal val ClassSymbol.qualifiedName: String
73 get() = binaryName().replace('/', '.').replace('$', '.')
74
75 /**
76 * The underlying value of this [Const].
77 *
78 * e.g. [Integer] for integers, [String]s for strings and any other values.
79 */
80 internal val Const.underlyingValue: Any?
81 get() {
82 when (kind()) {
83 Kind.PRIMITIVE -> {
84 val value = this as Value
85 return value.value
86 }
87 // For cases like AnyClass.class, return the qualified name of AnyClass
88 Kind.CLASS_LITERAL -> {
89 val value = this as TurbineClassValue
90 return value.type().toString()
91 }
92 Kind.ENUM_CONSTANT -> {
93 val value = this as EnumConstantValue
94 val temp = "${value.sym().owner().qualifiedName}.$value"
95 return temp
96 }
97 else -> {
98 return toString()
99 }
100 }
101 }
102
103 internal val ClassSymbol.dotSeparatedPackageName
104 get() = packageName().replace('/', '.')
105