[Analysis API] optimize KotlinPackageProvider.getSubPackageFqNames
Previously, we queried heavy kotlin package provider two times which affected performance Now it's being queries only a single time Also, the commit introduces separation for KotlinPackageProvider between kotlin and platform-specific packages ^KTIJ-24640
This commit is contained in:
committed by
Space Team
parent
c940eb25b0
commit
4944b454c5
+1
-4
@@ -6,7 +6,6 @@
|
|||||||
package org.jetbrains.kotlin.analysis.api.fir
|
package org.jetbrains.kotlin.analysis.api.fir
|
||||||
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.JavaPsiFacade
|
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.util.containers.ContainerUtil
|
import com.intellij.util.containers.ContainerUtil
|
||||||
import org.jetbrains.kotlin.analysis.api.KtStarTypeProjection
|
import org.jetbrains.kotlin.analysis.api.KtStarTypeProjection
|
||||||
@@ -107,9 +106,7 @@ internal class KtSymbolByFirBuilder constructor(
|
|||||||
private val packageProvider = project.createPackageProvider(GlobalSearchScope.allScope(project))//todo scope
|
private val packageProvider = project.createPackageProvider(GlobalSearchScope.allScope(project))//todo scope
|
||||||
|
|
||||||
fun createPackageSymbolIfOneExists(packageFqName: FqName): KtFirPackageSymbol? {
|
fun createPackageSymbolIfOneExists(packageFqName: FqName): KtFirPackageSymbol? {
|
||||||
val exists =
|
val exists = packageProvider.doesPackageExist(packageFqName, analysisSession.targetPlatform)
|
||||||
packageProvider.doKotlinPackageExists(packageFqName)
|
|
||||||
|| JavaPsiFacade.getInstance(project).findPackage(packageFqName.asString()) != null
|
|
||||||
if (!exists) {
|
if (!exists) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-16
@@ -26,7 +26,6 @@ import org.jetbrains.kotlin.fir.scopes.impl.FirPackageMemberScope
|
|||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||||
import org.jetbrains.kotlin.platform.jvm.isJvm
|
|
||||||
|
|
||||||
internal class KtFirPackageScope(
|
internal class KtFirPackageScope(
|
||||||
private val fqName: FqName,
|
private val fqName: FqName,
|
||||||
@@ -111,21 +110,8 @@ internal class KtFirPackageScope(
|
|||||||
|
|
||||||
override fun getPackageSymbols(nameFilter: KtScopeNameFilter): Sequence<KtPackageSymbol> = withValidityAssertion {
|
override fun getPackageSymbols(nameFilter: KtScopeNameFilter): Sequence<KtPackageSymbol> = withValidityAssertion {
|
||||||
sequence {
|
sequence {
|
||||||
if (targetPlatform.isJvm()) {
|
packageProvider.getSubPackageFqNames(fqName, targetPlatform, nameFilter).forEach {
|
||||||
val javaPackage = JavaPsiFacade.getInstance(project).findPackage(fqName.asString())
|
yield(builder.createPackageSymbol(fqName.child(it)))
|
||||||
if (javaPackage != null) {
|
|
||||||
for (psiPackage in javaPackage.getSubPackages(searchScope)) {
|
|
||||||
val fqName = FqName(psiPackage.qualifiedName)
|
|
||||||
if (nameFilter(fqName.shortName())) {
|
|
||||||
yield(builder.createPackageSymbol(fqName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
packageProvider.getKotlinSubPackageFqNames(fqName).forEach {
|
|
||||||
if (nameFilter(it)) {
|
|
||||||
yield(builder.createPackageSymbol(fqName.child(it)))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -65,5 +65,5 @@ class KtPackage(
|
|||||||
) : PsiPackageImpl(manager, fqName.asString().replace('/', '.')) {
|
) : PsiPackageImpl(manager, fqName.asString().replace('/', '.')) {
|
||||||
override fun copy() = KtPackage(manager, fqName, scope)
|
override fun copy() = KtPackage(manager, fqName, scope)
|
||||||
|
|
||||||
override fun isValid(): Boolean = project.createPackageProvider(scope).doKotlinPackageExists(fqName)
|
override fun isValid(): Boolean = project.createPackageProvider(scope).doesKotlinOnlyPackageExist(fqName)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -39,7 +39,7 @@ object AnalysisApiBaseTestServiceRegistrar: AnalysisApiTestServiceRegistrar() {
|
|||||||
registerService(KtModuleScopeProvider::class.java, KtModuleScopeProviderImpl())
|
registerService(KtModuleScopeProvider::class.java, KtModuleScopeProviderImpl())
|
||||||
registerService(KotlinAnnotationsResolverFactory::class.java, KotlinStaticAnnotationsResolverFactory(allKtFiles))
|
registerService(KotlinAnnotationsResolverFactory::class.java, KotlinStaticAnnotationsResolverFactory(allKtFiles))
|
||||||
registerService(KotlinDeclarationProviderFactory::class.java, KotlinStaticDeclarationProviderFactory(project, allKtFiles))
|
registerService(KotlinDeclarationProviderFactory::class.java, KotlinStaticDeclarationProviderFactory(project, allKtFiles))
|
||||||
registerService(KotlinPackageProviderFactory::class.java, KotlinStaticPackageProviderFactory(allKtFiles))
|
registerService(KotlinPackageProviderFactory::class.java, KotlinStaticPackageProviderFactory(project, allKtFiles))
|
||||||
registerService(KotlinReferenceProvidersService::class.java, HLApiReferenceProviderService::class.java)
|
registerService(KotlinReferenceProvidersService::class.java, HLApiReferenceProviderService::class.java)
|
||||||
registerService(KotlinResolutionScopeProvider::class.java, KotlinByModulesResolutionScopeProvider::class.java)
|
registerService(KotlinResolutionScopeProvider::class.java, KotlinByModulesResolutionScopeProvider::class.java)
|
||||||
}
|
}
|
||||||
|
|||||||
+55
-7
@@ -10,19 +10,67 @@ import com.intellij.openapi.project.Project
|
|||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides information about Kotlin packages in the given scope. Can be constructed via [KotlinPackageProviderFactory]
|
* Provides information about packages that are visible to Kotlin in the given scope. Can be constructed via [KotlinPackageProviderFactory].
|
||||||
* [doKotlinPackageExists] is called very often by a FIR compiler. And implementations should consider cache results.
|
* The FIR compiler calls [doesKotlinOnlyPackageExist] very often, so the implementations should consider caching the results.
|
||||||
*/
|
*/
|
||||||
public abstract class KotlinPackageProvider {
|
public abstract class KotlinPackageProvider {
|
||||||
/**
|
/**
|
||||||
* Checks if a package with given [FqName] exists in current [GlobalSearchScope].
|
* Checks if a package with given [FqName] exists in current [GlobalSearchScope] with a view from a given [platform].
|
||||||
* Note, that for Kotlin it is not mandatory for a package to correspond to a directory structure like in Java.
|
*
|
||||||
* So, a package [FqName] is determined by Kotlin files package directive.
|
* This includes Kotlin packages as well as platform-specific (i.e., JVM packages) that match the [platform].
|
||||||
|
* Generally, the result is equal to [doesKotlinOnlyPackageExist] || [doesPlatformSpecificPackageExist].
|
||||||
*/
|
*/
|
||||||
public abstract fun doKotlinPackageExists(packageFqName: FqName): Boolean
|
public abstract fun doesPackageExist(packageFqName: FqName, platform: TargetPlatform): Boolean
|
||||||
public abstract fun getKotlinSubPackageFqNames(packageFqName: FqName): Set<Name>
|
|
||||||
|
/**
|
||||||
|
* Checks if a package with a given [FqName] exists in the current [GlobalSearchScope].
|
||||||
|
*
|
||||||
|
* The package should contain Kotlin declarations inside.
|
||||||
|
*
|
||||||
|
* Note that for Kotlin, a package doesn't need to correspond to a directory structure like in Java.
|
||||||
|
* So, a package [FqName] is determined by a Kotlin file package directive.
|
||||||
|
*/
|
||||||
|
public abstract fun doesKotlinOnlyPackageExist(packageFqName: FqName): Boolean
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if a platform-specific (e.g., Java packages for Kotlin/JVM) package with [FqName] exists in the current [GlobalSearchScope].
|
||||||
|
*/
|
||||||
|
public abstract fun doesPlatformSpecificPackageExist(packageFqName: FqName, platform: TargetPlatform): Boolean
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of subpackages for a given package, which satisfies [nameFilter].
|
||||||
|
*
|
||||||
|
* The returned sub-package list contains sub-packages visible to Kotlin. (e.g., for Kotlin/JVM, it should include Java packages)
|
||||||
|
*
|
||||||
|
* Generally, the result is equal to [getKotlinOnlySubPackagesFqNames] union with [getPlatformSpecificSubPackagesFqNames]
|
||||||
|
*/
|
||||||
|
public abstract fun getSubPackageFqNames(
|
||||||
|
packageFqName: FqName,
|
||||||
|
platform: TargetPlatform,
|
||||||
|
nameFilter: (Name) -> Boolean
|
||||||
|
): Set<Name>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the list of subpackages for a given package, which satisfies [nameFilter].
|
||||||
|
*
|
||||||
|
* The returned sub-package list contains all packages with some Kotlin declarations inside.
|
||||||
|
*/
|
||||||
|
public abstract fun getKotlinOnlySubPackagesFqNames(packageFqName: FqName, nameFilter: (Name) -> Boolean): Set<Name>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the platform-specific (e.g., Java packages for Kotlin/JVM) list of subpackages for a given package, which satisfies [nameFilter].
|
||||||
|
*
|
||||||
|
* The returned sub-package list contains sub-packages visible to Kotlin. (e.g., for Kotlin/JVM, it should include Java packages)
|
||||||
|
*/
|
||||||
|
public abstract fun getPlatformSpecificSubPackagesFqNames(
|
||||||
|
packageFqName: FqName,
|
||||||
|
platform: TargetPlatform,
|
||||||
|
nameFilter: (Name) -> Boolean
|
||||||
|
): Set<Name>
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract class KotlinPackageProviderFactory {
|
public abstract class KotlinPackageProviderFactory {
|
||||||
|
|||||||
+94
@@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.analysis.providers.impl
|
||||||
|
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
|
import com.intellij.psi.PsiElementFinder
|
||||||
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
|
import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||||
|
import org.jetbrains.kotlin.platform.jvm.isJvm
|
||||||
|
|
||||||
|
|
||||||
|
public abstract class KotlinPackageProviderBase(
|
||||||
|
protected val
|
||||||
|
project: Project,
|
||||||
|
protected val searchScope: GlobalSearchScope
|
||||||
|
) : KotlinPackageProvider() {
|
||||||
|
|
||||||
|
override fun doesPackageExist(packageFqName: FqName, platform: TargetPlatform): Boolean {
|
||||||
|
return doesPlatformSpecificPackageExist(packageFqName, platform) || doesKotlinOnlyPackageExist(packageFqName)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun doesPlatformSpecificPackageExist(packageFqName: FqName, platform: TargetPlatform): Boolean {
|
||||||
|
when {
|
||||||
|
platform.isJvm() -> {
|
||||||
|
val fqNameString = packageFqName.asString()
|
||||||
|
forEachNonKotlinPsiElementFinder { finder ->
|
||||||
|
val psiPackage = finder.findPackage(fqNameString)
|
||||||
|
if (psiPackage != null) {
|
||||||
|
// we cannot easily check if some PsiPackage is in GlobalSearchScope or not
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// non-JVM platforms are not supported yet
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSubPackageFqNames(packageFqName: FqName, platform: TargetPlatform, nameFilter: (Name) -> Boolean): Set<Name> =
|
||||||
|
buildSet {
|
||||||
|
addAll(getKotlinOnlySubPackagesFqNames(packageFqName, nameFilter))
|
||||||
|
addAll(getPlatformSpecificSubPackagesFqNames(packageFqName, platform, nameFilter))
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
override fun getPlatformSpecificSubPackagesFqNames(
|
||||||
|
packageFqName: FqName,
|
||||||
|
platform: TargetPlatform,
|
||||||
|
nameFilter: (Name) -> Boolean
|
||||||
|
): Set<Name> = when {
|
||||||
|
platform.isJvm() -> {
|
||||||
|
val fqNameString = packageFqName.asString()
|
||||||
|
buildSet {
|
||||||
|
forEachNonKotlinPsiElementFinder { finder ->
|
||||||
|
val psiPackage = finder.findPackage(fqNameString) ?: return@forEachNonKotlinPsiElementFinder
|
||||||
|
for (subPackage in finder.getSubPackages(psiPackage, searchScope)) {
|
||||||
|
val name = subPackage.name?.let(Name::identifierIfValid) ?: continue
|
||||||
|
if (!nameFilter(name)) continue
|
||||||
|
add(name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> {
|
||||||
|
// non-JVM platforms are not supported yet
|
||||||
|
emptySet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private inline fun forEachNonKotlinPsiElementFinder(action: (PsiElementFinder) -> Unit) {
|
||||||
|
for (finder in PsiElementFinder.EP.getPoint(project).extensionList) {
|
||||||
|
if (finder::class.java.name == KOTLIN_JAVA_ELEMENT_FINDER_CLASS_NAME) {
|
||||||
|
// ignore kotlin package finder
|
||||||
|
// kotlin packages will be handled by KotlinPackageProvider.doesKotlinOnlyPackageExist/getKotlinOnlySubPackagesFqNames
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
action(finder)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
private const val KOTLIN_JAVA_ELEMENT_FINDER_CLASS_NAME = "org.jetbrains.kotlin.asJava.finder.JavaElementFinder"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
+13
-8
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.analysis.providers.impl
|
package org.jetbrains.kotlin.analysis.providers.impl
|
||||||
|
|
||||||
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider
|
import org.jetbrains.kotlin.analysis.providers.KotlinPackageProvider
|
||||||
import org.jetbrains.kotlin.analysis.providers.KotlinPackageProviderFactory
|
import org.jetbrains.kotlin.analysis.providers.KotlinPackageProviderFactory
|
||||||
@@ -13,10 +14,11 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
|
||||||
public class KotlinStaticPackageProvider(
|
public class KotlinStaticPackageProvider(
|
||||||
|
project: Project,
|
||||||
scope: GlobalSearchScope,
|
scope: GlobalSearchScope,
|
||||||
files: Collection<KtFile>
|
files: Collection<KtFile>
|
||||||
) : KotlinPackageProvider() {
|
) : KotlinPackageProviderBase(project, scope) {
|
||||||
private val packageToSubPackageNames: Map<FqName, Set<Name>> = run {
|
private val kotlinPackageToSubPackages: Map<FqName, Set<Name>> = run {
|
||||||
val filesInScope = files.filter { scope.contains(it.virtualFile) }
|
val filesInScope = files.filter { scope.contains(it.virtualFile) }
|
||||||
val packages = mutableMapOf<FqName, MutableSet<Name>>()
|
val packages = mutableMapOf<FqName, MutableSet<Name>>()
|
||||||
filesInScope.forEach { file ->
|
filesInScope.forEach { file ->
|
||||||
@@ -30,17 +32,20 @@ public class KotlinStaticPackageProvider(
|
|||||||
packages
|
packages
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun doKotlinPackageExists(packageFqName: FqName): Boolean {
|
override fun doesKotlinOnlyPackageExist(packageFqName: FqName): Boolean {
|
||||||
return packageFqName in packageToSubPackageNames
|
return packageFqName in kotlinPackageToSubPackages
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getKotlinSubPackageFqNames(packageFqName: FqName): Set<Name> {
|
override fun getKotlinOnlySubPackagesFqNames(packageFqName: FqName, nameFilter: (Name) -> Boolean): Set<Name> {
|
||||||
return packageToSubPackageNames[packageFqName] ?: emptySet()
|
return kotlinPackageToSubPackages[packageFqName]?.filterTo(mutableSetOf()) { nameFilter(it) } ?: emptySet()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class KotlinStaticPackageProviderFactory(private val files: Collection<KtFile>) : KotlinPackageProviderFactory() {
|
public class KotlinStaticPackageProviderFactory(
|
||||||
|
private val project: Project,
|
||||||
|
private val files: Collection<KtFile>
|
||||||
|
) : KotlinPackageProviderFactory() {
|
||||||
override fun createPackageProvider(searchScope: GlobalSearchScope): KotlinPackageProvider {
|
override fun createPackageProvider(searchScope: GlobalSearchScope): KotlinPackageProvider {
|
||||||
return KotlinStaticPackageProvider(searchScope, files)
|
return KotlinStaticPackageProvider(project, searchScope, files)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+1
-1
@@ -130,7 +130,7 @@ public class StandaloneAnalysisAPISessionBuilder(
|
|||||||
kotlinCoreProjectEnvironment.environment.jarFileSystem as CoreJarFileSystem
|
kotlinCoreProjectEnvironment.environment.jarFileSystem as CoreJarFileSystem
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
registerService(KotlinPackageProviderFactory::class.java, KotlinStaticPackageProviderFactory(ktFiles))
|
registerService(KotlinPackageProviderFactory::class.java, KotlinStaticPackageProviderFactory(project, ktFiles))
|
||||||
|
|
||||||
registerService(KtAnalysisSessionProvider::class.java, KtFirAnalysisSessionProvider(this))
|
registerService(KtAnalysisSessionProvider::class.java, KtFirAnalysisSessionProvider(this))
|
||||||
registerService(
|
registerService(
|
||||||
|
|||||||
+1
-1
@@ -161,7 +161,7 @@ internal fun configureProjectEnvironment(
|
|||||||
)
|
)
|
||||||
project.picoContainer.registerComponentInstance(
|
project.picoContainer.registerComponentInstance(
|
||||||
KotlinPackageProviderFactory::class.qualifiedName,
|
KotlinPackageProviderFactory::class.qualifiedName,
|
||||||
KotlinStaticPackageProviderFactory(ktFiles)
|
KotlinStaticPackageProviderFactory(project, ktFiles)
|
||||||
)
|
)
|
||||||
project.picoContainer.registerComponentInstance(
|
project.picoContainer.registerComponentInstance(
|
||||||
PackagePartProviderFactory::class.qualifiedName,
|
PackagePartProviderFactory::class.qualifiedName,
|
||||||
|
|||||||
+1
-1
@@ -92,7 +92,7 @@ internal class LLFirProviderHelper(
|
|||||||
|
|
||||||
fun getPackage(fqName: FqName): FqName? {
|
fun getPackage(fqName: FqName): FqName? {
|
||||||
if (!allowKotlinPackage && fqName.isKotlinPackage()) return null
|
if (!allowKotlinPackage && fqName.isKotlinPackage()) return null
|
||||||
return fqName.takeIf(packageProvider::doKotlinPackageExists)
|
return fqName.takeIf(packageProvider::doesKotlinOnlyPackageExist)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -79,11 +79,11 @@ class SymbolKotlinAsJavaSupport(project: Project) : KotlinAsJavaSupportBase<KtMo
|
|||||||
.toSet()
|
.toSet()
|
||||||
|
|
||||||
override fun packageExists(fqName: FqName, scope: GlobalSearchScope): Boolean =
|
override fun packageExists(fqName: FqName, scope: GlobalSearchScope): Boolean =
|
||||||
project.createPackageProvider(scope).doKotlinPackageExists(fqName)
|
project.createPackageProvider(scope).doesKotlinOnlyPackageExist(fqName)
|
||||||
|
|
||||||
override fun getSubPackages(fqn: FqName, scope: GlobalSearchScope): Collection<FqName> =
|
override fun getSubPackages(fqn: FqName, scope: GlobalSearchScope): Collection<FqName> =
|
||||||
project.createPackageProvider(scope)
|
project.createPackageProvider(scope)
|
||||||
.getKotlinSubPackageFqNames(fqn)
|
.getKotlinOnlySubPackagesFqNames(fqn, nameFilter = { true })
|
||||||
.map { fqn.child(it) }
|
.map { fqn.child(it) }
|
||||||
|
|
||||||
override fun createInstanceOfLightScript(script: KtScript): KtLightClass? = error("Should not be called")
|
override fun createInstanceOfLightScript(script: KtScript): KtLightClass? = error("Should not be called")
|
||||||
|
|||||||
@@ -74,6 +74,11 @@ public final class Name implements Comparable<Name> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static @Nullable Name identifierIfValid(@NotNull String name) {
|
||||||
|
if (!isValidIdentifier(name)) return null;
|
||||||
|
return identifier(name);
|
||||||
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static Name special(@NotNull String name) {
|
public static Name special(@NotNull String name) {
|
||||||
if (!name.startsWith("<")) {
|
if (!name.startsWith("<")) {
|
||||||
|
|||||||
Reference in New Issue
Block a user