• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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.android.tools.metalava.model.ClassItem
20 import com.android.tools.metalava.model.FilterPredicate
21 import com.android.tools.metalava.model.Import
22 import com.android.tools.metalava.model.SourceFile
23 import com.android.tools.metalava.model.item.DefaultCodebase
24 import com.google.turbine.diag.LineMap
25 import com.google.turbine.tree.Tree.CompUnit
26 import java.util.TreeSet
27 
28 internal class TurbineSourceFile(
29     val codebase: DefaultCodebase,
30     val compUnit: CompUnit,
31 ) : SourceFile {
32 
getHeaderCommentsnull33     override fun getHeaderComments() = getHeaderComments(compUnit.source().source())
34 
35     override fun classes(): Sequence<ClassItem> {
36         val pkgName = getPackageName(compUnit)
37         val classDecls = compUnit.decls() // Top level class declarations
38         val classNames = classDecls.map { pkgName + "." + it.name().value() }
39         return classNames.asSequence().mapNotNull { codebase.findClass(it) }
40     }
41 
equalsnull42     override fun equals(other: Any?): Boolean {
43         if (this === other) return true
44         return other is TurbineSourceFile && compUnit == other.compUnit
45     }
46 
hashCodenull47     override fun hashCode(): Int {
48         return compUnit.hashCode()
49     }
50 
getImportsnull51     override fun getImports(predicate: FilterPredicate): Collection<Import> {
52         val imports = TreeSet<Import>(compareBy { it.pattern })
53 
54         for (import in compUnit.imports()) {
55             val resolvedName = import.type().dotSeparatedName
56             // Package import
57             if (import.wild()) {
58                 val pkgItem = codebase.findPackage(resolvedName) ?: continue
59                 if (
60                     predicate.test(pkgItem) &&
61                         // Also make sure it isn't an empty package (after applying the
62                         // filter)
63                         // since in that case we'd have an invalid import
64                         pkgItem.topLevelClasses().any { it.emit && predicate.test(it) }
65                 ) {
66                     imports.add(Import(pkgItem))
67                 }
68             }
69             // Not static member import i.e. class import
70             else if (!import.stat()) {
71                 val classItem = codebase.resolveClass(resolvedName) ?: continue
72                 if (predicate.test(classItem)) {
73                     imports.add(Import(classItem))
74                 }
75             }
76         }
77 
78         // Next only keep those that are present in any docs; those are the only ones
79         // we need to import
80         if (imports.isNotEmpty()) {
81             return filterImports(imports, predicate)
82         }
83 
84         return emptyList()
85     }
86 
87     /**
88      * The [LineMap] used to map positions in the source file into line numbers.
89      *
90      * Created lazily as it can be expensive to create.
91      */
92     private val lineMap by
<lambda>null93         lazy(LazyThreadSafetyMode.NONE) { LineMap.create(compUnit.source().source()) }
94 
95     /**
96      * Get the line number for [position] which was retrieved from
97      * [com.google.turbine.tree.Tree.position].
98      */
lineForPositionnull99     fun lineForPosition(position: Int) = lineMap.lineNumber(position)
100 }
101