xref: /aosp_15_r20/external/ksp/common-util/src/main/kotlin/com/google/devtools/ksp/PsiUtils.kt (revision af87fb4bb8e3042070d2a054e912924f599b22b7)
1 /*
2  * Copyright 2022 Google LLC
3  * Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 package com.google.devtools.ksp
19 
20 import com.google.devtools.ksp.symbol.*
21 import com.intellij.lang.jvm.JvmModifier
22 import com.intellij.openapi.project.Project
23 import com.intellij.psi.PsiComment
24 import com.intellij.psi.PsiDocumentManager
25 import com.intellij.psi.PsiElement
26 import com.intellij.psi.PsiFile
27 import com.intellij.psi.PsiModifierListOwner
28 import org.jetbrains.kotlin.lexer.KtTokens
29 import org.jetbrains.kotlin.psi.KtClass
30 import org.jetbrains.kotlin.psi.KtClassOrObject
31 import org.jetbrains.kotlin.psi.KtEnumEntry
32 import org.jetbrains.kotlin.psi.KtModifierList
33 import org.jetbrains.kotlin.psi.KtModifierListOwner
34 import org.jetbrains.kotlin.psi.KtObjectDeclaration
35 import org.jetbrains.kotlin.psi.psiUtil.siblings
36 
37 val jvmModifierMap = mapOf(
38     JvmModifier.PUBLIC to Modifier.PUBLIC,
39     JvmModifier.PRIVATE to Modifier.PRIVATE,
40     JvmModifier.ABSTRACT to Modifier.ABSTRACT,
41     JvmModifier.FINAL to Modifier.FINAL,
42     JvmModifier.PROTECTED to Modifier.PROTECTED,
43     JvmModifier.STATIC to Modifier.JAVA_STATIC,
44     JvmModifier.STRICTFP to Modifier.JAVA_STRICT,
45     JvmModifier.NATIVE to Modifier.JAVA_NATIVE,
46     JvmModifier.SYNCHRONIZED to Modifier.JAVA_SYNCHRONIZED,
47     JvmModifier.TRANSIENT to Modifier.JAVA_TRANSIENT,
48     JvmModifier.VOLATILE to Modifier.JAVA_VOLATILE
49 )
50 
51 val javaModifiers = setOf(
52     Modifier.ABSTRACT,
53     Modifier.FINAL,
54     Modifier.JAVA_DEFAULT,
55     Modifier.JAVA_NATIVE,
56     Modifier.JAVA_STATIC,
57     Modifier.JAVA_STRICT,
58     Modifier.JAVA_SYNCHRONIZED,
59     Modifier.JAVA_TRANSIENT,
60     Modifier.JAVA_VOLATILE,
61     Modifier.PRIVATE,
62     Modifier.PROTECTED,
63     Modifier.PUBLIC,
64 )
65 
66 val modifierMap = mapOf(
67     KtTokens.PUBLIC_KEYWORD to Modifier.PUBLIC,
68     KtTokens.PRIVATE_KEYWORD to Modifier.PRIVATE,
69     KtTokens.INTERNAL_KEYWORD to Modifier.INTERNAL,
70     KtTokens.PROTECTED_KEYWORD to Modifier.PROTECTED,
71     KtTokens.IN_KEYWORD to Modifier.IN,
72     KtTokens.OUT_KEYWORD to Modifier.OUT,
73     KtTokens.OVERRIDE_KEYWORD to Modifier.OVERRIDE,
74     KtTokens.LATEINIT_KEYWORD to Modifier.LATEINIT,
75     KtTokens.ENUM_KEYWORD to Modifier.ENUM,
76     KtTokens.SEALED_KEYWORD to Modifier.SEALED,
77     KtTokens.ANNOTATION_KEYWORD to Modifier.ANNOTATION,
78     KtTokens.DATA_KEYWORD to Modifier.DATA,
79     KtTokens.INNER_KEYWORD to Modifier.INNER,
80     KtTokens.FUN_KEYWORD to Modifier.FUN,
81     KtTokens.VALUE_KEYWORD to Modifier.VALUE,
82     KtTokens.SUSPEND_KEYWORD to Modifier.SUSPEND,
83     KtTokens.TAILREC_KEYWORD to Modifier.TAILREC,
84     KtTokens.OPERATOR_KEYWORD to Modifier.OPERATOR,
85     KtTokens.INFIX_KEYWORD to Modifier.INFIX,
86     KtTokens.INLINE_KEYWORD to Modifier.INLINE,
87     KtTokens.EXTERNAL_KEYWORD to Modifier.EXTERNAL,
88     KtTokens.ABSTRACT_KEYWORD to Modifier.ABSTRACT,
89     KtTokens.FINAL_KEYWORD to Modifier.FINAL,
90     KtTokens.OPEN_KEYWORD to Modifier.OPEN,
91     KtTokens.VARARG_KEYWORD to Modifier.VARARG,
92     KtTokens.NOINLINE_KEYWORD to Modifier.NOINLINE,
93     KtTokens.CROSSINLINE_KEYWORD to Modifier.CROSSINLINE,
94     KtTokens.REIFIED_KEYWORD to Modifier.REIFIED,
95     KtTokens.EXPECT_KEYWORD to Modifier.EXPECT,
96     KtTokens.ACTUAL_KEYWORD to Modifier.ACTUAL,
97     KtTokens.CONST_KEYWORD to Modifier.CONST
98 )
99 
toKSModifiersnull100 fun KtModifierList?.toKSModifiers(): Set<Modifier> {
101     if (this == null)
102         return emptySet()
103     val modifiers = mutableSetOf<Modifier>()
104     modifiers.addAll(
105         modifierMap.entries
106             .filter { hasModifier(it.key) }
107             .map { it.value }
108     )
109     return modifiers
110 }
111 
KtModifierListOwnernull112 fun KtModifierListOwner.toKSModifiers(): Set<Modifier> {
113     val modifierList = this.modifierList
114     return modifierList.toKSModifiers()
115 }
116 
toKSModifiersnull117 fun PsiModifierListOwner.toKSModifiers(): Set<Modifier> {
118     val modifiers = mutableSetOf<Modifier>()
119     modifiers.addAll(
120         jvmModifierMap.entries.filter { this.hasModifier(it.key) }
121             .map { it.value }
122             .toSet()
123     )
124     if (this.modifierList?.hasExplicitModifier("default") == true) {
125         modifiers.add(Modifier.JAVA_DEFAULT)
126     }
127     return modifiers
128 }
129 
Projectnull130 fun Project.findLocationString(file: PsiFile, offset: Int): String {
131     val psiDocumentManager = PsiDocumentManager.getInstance(this)
132     val document = psiDocumentManager.getDocument(file) ?: return "<unknown>"
133     val lineNumber = document.getLineNumber(offset)
134     val offsetInLine = offset - document.getLineStartOffset(lineNumber)
135     return "${file.virtualFile.path}: (${lineNumber + 1}, ${offsetInLine + 1})"
136 }
137 
parseDocStringnull138 private fun parseDocString(raw: String): String? {
139     val t1 = raw.trim()
140     if (!t1.startsWith("/**") || !t1.endsWith("*/"))
141         return null
142     val lineSep = t1.findAnyOf(listOf("\r\n", "\n", "\r"))?.second ?: ""
143     return t1.trim('/').trim('*').lines().joinToString(lineSep) {
144         it.trimStart().trimStart('*')
145     }
146 }
147 
getDocStringnull148 fun PsiElement.getDocString(): String? =
149     this.firstChild.siblings().firstOrNull { it is PsiComment }?.let {
150         parseDocString(it.text)
151     }
152 
KtClassOrObjectnull153 fun KtClassOrObject.getClassType(): ClassKind {
154     return when (this) {
155         is KtObjectDeclaration -> ClassKind.OBJECT
156         is KtEnumEntry -> ClassKind.ENUM_ENTRY
157         is KtClass -> when {
158             this.isEnum() -> ClassKind.ENUM_CLASS
159             this.isInterface() -> ClassKind.INTERFACE
160             this.isAnnotation() -> ClassKind.ANNOTATION_CLASS
161             else -> ClassKind.CLASS
162         }
163         else -> throw IllegalStateException("Unexpected psi type ${this.javaClass}, $ExceptionMessage")
164     }
165 }
166 
findParentOfTypenull167 inline fun <reified T> PsiElement.findParentOfType(): T? {
168     var parent = this.parent
169     while (parent != null && parent !is T) {
170         parent = parent.parent
171     }
172     return parent as? T
173 }
174 
memoizednull175 fun <T> Sequence<T>.memoized() = MemoizedSequence(this)
176