• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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.psi
18 
19 import com.android.tools.metalava.model.ClassItem
20 import com.android.tools.metalava.model.PackageItem
21 import com.intellij.psi.PsiPackage
22 
23 class PsiPackageItem(
24     override val codebase: PsiBasedCodebase,
25     private val psiPackage: PsiPackage,
26     private val qualifiedName: String,
27     modifiers: PsiModifierItem,
28     documentation: String
29 ) :
30     PsiItem(
31         codebase = codebase,
32         modifiers = modifiers,
33         documentation = documentation,
34         element = psiPackage
35     ), PackageItem {
36     // Note - top level classes only
37     private val classes: MutableList<PsiClassItem> = mutableListOf()
38 
<lambda>null39     override fun topLevelClasses(): Sequence<ClassItem> = classes.asSequence().filter { it.isTopLevelClass() }
40 
41     lateinit var containingPackageField: PsiPackageItem
42 
containingClassnull43     override fun containingClass(strict: Boolean): ClassItem? = null
44 
45     override fun containingPackage(strict: Boolean): PackageItem? {
46         if (!strict) {
47             return this
48         }
49         return if (qualifiedName.isEmpty()) null else {
50             if (!::containingPackageField.isInitialized) {
51                 var parentPackage = qualifiedName
52                 while (true) {
53                     val index = parentPackage.lastIndexOf('.')
54                     if (index == -1) {
55                         containingPackageField = codebase.findPackage("")!!
56                         return containingPackageField
57                     }
58                     parentPackage = parentPackage.substring(0, index)
59                     val pkg = codebase.findPackage(parentPackage)
60                     if (pkg != null) {
61                         containingPackageField = pkg
62                         return pkg
63                     }
64                 }
65 
66                 @Suppress("UNREACHABLE_CODE")
67                 null
68             } else {
69                 containingPackageField
70             }
71         }
72     }
73 
addClassnull74     fun addClass(cls: PsiClassItem) {
75         if (!cls.isTopLevelClass()) {
76             // TODO: Stash in a list somewhere to make allClasses() faster?
77             return
78         }
79 
80         /*
81         // Temp debugging:
82         val q = cls.qualifiedName()
83         for (c in classes) {
84             if (q == c.qualifiedName()) {
85                 assert(false, { "Unexpectedly found class $q already listed in $this" })
86                 return
87             }
88         }
89         */
90 
91         classes.add(cls)
92         cls.containingPackage = this
93     }
94 
addClassesnull95     fun addClasses(classList: List<PsiClassItem>) {
96         for (cls in classList) {
97             addClass(cls)
98         }
99     }
100 
qualifiedNamenull101     override fun qualifiedName(): String = qualifiedName
102 
103     override fun equals(other: Any?): Boolean {
104         if (this === other) {
105             return true
106         }
107         return other is PackageItem && qualifiedName == other.qualifiedName()
108     }
109 
hashCodenull110     override fun hashCode(): Int = qualifiedName.hashCode()
111 
112     override fun toString(): String = "package $qualifiedName"
113 
114     override fun finishInitialization() {
115         super.finishInitialization()
116         val initialClasses = ArrayList(classes)
117         var original = initialClasses.size // classes added after this point will have indices >= original
118         for (cls in initialClasses) {
119             cls.finishInitialization()
120         }
121 
122         // Finish initialization of any additional classes that were registered during
123         // the above initialization (recursively)
124         while (original < classes.size) {
125             val added = ArrayList(classes.subList(original, classes.size))
126             original = classes.size
127             for (cls in added) {
128                 cls.finishInitialization()
129             }
130         }
131     }
132 
133     companion object {
createnull134         fun create(codebase: PsiBasedCodebase, psiPackage: PsiPackage, extraDocs: String?): PsiPackageItem {
135             val commentText = javadoc(psiPackage) + if (extraDocs != null) "\n$extraDocs" else ""
136             val modifiers = modifiers(codebase, psiPackage, commentText)
137             if (modifiers.isPackagePrivate()) {
138                 modifiers.setPublic(true) // packages are always public (if not hidden explicitly with private)
139             }
140             val qualifiedName = psiPackage.qualifiedName
141 
142             val pkg = PsiPackageItem(
143                 codebase = codebase,
144                 psiPackage = psiPackage,
145                 qualifiedName = qualifiedName,
146                 documentation = commentText,
147                 modifiers = modifiers
148             )
149             pkg.modifiers.setOwner(pkg)
150             return pkg
151         }
152 
createnull153         fun create(codebase: PsiBasedCodebase, original: PsiPackageItem): PsiPackageItem {
154             val pkg = PsiPackageItem(
155                 codebase = codebase,
156                 psiPackage = original.psiPackage,
157                 qualifiedName = original.qualifiedName,
158                 documentation = original.documentation,
159                 modifiers = PsiModifierItem.create(codebase, original.modifiers)
160             )
161             pkg.modifiers.setOwner(pkg)
162             return pkg
163         }
164     }
165 }