• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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