Reformat the rest of 'frontend'-module according to new codestyle
This commit is contained in:
@@ -48,8 +48,8 @@ import java.util.*
|
|||||||
import kotlin.coroutines.experimental.buildSequence
|
import kotlin.coroutines.experimental.buildSequence
|
||||||
|
|
||||||
class ResolverForModule(
|
class ResolverForModule(
|
||||||
val packageFragmentProvider: PackageFragmentProvider,
|
val packageFragmentProvider: PackageFragmentProvider,
|
||||||
val componentProvider: ComponentProvider
|
val componentProvider: ComponentProvider
|
||||||
)
|
)
|
||||||
|
|
||||||
abstract class ResolverForProject<M : ModuleInfo> {
|
abstract class ResolverForProject<M : ModuleInfo> {
|
||||||
@@ -70,34 +70,36 @@ class EmptyResolverForProject<M : ModuleInfo> : ResolverForProject<M>() {
|
|||||||
get() = "Empty resolver"
|
get() = "Empty resolver"
|
||||||
|
|
||||||
override fun tryGetResolverForModule(moduleInfo: M): ResolverForModule? = null
|
override fun tryGetResolverForModule(moduleInfo: M): ResolverForModule? = null
|
||||||
override fun resolverForModuleDescriptor(descriptor: ModuleDescriptor): ResolverForModule = throw IllegalStateException("$descriptor is not contained in this resolver")
|
override fun resolverForModuleDescriptor(descriptor: ModuleDescriptor): ResolverForModule =
|
||||||
|
throw IllegalStateException("$descriptor is not contained in this resolver")
|
||||||
|
|
||||||
override fun descriptorForModule(moduleInfo: M) = diagnoseUnknownModuleInfo(listOf(moduleInfo))
|
override fun descriptorForModule(moduleInfo: M) = diagnoseUnknownModuleInfo(listOf(moduleInfo))
|
||||||
override val allModules: Collection<M> = listOf()
|
override val allModules: Collection<M> = listOf()
|
||||||
override fun diagnoseUnknownModuleInfo(infos: List<ModuleInfo>) = throw IllegalStateException("Should not be called for $infos")
|
override fun diagnoseUnknownModuleInfo(infos: List<ModuleInfo>) = throw IllegalStateException("Should not be called for $infos")
|
||||||
}
|
}
|
||||||
|
|
||||||
class ResolverForProjectImpl<M : ModuleInfo>(
|
class ResolverForProjectImpl<M : ModuleInfo>(
|
||||||
private val debugName: String,
|
private val debugName: String,
|
||||||
private val projectContext: ProjectContext,
|
private val projectContext: ProjectContext,
|
||||||
modules: Collection<M>,
|
modules: Collection<M>,
|
||||||
private val analyzerFacade: (M) -> AnalyzerFacade,
|
private val analyzerFacade: (M) -> AnalyzerFacade,
|
||||||
private val modulesContent: (M) -> ModuleContent,
|
private val modulesContent: (M) -> ModuleContent,
|
||||||
private val platformParameters: PlatformAnalysisParameters,
|
private val platformParameters: PlatformAnalysisParameters,
|
||||||
private val targetEnvironment: TargetEnvironment = CompilerEnvironment,
|
private val targetEnvironment: TargetEnvironment = CompilerEnvironment,
|
||||||
private val builtIns: KotlinBuiltIns = DefaultBuiltIns.Instance,
|
private val builtIns: KotlinBuiltIns = DefaultBuiltIns.Instance,
|
||||||
private val delegateResolver: ResolverForProject<M> = EmptyResolverForProject(),
|
private val delegateResolver: ResolverForProject<M> = EmptyResolverForProject(),
|
||||||
private val packagePartProviderFactory: (M, ModuleContent) -> PackagePartProvider = { _, _ -> PackagePartProvider.Empty },
|
private val packagePartProviderFactory: (M, ModuleContent) -> PackagePartProvider = { _, _ -> PackagePartProvider.Empty },
|
||||||
private val firstDependency: M? = null,
|
private val firstDependency: M? = null,
|
||||||
private val modulePlatforms: (M) -> MultiTargetPlatform?,
|
private val modulePlatforms: (M) -> MultiTargetPlatform?,
|
||||||
private val packageOracleFactory: PackageOracleFactory = PackageOracleFactory.OptimisticFactory,
|
private val packageOracleFactory: PackageOracleFactory = PackageOracleFactory.OptimisticFactory,
|
||||||
private val languageSettingsProvider: LanguageSettingsProvider = LanguageSettingsProvider.Default,
|
private val languageSettingsProvider: LanguageSettingsProvider = LanguageSettingsProvider.Default,
|
||||||
private val invalidateOnOOCB: Boolean = true
|
private val invalidateOnOOCB: Boolean = true
|
||||||
) : ResolverForProject<M>() {
|
) : ResolverForProject<M>() {
|
||||||
|
|
||||||
private class ModuleData(
|
private class ModuleData(
|
||||||
val moduleDescriptor: ModuleDescriptorImpl,
|
val moduleDescriptor: ModuleDescriptorImpl,
|
||||||
val modificationTracker: ModificationTracker?,
|
val modificationTracker: ModificationTracker?,
|
||||||
val modificationCount: Long?
|
val modificationCount: Long?
|
||||||
) {
|
) {
|
||||||
fun isOutOfDate(): Boolean {
|
fun isOutOfDate(): Boolean {
|
||||||
val currentModCount = modificationTracker?.modificationCount
|
val currentModCount = modificationTracker?.modificationCount
|
||||||
@@ -117,16 +119,22 @@ class ResolverForProjectImpl<M : ModuleInfo>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setupModuleDescriptor(module: M, moduleDescriptor: ModuleDescriptorImpl) {
|
private fun setupModuleDescriptor(module: M, moduleDescriptor: ModuleDescriptorImpl) {
|
||||||
moduleDescriptor.setDependencies(LazyModuleDependencies(
|
moduleDescriptor.setDependencies(
|
||||||
|
LazyModuleDependencies(
|
||||||
projectContext.storageManager,
|
projectContext.storageManager,
|
||||||
module,
|
module,
|
||||||
firstDependency,
|
firstDependency,
|
||||||
this))
|
this
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
val content = modulesContent(module)
|
val content = modulesContent(module)
|
||||||
moduleDescriptor.initialize(
|
moduleDescriptor.initialize(
|
||||||
DelegatingPackageFragmentProvider(this, moduleDescriptor, content,
|
DelegatingPackageFragmentProvider(
|
||||||
packageOracleFactory.createOracle(module)))
|
this, moduleDescriptor, content,
|
||||||
|
packageOracleFactory.createOracle(module)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val resolverByModuleDescriptor = mutableMapOf<ModuleDescriptor, ResolverForModule>()
|
private val resolverByModuleDescriptor = mutableMapOf<ModuleDescriptor, ResolverForModule>()
|
||||||
@@ -153,16 +161,17 @@ class ResolverForProjectImpl<M : ModuleInfo>(
|
|||||||
ResolverForModuleComputationTracker.getInstance(projectContext.project)?.onResolverComputed(module)
|
ResolverForModuleComputationTracker.getInstance(projectContext.project)?.onResolverComputed(module)
|
||||||
|
|
||||||
analyzerFacade(module).createResolverForModule(
|
analyzerFacade(module).createResolverForModule(
|
||||||
module, descriptor as ModuleDescriptorImpl, projectContext.withModule(descriptor), modulesContent(module),
|
module, descriptor as ModuleDescriptorImpl, projectContext.withModule(descriptor), modulesContent(module),
|
||||||
platformParameters, targetEnvironment, this@ResolverForProjectImpl,
|
platformParameters, targetEnvironment, this@ResolverForProjectImpl,
|
||||||
languageSettingsProvider,
|
languageSettingsProvider,
|
||||||
packagePartProviderFactory(module, modulesContent(module)))
|
packagePartProviderFactory(module, modulesContent(module))
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun isResolverForModuleDescriptorComputed(descriptor: ModuleDescriptor) =
|
internal fun isResolverForModuleDescriptorComputed(descriptor: ModuleDescriptor) =
|
||||||
descriptor in resolverByModuleDescriptor
|
descriptor in resolverByModuleDescriptor
|
||||||
|
|
||||||
override fun descriptorForModule(moduleInfo: M): ModuleDescriptorImpl {
|
override fun descriptorForModule(moduleInfo: M): ModuleDescriptorImpl {
|
||||||
if (!isCorrectModuleInfo(moduleInfo)) {
|
if (!isCorrectModuleInfo(moduleInfo)) {
|
||||||
@@ -172,7 +181,7 @@ class ResolverForProjectImpl<M : ModuleInfo>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun diagnoseUnknownModuleInfo(infos: List<ModuleInfo>) =
|
override fun diagnoseUnknownModuleInfo(infos: List<ModuleInfo>) =
|
||||||
throw AssertionError("$name does not know how to resolve $infos")
|
throw AssertionError("$name does not know how to resolve $infos")
|
||||||
|
|
||||||
private fun doGetDescriptorForModule(module: M): ModuleDescriptorImpl {
|
private fun doGetDescriptorForModule(module: M): ModuleDescriptorImpl {
|
||||||
if (module in modules) {
|
if (module in modules) {
|
||||||
@@ -204,19 +213,21 @@ class ResolverForProjectImpl<M : ModuleInfo>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createModuleDescriptor(module: M): ModuleData {
|
private fun createModuleDescriptor(module: M): ModuleData {
|
||||||
val moduleDescriptor = ModuleDescriptorImpl(module.name,
|
val moduleDescriptor = ModuleDescriptorImpl(
|
||||||
projectContext.storageManager, builtIns, modulePlatforms(module), module.capabilities)
|
module.name,
|
||||||
|
projectContext.storageManager, builtIns, modulePlatforms(module), module.capabilities
|
||||||
|
)
|
||||||
moduleInfoByDescriptor[moduleDescriptor] = module
|
moduleInfoByDescriptor[moduleDescriptor] = module
|
||||||
setupModuleDescriptor(module, moduleDescriptor)
|
setupModuleDescriptor(module, moduleDescriptor)
|
||||||
val modificationTracker = (module as? TrackableModuleInfo)?.createModificationTracker() ?:
|
val modificationTracker = (module as? TrackableModuleInfo)?.createModificationTracker()
|
||||||
(PsiModificationTracker.SERVICE.getInstance(projectContext.project).outOfCodeBlockModificationTracker.takeIf { invalidateOnOOCB })
|
?: (PsiModificationTracker.SERVICE.getInstance(projectContext.project).outOfCodeBlockModificationTracker.takeIf { invalidateOnOOCB })
|
||||||
return ModuleData(moduleDescriptor, modificationTracker, modificationTracker?.modificationCount)
|
return ModuleData(moduleDescriptor, modificationTracker, modificationTracker?.modificationCount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ModuleContent(
|
data class ModuleContent(
|
||||||
val syntheticFiles: Collection<KtFile>,
|
val syntheticFiles: Collection<KtFile>,
|
||||||
val moduleContentScope: GlobalSearchScope
|
val moduleContentScope: GlobalSearchScope
|
||||||
)
|
)
|
||||||
|
|
||||||
interface PlatformAnalysisParameters
|
interface PlatformAnalysisParameters
|
||||||
@@ -238,10 +249,10 @@ interface ModuleInfo {
|
|||||||
// but if they are present, they should come after JVM built-ins in the dependencies list, because JVM built-ins contain
|
// but if they are present, they should come after JVM built-ins in the dependencies list, because JVM built-ins contain
|
||||||
// additional members dependent on the JDK
|
// additional members dependent on the JDK
|
||||||
fun dependencyOnBuiltIns(): ModuleInfo.DependencyOnBuiltIns =
|
fun dependencyOnBuiltIns(): ModuleInfo.DependencyOnBuiltIns =
|
||||||
if (platform == TargetPlatform.Common)
|
if (platform == TargetPlatform.Common)
|
||||||
ModuleInfo.DependencyOnBuiltIns.AFTER_SDK
|
ModuleInfo.DependencyOnBuiltIns.AFTER_SDK
|
||||||
else
|
else
|
||||||
ModuleInfo.DependencyOnBuiltIns.LAST
|
ModuleInfo.DependencyOnBuiltIns.LAST
|
||||||
|
|
||||||
//TODO: (module refactoring) provide dependency on builtins after runtime in IDEA
|
//TODO: (module refactoring) provide dependency on builtins after runtime in IDEA
|
||||||
enum class DependencyOnBuiltIns { NONE, AFTER_SDK, LAST }
|
enum class DependencyOnBuiltIns { NONE, AFTER_SDK, LAST }
|
||||||
@@ -257,25 +268,25 @@ interface TrackableModuleInfo : ModuleInfo {
|
|||||||
|
|
||||||
abstract class AnalyzerFacade {
|
abstract class AnalyzerFacade {
|
||||||
abstract fun <M : ModuleInfo> createResolverForModule(
|
abstract fun <M : ModuleInfo> createResolverForModule(
|
||||||
moduleInfo: M,
|
moduleInfo: M,
|
||||||
moduleDescriptor: ModuleDescriptorImpl,
|
moduleDescriptor: ModuleDescriptorImpl,
|
||||||
moduleContext: ModuleContext,
|
moduleContext: ModuleContext,
|
||||||
moduleContent: ModuleContent,
|
moduleContent: ModuleContent,
|
||||||
platformParameters: PlatformAnalysisParameters,
|
platformParameters: PlatformAnalysisParameters,
|
||||||
targetEnvironment: TargetEnvironment,
|
targetEnvironment: TargetEnvironment,
|
||||||
resolverForProject: ResolverForProject<M>,
|
resolverForProject: ResolverForProject<M>,
|
||||||
languageSettingsProvider: LanguageSettingsProvider,
|
languageSettingsProvider: LanguageSettingsProvider,
|
||||||
packagePartProvider: PackagePartProvider
|
packagePartProvider: PackagePartProvider
|
||||||
): ResolverForModule
|
): ResolverForModule
|
||||||
|
|
||||||
abstract val targetPlatform: TargetPlatform
|
abstract val targetPlatform: TargetPlatform
|
||||||
}
|
}
|
||||||
|
|
||||||
class LazyModuleDependencies<M: ModuleInfo>(
|
class LazyModuleDependencies<M : ModuleInfo>(
|
||||||
storageManager: StorageManager,
|
storageManager: StorageManager,
|
||||||
private val module: M,
|
private val module: M,
|
||||||
firstDependency: M? = null,
|
firstDependency: M? = null,
|
||||||
private val resolverForProject: ResolverForProjectImpl<M>
|
private val resolverForProject: ResolverForProjectImpl<M>
|
||||||
) : ModuleDependencies {
|
) : ModuleDependencies {
|
||||||
private val dependencies = storageManager.createLazyValue {
|
private val dependencies = storageManager.createLazyValue {
|
||||||
val moduleDescriptor = resolverForProject.descriptorForModule(module)
|
val moduleDescriptor = resolverForProject.descriptorForModule(module)
|
||||||
@@ -307,10 +318,10 @@ class LazyModuleDependencies<M: ModuleInfo>(
|
|||||||
|
|
||||||
|
|
||||||
private class DelegatingPackageFragmentProvider<M : ModuleInfo>(
|
private class DelegatingPackageFragmentProvider<M : ModuleInfo>(
|
||||||
private val resolverForProject: ResolverForProjectImpl<M>,
|
private val resolverForProject: ResolverForProjectImpl<M>,
|
||||||
private val module: ModuleDescriptor,
|
private val module: ModuleDescriptor,
|
||||||
moduleContent: ModuleContent,
|
moduleContent: ModuleContent,
|
||||||
private val packageOracle: PackageOracle
|
private val packageOracle: PackageOracle
|
||||||
) : PackageFragmentProvider {
|
) : PackageFragmentProvider {
|
||||||
private val syntheticFilePackages = moduleContent.syntheticFiles.map { it.packageFqName }.toSet()
|
private val syntheticFilePackages = moduleContent.syntheticFiles.map { it.packageFqName }.toSet()
|
||||||
|
|
||||||
@@ -366,6 +377,7 @@ interface ResolverForModuleComputationTracker {
|
|||||||
fun onResolverComputed(moduleInfo: ModuleInfo)
|
fun onResolverComputed(moduleInfo: ModuleInfo)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getInstance(project: Project): ResolverForModuleComputationTracker? = ServiceManager.getService(project, ResolverForModuleComputationTracker::class.java) ?: null
|
fun getInstance(project: Project): ResolverForModuleComputationTracker? =
|
||||||
|
ServiceManager.getService(project, ResolverForModuleComputationTracker::class.java) ?: null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+44
-44
@@ -51,42 +51,42 @@ import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragmen
|
|||||||
*/
|
*/
|
||||||
object CommonAnalyzerFacade : AnalyzerFacade() {
|
object CommonAnalyzerFacade : AnalyzerFacade() {
|
||||||
private class SourceModuleInfo(
|
private class SourceModuleInfo(
|
||||||
override val name: Name,
|
override val name: Name,
|
||||||
override val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>,
|
override val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>,
|
||||||
private val dependOnOldBuiltIns: Boolean
|
private val dependOnOldBuiltIns: Boolean
|
||||||
) : ModuleInfo {
|
) : ModuleInfo {
|
||||||
override fun dependencies() = listOf(this)
|
override fun dependencies() = listOf(this)
|
||||||
|
|
||||||
override fun dependencyOnBuiltIns(): ModuleInfo.DependencyOnBuiltIns =
|
override fun dependencyOnBuiltIns(): ModuleInfo.DependencyOnBuiltIns =
|
||||||
if (dependOnOldBuiltIns) ModuleInfo.DependencyOnBuiltIns.LAST else ModuleInfo.DependencyOnBuiltIns.NONE
|
if (dependOnOldBuiltIns) ModuleInfo.DependencyOnBuiltIns.LAST else ModuleInfo.DependencyOnBuiltIns.NONE
|
||||||
}
|
}
|
||||||
|
|
||||||
fun analyzeFiles(
|
fun analyzeFiles(
|
||||||
files: Collection<KtFile>, moduleName: Name, dependOnBuiltIns: Boolean, languageVersionSettings: LanguageVersionSettings,
|
files: Collection<KtFile>, moduleName: Name, dependOnBuiltIns: Boolean, languageVersionSettings: LanguageVersionSettings,
|
||||||
capabilities: Map<ModuleDescriptor.Capability<*>, Any?> = mapOf(MultiTargetPlatform.CAPABILITY to MultiTargetPlatform.Common),
|
capabilities: Map<ModuleDescriptor.Capability<*>, Any?> = mapOf(MultiTargetPlatform.CAPABILITY to MultiTargetPlatform.Common),
|
||||||
packagePartProviderFactory: (ModuleInfo, ModuleContent) -> PackagePartProvider
|
packagePartProviderFactory: (ModuleInfo, ModuleContent) -> PackagePartProvider
|
||||||
): AnalysisResult {
|
): AnalysisResult {
|
||||||
val moduleInfo = SourceModuleInfo(moduleName, capabilities, dependOnBuiltIns)
|
val moduleInfo = SourceModuleInfo(moduleName, capabilities, dependOnBuiltIns)
|
||||||
val project = files.firstOrNull()?.project ?: throw AssertionError("No files to analyze")
|
val project = files.firstOrNull()?.project ?: throw AssertionError("No files to analyze")
|
||||||
|
|
||||||
val multiplatformLanguageSettings = object : LanguageVersionSettings by languageVersionSettings {
|
val multiplatformLanguageSettings = object : LanguageVersionSettings by languageVersionSettings {
|
||||||
override fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State =
|
override fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State =
|
||||||
if (feature == LanguageFeature.MultiPlatformProjects) LanguageFeature.State.ENABLED
|
if (feature == LanguageFeature.MultiPlatformProjects) LanguageFeature.State.ENABLED
|
||||||
else languageVersionSettings.getFeatureSupport(feature)
|
else languageVersionSettings.getFeatureSupport(feature)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Suppress("NAME_SHADOWING")
|
@Suppress("NAME_SHADOWING")
|
||||||
val resolver = ResolverForProjectImpl (
|
val resolver = ResolverForProjectImpl(
|
||||||
"sources for metadata serializer",
|
"sources for metadata serializer",
|
||||||
ProjectContext(project), listOf(moduleInfo), { CommonAnalyzerFacade },
|
ProjectContext(project), listOf(moduleInfo), { CommonAnalyzerFacade },
|
||||||
{ ModuleContent(files, GlobalSearchScope.allScope(project)) },
|
{ ModuleContent(files, GlobalSearchScope.allScope(project)) },
|
||||||
object : PlatformAnalysisParameters {},
|
object : PlatformAnalysisParameters {},
|
||||||
languageSettingsProvider = object : LanguageSettingsProvider {
|
languageSettingsProvider = object : LanguageSettingsProvider {
|
||||||
override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project) = multiplatformLanguageSettings
|
override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project) = multiplatformLanguageSettings
|
||||||
override fun getTargetPlatform(moduleInfo: ModuleInfo) = TargetPlatformVersion.NoVersion
|
override fun getTargetPlatform(moduleInfo: ModuleInfo) = TargetPlatformVersion.NoVersion
|
||||||
},
|
},
|
||||||
packagePartProviderFactory = packagePartProviderFactory,
|
packagePartProviderFactory = packagePartProviderFactory,
|
||||||
modulePlatforms = { MultiTargetPlatform.Common }
|
modulePlatforms = { MultiTargetPlatform.Common }
|
||||||
)
|
)
|
||||||
|
|
||||||
val moduleDescriptor = resolver.descriptorForModule(moduleInfo)
|
val moduleDescriptor = resolver.descriptorForModule(moduleInfo)
|
||||||
@@ -98,46 +98,46 @@ object CommonAnalyzerFacade : AnalyzerFacade() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun <M : ModuleInfo> createResolverForModule(
|
override fun <M : ModuleInfo> createResolverForModule(
|
||||||
moduleInfo: M,
|
moduleInfo: M,
|
||||||
moduleDescriptor: ModuleDescriptorImpl,
|
moduleDescriptor: ModuleDescriptorImpl,
|
||||||
moduleContext: ModuleContext,
|
moduleContext: ModuleContext,
|
||||||
moduleContent: ModuleContent,
|
moduleContent: ModuleContent,
|
||||||
platformParameters: PlatformAnalysisParameters,
|
platformParameters: PlatformAnalysisParameters,
|
||||||
targetEnvironment: TargetEnvironment,
|
targetEnvironment: TargetEnvironment,
|
||||||
resolverForProject: ResolverForProject<M>,
|
resolverForProject: ResolverForProject<M>,
|
||||||
languageSettingsProvider: LanguageSettingsProvider,
|
languageSettingsProvider: LanguageSettingsProvider,
|
||||||
packagePartProvider: PackagePartProvider
|
packagePartProvider: PackagePartProvider
|
||||||
): ResolverForModule {
|
): ResolverForModule {
|
||||||
val (syntheticFiles, moduleContentScope) = moduleContent
|
val (syntheticFiles, moduleContentScope) = moduleContent
|
||||||
val project = moduleContext.project
|
val project = moduleContext.project
|
||||||
val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory(
|
val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory(
|
||||||
project, moduleContext.storageManager, syntheticFiles,
|
project, moduleContext.storageManager, syntheticFiles,
|
||||||
if (moduleInfo.isLibrary) GlobalSearchScope.EMPTY_SCOPE else moduleContentScope,
|
if (moduleInfo.isLibrary) GlobalSearchScope.EMPTY_SCOPE else moduleContentScope,
|
||||||
moduleInfo
|
moduleInfo
|
||||||
)
|
)
|
||||||
|
|
||||||
val trace = CodeAnalyzerInitializer.getInstance(project).createTrace()
|
val trace = CodeAnalyzerInitializer.getInstance(project).createTrace()
|
||||||
val container = createContainerToResolveCommonCode(
|
val container = createContainerToResolveCommonCode(
|
||||||
moduleContext, trace, declarationProviderFactory, moduleContentScope, targetEnvironment, packagePartProvider,
|
moduleContext, trace, declarationProviderFactory, moduleContentScope, targetEnvironment, packagePartProvider,
|
||||||
languageSettingsProvider.getLanguageVersionSettings(moduleInfo, project)
|
languageSettingsProvider.getLanguageVersionSettings(moduleInfo, project)
|
||||||
)
|
)
|
||||||
|
|
||||||
val packageFragmentProviders = listOf(
|
val packageFragmentProviders = listOf(
|
||||||
container.get<ResolveSession>().packageFragmentProvider,
|
container.get<ResolveSession>().packageFragmentProvider,
|
||||||
container.get<MetadataPackageFragmentProvider>()
|
container.get<MetadataPackageFragmentProvider>()
|
||||||
)
|
)
|
||||||
|
|
||||||
return ResolverForModule(CompositePackageFragmentProvider(packageFragmentProviders), container)
|
return ResolverForModule(CompositePackageFragmentProvider(packageFragmentProviders), container)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createContainerToResolveCommonCode(
|
private fun createContainerToResolveCommonCode(
|
||||||
moduleContext: ModuleContext,
|
moduleContext: ModuleContext,
|
||||||
bindingTrace: BindingTrace,
|
bindingTrace: BindingTrace,
|
||||||
declarationProviderFactory: DeclarationProviderFactory,
|
declarationProviderFactory: DeclarationProviderFactory,
|
||||||
moduleContentScope: GlobalSearchScope,
|
moduleContentScope: GlobalSearchScope,
|
||||||
targetEnvironment: TargetEnvironment,
|
targetEnvironment: TargetEnvironment,
|
||||||
packagePartProvider: PackagePartProvider,
|
packagePartProvider: PackagePartProvider,
|
||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
): StorageComponentContainer = createContainer("ResolveCommonCode", targetPlatform) {
|
): StorageComponentContainer = createContainer("ResolveCommonCode", targetPlatform) {
|
||||||
configureModule(moduleContext, targetPlatform, TargetPlatformVersion.NoVersion, bindingTrace)
|
configureModule(moduleContext, targetPlatform, TargetPlatformVersion.NoVersion, bindingTrace)
|
||||||
|
|
||||||
@@ -154,7 +154,7 @@ object CommonAnalyzerFacade : AnalyzerFacade() {
|
|||||||
useImpl<MetadataPackageFragmentProvider>()
|
useImpl<MetadataPackageFragmentProvider>()
|
||||||
|
|
||||||
val metadataFinderFactory = ServiceManager.getService(moduleContext.project, MetadataFinderFactory::class.java)
|
val metadataFinderFactory = ServiceManager.getService(moduleContext.project, MetadataFinderFactory::class.java)
|
||||||
?: error("No MetadataFinderFactory in project")
|
?: error("No MetadataFinderFactory in project")
|
||||||
useInstance(metadataFinderFactory.create(moduleContentScope))
|
useInstance(metadataFinderFactory.create(moduleContentScope))
|
||||||
|
|
||||||
targetEnvironment.configure(this)
|
targetEnvironment.configure(this)
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
|||||||
interface ControlFlowBuilder {
|
interface ControlFlowBuilder {
|
||||||
// Subroutines
|
// Subroutines
|
||||||
fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind? = null)
|
fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind? = null)
|
||||||
|
|
||||||
fun exitSubroutine(subroutine: KtElement, invocationKind: InvocationKind? = null): Pseudocode
|
fun exitSubroutine(subroutine: KtElement, invocationKind: InvocationKind? = null): Pseudocode
|
||||||
|
|
||||||
val currentSubroutine: KtElement
|
val currentSubroutine: KtElement
|
||||||
|
|||||||
@@ -624,7 +624,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
if (!VariableUseState.isUsed(variableUseState)) {
|
if (!VariableUseState.isUsed(variableUseState)) {
|
||||||
if (element.isSingleUnderscore) return
|
if (element.isSingleUnderscore) return
|
||||||
when {
|
when {
|
||||||
// KtDestructuringDeclarationEntry -> KtDestructuringDeclaration -> KtParameter -> KtParameterList
|
// KtDestructuringDeclarationEntry -> KtDestructuringDeclaration -> KtParameter -> KtParameterList
|
||||||
element is KtDestructuringDeclarationEntry && element.parent.parent?.parent is KtParameterList ->
|
element is KtDestructuringDeclarationEntry && element.parent.parent?.parent is KtParameterList ->
|
||||||
report(Errors.UNUSED_DESTRUCTURED_PARAMETER_ENTRY.on(element, variableDescriptor), ctxt)
|
report(Errors.UNUSED_DESTRUCTURED_PARAMETER_ENTRY.on(element, variableDescriptor), ctxt)
|
||||||
|
|
||||||
@@ -866,7 +866,7 @@ class ControlFlowInformationProvider private constructor(
|
|||||||
class KindAndCall(var kind: TailRecursionKind, internal val call: ResolvedCall<*>)
|
class KindAndCall(var kind: TailRecursionKind, internal val call: ResolvedCall<*>)
|
||||||
|
|
||||||
val calls = HashMap<KtElement, KindAndCall>()
|
val calls = HashMap<KtElement, KindAndCall>()
|
||||||
traverseCalls traverse@{ instruction, resolvedCall ->
|
traverseCalls traverse@ { instruction, resolvedCall ->
|
||||||
// is this a recursive call?
|
// is this a recursive call?
|
||||||
val functionDescriptor = resolvedCall.resultingDescriptor
|
val functionDescriptor = resolvedCall.resultingDescriptor
|
||||||
if (functionDescriptor.original != subroutineDescriptor) return@traverse
|
if (functionDescriptor.original != subroutineDescriptor) return@traverse
|
||||||
|
|||||||
@@ -1021,23 +1021,23 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
private fun visitInlinedFunction(lambdaFunctionLiteral: KtFunction, invocationKind: InvocationKind) {
|
private fun visitInlinedFunction(lambdaFunctionLiteral: KtFunction, invocationKind: InvocationKind) {
|
||||||
// Defer emitting of inlined declaration
|
// Defer emitting of inlined declaration
|
||||||
deferredGeneratorsStack.peek().add({ builder ->
|
deferredGeneratorsStack.peek().add({ builder ->
|
||||||
val beforeDeclaration = builder.createUnboundLabel("before inlined declaration")
|
val beforeDeclaration = builder.createUnboundLabel("before inlined declaration")
|
||||||
val afterDeclaration = builder.createUnboundLabel("after inlined declaration")
|
val afterDeclaration = builder.createUnboundLabel("after inlined declaration")
|
||||||
|
|
||||||
builder.bindLabel(beforeDeclaration)
|
builder.bindLabel(beforeDeclaration)
|
||||||
|
|
||||||
if (!invocationKind.isDefinitelyVisited()) {
|
if (!invocationKind.isDefinitelyVisited()) {
|
||||||
builder.nondeterministicJump(afterDeclaration, lambdaFunctionLiteral, null)
|
builder.nondeterministicJump(afterDeclaration, lambdaFunctionLiteral, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
generate(lambdaFunctionLiteral, invocationKind)
|
generate(lambdaFunctionLiteral, invocationKind)
|
||||||
|
|
||||||
if (invocationKind.canBeRevisited()) {
|
if (invocationKind.canBeRevisited()) {
|
||||||
builder.nondeterministicJump(beforeDeclaration, lambdaFunctionLiteral, null)
|
builder.nondeterministicJump(beforeDeclaration, lambdaFunctionLiteral, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
builder.bindLabel(afterDeclaration)
|
builder.bindLabel(afterDeclaration)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitNamedFunction(function: KtNamedFunction) {
|
override fun visitNamedFunction(function: KtNamedFunction) {
|
||||||
@@ -1544,8 +1544,10 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
|||||||
//noinspection EnumSwitchStatementWhichMissesCases
|
//noinspection EnumSwitchStatementWhichMissesCases
|
||||||
when (kind) {
|
when (kind) {
|
||||||
ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver = resolvedCall.dispatchReceiver
|
ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver = resolvedCall.dispatchReceiver
|
||||||
ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> explicitReceiver = resolvedCall.extensionReceiver
|
ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> explicitReceiver =
|
||||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER -> {}
|
resolvedCall.extensionReceiver
|
||||||
|
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER -> {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -29,28 +29,28 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
|||||||
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
||||||
|
|
||||||
class PseudocodeVariableDataCollector(
|
class PseudocodeVariableDataCollector(
|
||||||
private val bindingContext: BindingContext,
|
private val bindingContext: BindingContext,
|
||||||
private val pseudocode: Pseudocode
|
private val pseudocode: Pseudocode
|
||||||
) {
|
) {
|
||||||
val blockScopeVariableInfo = computeBlockScopeVariableInfo(pseudocode)
|
val blockScopeVariableInfo = computeBlockScopeVariableInfo(pseudocode)
|
||||||
|
|
||||||
fun <I : ControlFlowInfo<*, *>> collectData(
|
fun <I : ControlFlowInfo<*, *>> collectData(
|
||||||
traversalOrder: TraversalOrder,
|
traversalOrder: TraversalOrder,
|
||||||
initialInfo: I,
|
initialInfo: I,
|
||||||
instructionDataMergeStrategy: (Instruction, Collection<I>) -> Edges<I>
|
instructionDataMergeStrategy: (Instruction, Collection<I>) -> Edges<I>
|
||||||
): Map<Instruction, Edges<I>> {
|
): Map<Instruction, Edges<I>> {
|
||||||
return pseudocode.collectData(
|
return pseudocode.collectData(
|
||||||
traversalOrder,
|
traversalOrder,
|
||||||
instructionDataMergeStrategy,
|
instructionDataMergeStrategy,
|
||||||
{ from, to, info -> filterOutVariablesOutOfScope(from, to, info) },
|
{ from, to, info -> filterOutVariablesOutOfScope(from, to, info) },
|
||||||
initialInfo
|
initialInfo
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <I : ControlFlowInfo<*, *>> filterOutVariablesOutOfScope(
|
private fun <I : ControlFlowInfo<*, *>> filterOutVariablesOutOfScope(
|
||||||
from: Instruction,
|
from: Instruction,
|
||||||
to: Instruction,
|
to: Instruction,
|
||||||
info: I
|
info: I
|
||||||
): I {
|
): I {
|
||||||
// If an edge goes from deeper scope to a less deep one, this means that it points outside of the deeper scope.
|
// If an edge goes from deeper scope to a less deep one, this means that it points outside of the deeper scope.
|
||||||
val toDepth = to.blockScope.depth
|
val toDepth = to.blockScope.depth
|
||||||
@@ -74,9 +74,11 @@ class PseudocodeVariableDataCollector(
|
|||||||
val variableDeclarationElement = instruction.variableDeclarationElement
|
val variableDeclarationElement = instruction.variableDeclarationElement
|
||||||
val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement) ?: return@traverse
|
val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement) ?: return@traverse
|
||||||
val variableDescriptor = BindingContextUtils.variableDescriptorForDeclaration(descriptor)
|
val variableDescriptor = BindingContextUtils.variableDescriptorForDeclaration(descriptor)
|
||||||
?: throw AssertionError("Variable or class descriptor should correspond to " +
|
?: throw AssertionError(
|
||||||
"the instruction for ${instruction.element.text}.\n" +
|
"Variable or class descriptor should correspond to " +
|
||||||
"Descriptor: $descriptor")
|
"the instruction for ${instruction.element.text}.\n" +
|
||||||
|
"Descriptor: $descriptor"
|
||||||
|
)
|
||||||
blockScopeVariableInfo.registerVariableDeclaredInScope(variableDescriptor, instruction.blockScope)
|
blockScopeVariableInfo.registerVariableDeclaredInScope(variableDescriptor, instruction.blockScope)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -85,8 +87,8 @@ class PseudocodeVariableDataCollector(
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface BlockScopeVariableInfo {
|
interface BlockScopeVariableInfo {
|
||||||
val declaredIn : Map<VariableDescriptor, BlockScope>
|
val declaredIn: Map<VariableDescriptor, BlockScope>
|
||||||
val scopeVariables : Map<BlockScope, Collection<VariableDescriptor>>
|
val scopeVariables: Map<BlockScope, Collection<VariableDescriptor>>
|
||||||
}
|
}
|
||||||
|
|
||||||
class BlockScopeVariableInfoImpl : BlockScopeVariableInfo {
|
class BlockScopeVariableInfoImpl : BlockScopeVariableInfo {
|
||||||
|
|||||||
@@ -42,14 +42,14 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
private val pseudocodeVariableDataCollector = PseudocodeVariableDataCollector(bindingContext, pseudocode)
|
private val pseudocodeVariableDataCollector = PseudocodeVariableDataCollector(bindingContext, pseudocode)
|
||||||
|
|
||||||
private class VariablesForDeclaration(
|
private class VariablesForDeclaration(
|
||||||
val valsWithTrivialInitializer: Set<VariableDescriptor>,
|
val valsWithTrivialInitializer: Set<VariableDescriptor>,
|
||||||
val nonTrivialVariables: Set<VariableDescriptor>
|
val nonTrivialVariables: Set<VariableDescriptor>
|
||||||
) {
|
) {
|
||||||
val allVars =
|
val allVars =
|
||||||
if (nonTrivialVariables.isEmpty())
|
if (nonTrivialVariables.isEmpty())
|
||||||
valsWithTrivialInitializer
|
valsWithTrivialInitializer
|
||||||
else
|
else
|
||||||
LinkedHashSet(valsWithTrivialInitializer).also { it.addAll(nonTrivialVariables) }
|
LinkedHashSet(valsWithTrivialInitializer).also { it.addAll(nonTrivialVariables) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private val declaredVariablesForDeclaration = hashMapOf<Pseudocode, VariablesForDeclaration>()
|
private val declaredVariablesForDeclaration = hashMapOf<Pseudocode, VariablesForDeclaration>()
|
||||||
@@ -65,10 +65,10 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
get() = pseudocodeVariableDataCollector.blockScopeVariableInfo
|
get() = pseudocodeVariableDataCollector.blockScopeVariableInfo
|
||||||
|
|
||||||
fun getDeclaredVariables(pseudocode: Pseudocode, includeInsideLocalDeclarations: Boolean): Set<VariableDescriptor> =
|
fun getDeclaredVariables(pseudocode: Pseudocode, includeInsideLocalDeclarations: Boolean): Set<VariableDescriptor> =
|
||||||
getAllDeclaredVariables(pseudocode, includeInsideLocalDeclarations).allVars
|
getAllDeclaredVariables(pseudocode, includeInsideLocalDeclarations).allVars
|
||||||
|
|
||||||
fun isVariableWithTrivialInitializer(variableDescriptor: VariableDescriptor) =
|
fun isVariableWithTrivialInitializer(variableDescriptor: VariableDescriptor) =
|
||||||
variableDescriptor in rootVariables.valsWithTrivialInitializer
|
variableDescriptor in rootVariables.valsWithTrivialInitializer
|
||||||
|
|
||||||
private fun getAllDeclaredVariables(pseudocode: Pseudocode, includeInsideLocalDeclarations: Boolean): VariablesForDeclaration {
|
private fun getAllDeclaredVariables(pseudocode: Pseudocode, includeInsideLocalDeclarations: Boolean): VariablesForDeclaration {
|
||||||
if (!includeInsideLocalDeclarations) {
|
if (!includeInsideLocalDeclarations) {
|
||||||
@@ -86,9 +86,9 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun addVariablesFromPseudocode(
|
private fun addVariablesFromPseudocode(
|
||||||
pseudocode: Pseudocode,
|
pseudocode: Pseudocode,
|
||||||
nonTrivialVariables: MutableSet<VariableDescriptor>,
|
nonTrivialVariables: MutableSet<VariableDescriptor>,
|
||||||
valsWithTrivialInitializer: MutableSet<VariableDescriptor>
|
valsWithTrivialInitializer: MutableSet<VariableDescriptor>
|
||||||
) {
|
) {
|
||||||
getUpperLevelDeclaredVariables(pseudocode).let {
|
getUpperLevelDeclaredVariables(pseudocode).let {
|
||||||
nonTrivialVariables.addAll(it.nonTrivialVariables)
|
nonTrivialVariables.addAll(it.nonTrivialVariables)
|
||||||
@@ -107,14 +107,13 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
if (instruction is VariableDeclarationInstruction) {
|
if (instruction is VariableDeclarationInstruction) {
|
||||||
val variableDeclarationElement = instruction.variableDeclarationElement
|
val variableDeclarationElement = instruction.variableDeclarationElement
|
||||||
val descriptor =
|
val descriptor =
|
||||||
variableDescriptorForDeclaration(
|
variableDescriptorForDeclaration(
|
||||||
bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement)
|
bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement)
|
||||||
) ?: continue
|
) ?: continue
|
||||||
|
|
||||||
if (!containsDoWhile && isValWithTrivialInitializer(variableDeclarationElement, descriptor)) {
|
if (!containsDoWhile && isValWithTrivialInitializer(variableDeclarationElement, descriptor)) {
|
||||||
valsWithTrivialInitializer.add(descriptor)
|
valsWithTrivialInitializer.add(descriptor)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
nonTrivialVariables.add(descriptor)
|
nonTrivialVariables.add(descriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,8 +123,8 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isValWithTrivialInitializer(variableDeclarationElement: KtDeclaration, descriptor: VariableDescriptor) =
|
private fun isValWithTrivialInitializer(variableDeclarationElement: KtDeclaration, descriptor: VariableDescriptor) =
|
||||||
variableDeclarationElement is KtParameter || variableDeclarationElement is KtObjectDeclaration ||
|
variableDeclarationElement is KtParameter || variableDeclarationElement is KtObjectDeclaration ||
|
||||||
variableDeclarationElement.safeAs<KtVariableDeclaration>()?.isVariableWithTrivialInitializer(descriptor) == true
|
variableDeclarationElement.safeAs<KtVariableDeclaration>()?.isVariableWithTrivialInitializer(descriptor) == true
|
||||||
|
|
||||||
private fun KtVariableDeclaration.isVariableWithTrivialInitializer(descriptor: VariableDescriptor): Boolean {
|
private fun KtVariableDeclaration.isVariableWithTrivialInitializer(descriptor: VariableDescriptor): Boolean {
|
||||||
if (descriptor.isPropertyWithoutBackingField()) return true
|
if (descriptor.isPropertyWithoutBackingField()) return true
|
||||||
@@ -148,18 +147,20 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
|
|
||||||
if (rootVariables.nonTrivialVariables.isEmpty()) return resultForValsWithTrivialInitializer
|
if (rootVariables.nonTrivialVariables.isEmpty()) return resultForValsWithTrivialInitializer
|
||||||
|
|
||||||
return pseudocodeVariableDataCollector.collectData(TraversalOrder.FORWARD, InitControlFlowInfo()) {
|
return pseudocodeVariableDataCollector.collectData(
|
||||||
instruction: Instruction, incomingEdgesData: Collection<InitControlFlowInfo> ->
|
TraversalOrder.FORWARD,
|
||||||
|
InitControlFlowInfo()
|
||||||
|
) { instruction: Instruction, incomingEdgesData: Collection<InitControlFlowInfo> ->
|
||||||
|
|
||||||
val enterInstructionData = mergeIncomingEdgesDataForInitializers(instruction, incomingEdgesData, blockScopeVariableInfo)
|
val enterInstructionData = mergeIncomingEdgesDataForInitializers(instruction, incomingEdgesData, blockScopeVariableInfo)
|
||||||
val exitInstructionData = addVariableInitStateFromCurrentInstructionIfAny(
|
val exitInstructionData = addVariableInitStateFromCurrentInstructionIfAny(
|
||||||
instruction, enterInstructionData, blockScopeVariableInfo)
|
instruction, enterInstructionData, blockScopeVariableInfo
|
||||||
|
)
|
||||||
Edges(enterInstructionData, exitInstructionData)
|
Edges(enterInstructionData, exitInstructionData)
|
||||||
}.mapValues {
|
}.mapValues { (instruction, edges) ->
|
||||||
(instruction, edges) ->
|
val trivialEdges = resultForValsWithTrivialInitializer[instruction]!!
|
||||||
val trivialEdges = resultForValsWithTrivialInitializer[instruction]!!
|
Edges(trivialEdges.incoming.replaceDelegate(edges.incoming), trivialEdges.outgoing.replaceDelegate(edges.outgoing))
|
||||||
Edges(trivialEdges.incoming.replaceDelegate(edges.incoming), trivialEdges.outgoing.replaceDelegate(edges.outgoing))
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun computeInitInfoForTrivialVals(): Map<Instruction, Edges<ReadOnlyInitControlFlowInfoImpl>> {
|
private fun computeInitInfoForTrivialVals(): Map<Instruction, Edges<ReadOnlyInitControlFlowInfoImpl>> {
|
||||||
@@ -170,8 +171,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
val enterState = ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, null)
|
val enterState = ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, null)
|
||||||
when (instruction) {
|
when (instruction) {
|
||||||
is VariableDeclarationInstruction ->
|
is VariableDeclarationInstruction ->
|
||||||
extractValWithTrivialInitializer(instruction)?.let {
|
extractValWithTrivialInitializer(instruction)?.let { variableDescriptor ->
|
||||||
variableDescriptor ->
|
|
||||||
declaredSet = declaredSet.add(variableDescriptor)
|
declaredSet = declaredSet.add(variableDescriptor)
|
||||||
}
|
}
|
||||||
is WriteValueInstruction -> {
|
is WriteValueInstruction -> {
|
||||||
@@ -193,12 +193,12 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
// WriteValueInstruction having KtDeclaration as an element means
|
// WriteValueInstruction having KtDeclaration as an element means
|
||||||
// it must be a write happened at the same time when
|
// it must be a write happened at the same time when
|
||||||
// the variable (common variable/parameter/object) has been declared
|
// the variable (common variable/parameter/object) has been declared
|
||||||
element is KtDeclaration
|
element is KtDeclaration
|
||||||
|
|
||||||
private inner class ReadOnlyInitControlFlowInfoImpl(
|
private inner class ReadOnlyInitControlFlowInfoImpl(
|
||||||
val declaredSet: ImmutableSet<VariableDescriptor>,
|
val declaredSet: ImmutableSet<VariableDescriptor>,
|
||||||
val initSet: ImmutableSet<VariableDescriptor>,
|
val initSet: ImmutableSet<VariableDescriptor>,
|
||||||
private val delegate: ReadOnlyInitControlFlowInfo?
|
private val delegate: ReadOnlyInitControlFlowInfo?
|
||||||
) : ReadOnlyInitControlFlowInfo {
|
) : ReadOnlyInitControlFlowInfo {
|
||||||
override fun getOrNull(variableDescriptor: VariableDescriptor): VariableControlFlowState? {
|
override fun getOrNull(variableDescriptor: VariableDescriptor): VariableControlFlowState? {
|
||||||
if (variableDescriptor in declaredSet) {
|
if (variableDescriptor in declaredSet) {
|
||||||
@@ -208,16 +208,15 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun checkDefiniteInitializationInWhen(merge: ReadOnlyInitControlFlowInfo): Boolean =
|
override fun checkDefiniteInitializationInWhen(merge: ReadOnlyInitControlFlowInfo): Boolean =
|
||||||
delegate?.checkDefiniteInitializationInWhen(merge) ?: false
|
delegate?.checkDefiniteInitializationInWhen(merge) ?: false
|
||||||
|
|
||||||
fun replaceDelegate(newDelegate: ReadOnlyInitControlFlowInfo): ReadOnlyInitControlFlowInfo =
|
fun replaceDelegate(newDelegate: ReadOnlyInitControlFlowInfo): ReadOnlyInitControlFlowInfo =
|
||||||
ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, newDelegate)
|
ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, newDelegate)
|
||||||
|
|
||||||
override fun asMap(): ImmutableMap<VariableDescriptor, VariableControlFlowState> {
|
override fun asMap(): ImmutableMap<VariableDescriptor, VariableControlFlowState> {
|
||||||
val initial = delegate?.asMap() ?: ImmutableHashMap.empty()
|
val initial = delegate?.asMap() ?: ImmutableHashMap.empty()
|
||||||
|
|
||||||
return declaredSet.fold(initial) {
|
return declaredSet.fold(initial) { acc, variableDescriptor ->
|
||||||
acc, variableDescriptor ->
|
|
||||||
acc.put(variableDescriptor, getOrNull(variableDescriptor)!!)
|
acc.put(variableDescriptor, getOrNull(variableDescriptor)!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -244,17 +243,16 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun addVariableInitStateFromCurrentInstructionIfAny(
|
private fun addVariableInitStateFromCurrentInstructionIfAny(
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
enterInstructionData: InitControlFlowInfo,
|
enterInstructionData: InitControlFlowInfo,
|
||||||
blockScopeVariableInfo: BlockScopeVariableInfo): InitControlFlowInfo {
|
blockScopeVariableInfo: BlockScopeVariableInfo
|
||||||
|
): InitControlFlowInfo {
|
||||||
if (instruction is MagicInstruction) {
|
if (instruction is MagicInstruction) {
|
||||||
if (instruction.kind === MagicKind.EXHAUSTIVE_WHEN_ELSE) {
|
if (instruction.kind === MagicKind.EXHAUSTIVE_WHEN_ELSE) {
|
||||||
return enterInstructionData.iterator().fold(enterInstructionData) {
|
return enterInstructionData.iterator().fold(enterInstructionData) { result, (key, value) ->
|
||||||
result, (key, value) ->
|
|
||||||
if (!value.definitelyInitialized()) {
|
if (!value.definitelyInitialized()) {
|
||||||
result.put(key, VariableControlFlowState.createInitializedExhaustively(value.isDeclared))
|
result.put(key, VariableControlFlowState.createInitializedExhaustively(value.isDeclared))
|
||||||
}
|
} else result
|
||||||
else result
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -262,9 +260,9 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
return enterInstructionData
|
return enterInstructionData
|
||||||
}
|
}
|
||||||
val variable =
|
val variable =
|
||||||
PseudocodeUtil.extractVariableDescriptorIfAny(instruction, bindingContext)
|
PseudocodeUtil.extractVariableDescriptorIfAny(instruction, bindingContext)
|
||||||
?.takeIf { it in rootVariables.nonTrivialVariables }
|
?.takeIf { it in rootVariables.nonTrivialVariables }
|
||||||
?: return enterInstructionData
|
?: return enterInstructionData
|
||||||
var exitInstructionData = enterInstructionData
|
var exitInstructionData = enterInstructionData
|
||||||
if (instruction is WriteValueInstruction) {
|
if (instruction is WriteValueInstruction) {
|
||||||
// if writing to already initialized object
|
// if writing to already initialized object
|
||||||
@@ -275,12 +273,11 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
val enterInitState = enterInstructionData.getOrNull(variable)
|
val enterInitState = enterInstructionData.getOrNull(variable)
|
||||||
val initializationAtThisElement = VariableControlFlowState.create(instruction.element is KtProperty, enterInitState)
|
val initializationAtThisElement = VariableControlFlowState.create(instruction.element is KtProperty, enterInitState)
|
||||||
exitInstructionData = exitInstructionData.put(variable, initializationAtThisElement, enterInitState)
|
exitInstructionData = exitInstructionData.put(variable, initializationAtThisElement, enterInitState)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// instruction instanceof VariableDeclarationInstruction
|
// instruction instanceof VariableDeclarationInstruction
|
||||||
val enterInitState =
|
val enterInitState =
|
||||||
enterInstructionData.getOrNull(variable)
|
enterInstructionData.getOrNull(variable)
|
||||||
?: getDefaultValueForInitializers(variable, instruction, blockScopeVariableInfo)
|
?: getDefaultValueForInitializers(variable, instruction, blockScopeVariableInfo)
|
||||||
|
|
||||||
if (!enterInitState.mayBeInitialized() || !enterInitState.isDeclared) {
|
if (!enterInitState.mayBeInitialized() || !enterInitState.isDeclared) {
|
||||||
val variableDeclarationInfo = VariableControlFlowState.create(enterInitState.initState, isDeclared = true)
|
val variableDeclarationInfo = VariableControlFlowState.create(enterInitState.initState, isDeclared = true)
|
||||||
@@ -303,12 +300,14 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return pseudocodeVariableDataCollector.collectData(TraversalOrder.BACKWARD, UseControlFlowInfo()) { instruction: Instruction, incomingEdgesData: Collection<UseControlFlowInfo> ->
|
return pseudocodeVariableDataCollector.collectData(
|
||||||
|
TraversalOrder.BACKWARD,
|
||||||
|
UseControlFlowInfo()
|
||||||
|
) { instruction: Instruction, incomingEdgesData: Collection<UseControlFlowInfo> ->
|
||||||
|
|
||||||
val enterResult: UseControlFlowInfo = if (incomingEdgesData.size == 1) {
|
val enterResult: UseControlFlowInfo = if (incomingEdgesData.size == 1) {
|
||||||
incomingEdgesData.single()
|
incomingEdgesData.single()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
incomingEdgesData.fold(UseControlFlowInfo()) { result, edgeData ->
|
incomingEdgesData.fold(UseControlFlowInfo()) { result, edgeData ->
|
||||||
edgeData.iterator().fold(result) { subResult, (variableDescriptor, variableUseState) ->
|
edgeData.iterator().fold(result) { subResult, (variableDescriptor, variableUseState) ->
|
||||||
subResult.put(variableDescriptor, variableUseState.merge(subResult.getOrNull(variableDescriptor)))
|
subResult.put(variableDescriptor, variableUseState.merge(subResult.getOrNull(variableDescriptor)))
|
||||||
@@ -317,38 +316,35 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
val variableDescriptor =
|
val variableDescriptor =
|
||||||
PseudocodeUtil.extractVariableDescriptorFromReference(instruction, bindingContext)
|
PseudocodeUtil.extractVariableDescriptorFromReference(instruction, bindingContext)
|
||||||
?.takeIf { it in rootVariables.nonTrivialVariables }
|
?.takeIf { it in rootVariables.nonTrivialVariables }
|
||||||
if (variableDescriptor == null || instruction !is ReadValueInstruction && instruction !is WriteValueInstruction) {
|
if (variableDescriptor == null || instruction !is ReadValueInstruction && instruction !is WriteValueInstruction) {
|
||||||
Edges(enterResult, enterResult)
|
Edges(enterResult, enterResult)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val exitResult =
|
val exitResult =
|
||||||
if (instruction is ReadValueInstruction) {
|
if (instruction is ReadValueInstruction) {
|
||||||
enterResult.put(variableDescriptor, VariableUseState.READ)
|
enterResult.put(variableDescriptor, VariableUseState.READ)
|
||||||
|
} else {
|
||||||
|
var variableUseState: VariableUseState? = enterResult.getOrNull(variableDescriptor)
|
||||||
|
if (variableUseState == null) {
|
||||||
|
variableUseState = VariableUseState.UNUSED
|
||||||
}
|
}
|
||||||
else {
|
when (variableUseState) {
|
||||||
var variableUseState: VariableUseState? = enterResult.getOrNull(variableDescriptor)
|
VariableUseState.UNUSED, VariableUseState.ONLY_WRITTEN_NEVER_READ ->
|
||||||
if (variableUseState == null) {
|
enterResult.put(variableDescriptor, VariableUseState.ONLY_WRITTEN_NEVER_READ)
|
||||||
variableUseState = VariableUseState.UNUSED
|
VariableUseState.WRITTEN_AFTER_READ, VariableUseState.READ ->
|
||||||
}
|
enterResult.put(variableDescriptor, VariableUseState.WRITTEN_AFTER_READ)
|
||||||
when (variableUseState) {
|
|
||||||
VariableUseState.UNUSED, VariableUseState.ONLY_WRITTEN_NEVER_READ ->
|
|
||||||
enterResult.put(variableDescriptor, VariableUseState.ONLY_WRITTEN_NEVER_READ)
|
|
||||||
VariableUseState.WRITTEN_AFTER_READ, VariableUseState.READ ->
|
|
||||||
enterResult.put(variableDescriptor, VariableUseState.WRITTEN_AFTER_READ)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Edges(enterResult, exitResult)
|
Edges(enterResult, exitResult)
|
||||||
}
|
}
|
||||||
}.mapValues {
|
}.mapValues { (_, edges) ->
|
||||||
(_, edges) ->
|
|
||||||
|
|
||||||
Edges(
|
Edges(
|
||||||
edgesForTrivialVals.incoming.replaceDelegate(edges.incoming),
|
edgesForTrivialVals.incoming.replaceDelegate(edges.incoming),
|
||||||
edgesForTrivialVals.outgoing.replaceDelegate(edges.outgoing)
|
edgesForTrivialVals.outgoing.replaceDelegate(edges.outgoing)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun computeUseInfoForTrivialVals(): Edges<ReadOnlyUseControlFlowInfoImpl> {
|
private fun computeUseInfoForTrivialVals(): Edges<ReadOnlyUseControlFlowInfoImpl> {
|
||||||
@@ -373,8 +369,8 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inner class ReadOnlyUseControlFlowInfoImpl(
|
private inner class ReadOnlyUseControlFlowInfoImpl(
|
||||||
val used: Set<VariableDescriptor>,
|
val used: Set<VariableDescriptor>,
|
||||||
val delegate: ReadOnlyUseControlFlowInfo?
|
val delegate: ReadOnlyUseControlFlowInfo?
|
||||||
) : ReadOnlyUseControlFlowInfo {
|
) : ReadOnlyUseControlFlowInfo {
|
||||||
override fun getOrNull(variableDescriptor: VariableDescriptor): VariableUseState? {
|
override fun getOrNull(variableDescriptor: VariableDescriptor): VariableUseState? {
|
||||||
if (variableDescriptor in used) return VariableUseState.READ
|
if (variableDescriptor in used) return VariableUseState.READ
|
||||||
@@ -382,13 +378,12 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun replaceDelegate(newDelegate: ReadOnlyUseControlFlowInfo): ReadOnlyUseControlFlowInfo =
|
fun replaceDelegate(newDelegate: ReadOnlyUseControlFlowInfo): ReadOnlyUseControlFlowInfo =
|
||||||
ReadOnlyUseControlFlowInfoImpl(used, newDelegate)
|
ReadOnlyUseControlFlowInfoImpl(used, newDelegate)
|
||||||
|
|
||||||
override fun asMap(): ImmutableMap<VariableDescriptor, VariableUseState> {
|
override fun asMap(): ImmutableMap<VariableDescriptor, VariableUseState> {
|
||||||
val initial = delegate?.asMap() ?: ImmutableHashMap.empty()
|
val initial = delegate?.asMap() ?: ImmutableHashMap.empty()
|
||||||
|
|
||||||
return used.fold(initial) {
|
return used.fold(initial) { acc, variableDescriptor ->
|
||||||
acc, variableDescriptor ->
|
|
||||||
acc.put(variableDescriptor, getOrNull(variableDescriptor)!!)
|
acc.put(variableDescriptor, getOrNull(variableDescriptor)!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -417,24 +412,24 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getDefaultValueForInitializers(
|
fun getDefaultValueForInitializers(
|
||||||
variable: VariableDescriptor,
|
variable: VariableDescriptor,
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
blockScopeVariableInfo: BlockScopeVariableInfo
|
blockScopeVariableInfo: BlockScopeVariableInfo
|
||||||
): VariableControlFlowState {
|
): VariableControlFlowState {
|
||||||
//todo: think of replacing it with "MapWithDefaultValue"
|
//todo: think of replacing it with "MapWithDefaultValue"
|
||||||
val declaredIn = blockScopeVariableInfo.declaredIn[variable]
|
val declaredIn = blockScopeVariableInfo.declaredIn[variable]
|
||||||
val declaredOutsideThisDeclaration =
|
val declaredOutsideThisDeclaration =
|
||||||
declaredIn == null //declared outside this pseudocode
|
declaredIn == null //declared outside this pseudocode
|
||||||
|| declaredIn.blockScopeForContainingDeclaration != instruction.blockScope.blockScopeForContainingDeclaration
|
|| declaredIn.blockScopeForContainingDeclaration != instruction.blockScope.blockScopeForContainingDeclaration
|
||||||
return VariableControlFlowState.create(isInitialized = declaredOutsideThisDeclaration)
|
return VariableControlFlowState.create(isInitialized = declaredOutsideThisDeclaration)
|
||||||
}
|
}
|
||||||
|
|
||||||
private val EMPTY_INIT_CONTROL_FLOW_INFO = InitControlFlowInfo()
|
private val EMPTY_INIT_CONTROL_FLOW_INFO = InitControlFlowInfo()
|
||||||
|
|
||||||
private fun mergeIncomingEdgesDataForInitializers(
|
private fun mergeIncomingEdgesDataForInitializers(
|
||||||
instruction: Instruction,
|
instruction: Instruction,
|
||||||
incomingEdgesData: Collection<InitControlFlowInfo>,
|
incomingEdgesData: Collection<InitControlFlowInfo>,
|
||||||
blockScopeVariableInfo: BlockScopeVariableInfo
|
blockScopeVariableInfo: BlockScopeVariableInfo
|
||||||
): InitControlFlowInfo {
|
): InitControlFlowInfo {
|
||||||
if (incomingEdgesData.size == 1) return incomingEdgesData.single()
|
if (incomingEdgesData.size == 1) return incomingEdgesData.single()
|
||||||
if (incomingEdgesData.isEmpty()) return EMPTY_INIT_CONTROL_FLOW_INFO
|
if (incomingEdgesData.isEmpty()) return EMPTY_INIT_CONTROL_FLOW_INFO
|
||||||
@@ -448,7 +443,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
|||||||
var isDeclared = true
|
var isDeclared = true
|
||||||
for (edgeData in incomingEdgesData) {
|
for (edgeData in incomingEdgesData) {
|
||||||
val varControlFlowState = edgeData.getOrNull(variable)
|
val varControlFlowState = edgeData.getOrNull(variable)
|
||||||
?: getDefaultValueForInitializers(variable, instruction, blockScopeVariableInfo)
|
?: getDefaultValueForInitializers(variable, instruction, blockScopeVariableInfo)
|
||||||
initState = initState?.merge(varControlFlowState.initState) ?: varControlFlowState.initState
|
initState = initState?.merge(varControlFlowState.initState) ?: varControlFlowState.initState
|
||||||
if (!varControlFlowState.isDeclared) {
|
if (!varControlFlowState.isDeclared) {
|
||||||
isDeclared = false
|
isDeclared = false
|
||||||
|
|||||||
@@ -33,8 +33,8 @@ interface UnreachableCode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class UnreachableCodeImpl(
|
class UnreachableCodeImpl(
|
||||||
private val reachableElements: Set<KtElement>,
|
private val reachableElements: Set<KtElement>,
|
||||||
private val unreachableElements: Set<KtElement>
|
private val unreachableElements: Set<KtElement>
|
||||||
) : UnreachableCode {
|
) : UnreachableCode {
|
||||||
|
|
||||||
// This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well
|
// This is needed in order to highlight only '1 < 2' and not '1', '<' and '2' as well
|
||||||
@@ -42,30 +42,29 @@ class UnreachableCodeImpl(
|
|||||||
|
|
||||||
override fun getUnreachableTextRanges(element: KtElement): List<TextRange> {
|
override fun getUnreachableTextRanges(element: KtElement): List<TextRange> {
|
||||||
return if (element.hasChildrenInSet(reachableElements)) {
|
return if (element.hasChildrenInSet(reachableElements)) {
|
||||||
with (element.getLeavesOrReachableChildren().removeReachableElementsWithMeaninglessSiblings().mergeAdjacentTextRanges()) {
|
with(element.getLeavesOrReachableChildren().removeReachableElementsWithMeaninglessSiblings().mergeAdjacentTextRanges()) {
|
||||||
if (isNotEmpty()) this
|
if (isNotEmpty()) this
|
||||||
// Specific case like condition in when:
|
// Specific case like condition in when:
|
||||||
// element is dead but its only child is alive and has the same text range
|
// element is dead but its only child is alive and has the same text range
|
||||||
else listOf(element.textRange.endOffset.let { TextRange(it, it) })
|
else listOf(element.textRange.endOffset.let { TextRange(it, it) })
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
listOf(element.textRange!!)
|
listOf(element.textRange!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KtElement.hasChildrenInSet(set: Set<KtElement>): Boolean =
|
private fun KtElement.hasChildrenInSet(set: Set<KtElement>): Boolean =
|
||||||
PsiTreeUtil.collectElements(this) { it != this }.any { it in set }
|
PsiTreeUtil.collectElements(this) { it != this }.any { it in set }
|
||||||
|
|
||||||
private fun KtElement.getLeavesOrReachableChildren(): List<PsiElement> {
|
private fun KtElement.getLeavesOrReachableChildren(): List<PsiElement> {
|
||||||
val children = ArrayList<PsiElement>()
|
val children = ArrayList<PsiElement>()
|
||||||
acceptChildren(object : PsiElementVisitor() {
|
acceptChildren(object : PsiElementVisitor() {
|
||||||
override fun visitElement(element: PsiElement) {
|
override fun visitElement(element: PsiElement) {
|
||||||
val isReachable = element is KtElement && reachableElements.contains(element) && !element.hasChildrenInSet(unreachableElements)
|
val isReachable =
|
||||||
|
element is KtElement && reachableElements.contains(element) && !element.hasChildrenInSet(unreachableElements)
|
||||||
if (isReachable || element.children.isEmpty()) {
|
if (isReachable || element.children.isEmpty()) {
|
||||||
children.add(element)
|
children.add(element)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
element.acceptChildren(this)
|
element.acceptChildren(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -102,8 +101,7 @@ class UnreachableCodeImpl(
|
|||||||
|
|
||||||
private fun List<PsiElement>.mergeAdjacentTextRanges(): List<TextRange> {
|
private fun List<PsiElement>.mergeAdjacentTextRanges(): List<TextRange> {
|
||||||
val result = ArrayList<TextRange>()
|
val result = ArrayList<TextRange>()
|
||||||
val lastRange = fold(null as TextRange?) {
|
val lastRange = fold(null as TextRange?) { currentTextRange, element ->
|
||||||
currentTextRange, element ->
|
|
||||||
|
|
||||||
val elementRange = element.textRange!!
|
val elementRange = element.textRange!!
|
||||||
when {
|
when {
|
||||||
|
|||||||
@@ -54,10 +54,10 @@ val List<WhenMissingCase>.hasUnknown: Boolean
|
|||||||
|
|
||||||
private interface WhenExhaustivenessChecker {
|
private interface WhenExhaustivenessChecker {
|
||||||
fun getMissingCases(
|
fun getMissingCases(
|
||||||
expression: KtWhenExpression,
|
expression: KtWhenExpression,
|
||||||
context: BindingContext,
|
context: BindingContext,
|
||||||
subjectDescriptor: ClassDescriptor?,
|
subjectDescriptor: ClassDescriptor?,
|
||||||
nullable: Boolean
|
nullable: Boolean
|
||||||
): List<WhenMissingCase>
|
): List<WhenMissingCase>
|
||||||
|
|
||||||
fun isApplicable(subjectType: KotlinType): Boolean = false
|
fun isApplicable(subjectType: KotlinType): Boolean = false
|
||||||
@@ -72,7 +72,7 @@ object NullMissingCase : WhenMissingCase() {
|
|||||||
// It's not a regular exhaustiveness checker, invoke it only inside other checkers
|
// It's not a regular exhaustiveness checker, invoke it only inside other checkers
|
||||||
private object WhenOnNullableExhaustivenessChecker /* : WhenExhaustivenessChecker*/ {
|
private object WhenOnNullableExhaustivenessChecker /* : WhenExhaustivenessChecker*/ {
|
||||||
fun getMissingCases(expression: KtWhenExpression, context: BindingContext, nullable: Boolean) =
|
fun getMissingCases(expression: KtWhenExpression, context: BindingContext, nullable: Boolean) =
|
||||||
if (nullable) getNullCaseIfMissing(expression, context) else listOf()
|
if (nullable) getNullCaseIfMissing(expression, context) else listOf()
|
||||||
|
|
||||||
private fun getNullCaseIfMissing(expression: KtWhenExpression, context: BindingContext): List<WhenMissingCase> {
|
private fun getNullCaseIfMissing(expression: KtWhenExpression, context: BindingContext): List<WhenMissingCase> {
|
||||||
for (entry in expression.entries) {
|
for (entry in expression.entries) {
|
||||||
@@ -99,10 +99,10 @@ class BooleanMissingCase(val b: Boolean) : WhenMissingCase() {
|
|||||||
|
|
||||||
private object WhenOnBooleanExhaustivenessChecker : WhenExhaustivenessChecker {
|
private object WhenOnBooleanExhaustivenessChecker : WhenExhaustivenessChecker {
|
||||||
override fun getMissingCases(
|
override fun getMissingCases(
|
||||||
expression: KtWhenExpression,
|
expression: KtWhenExpression,
|
||||||
context: BindingContext,
|
context: BindingContext,
|
||||||
subjectDescriptor: ClassDescriptor?,
|
subjectDescriptor: ClassDescriptor?,
|
||||||
nullable: Boolean
|
nullable: Boolean
|
||||||
): List<WhenMissingCase> {
|
): List<WhenMissingCase> {
|
||||||
// It's assumed (and not checked) that expression is of the boolean type
|
// It's assumed (and not checked) that expression is of the boolean type
|
||||||
var containsFalse = false
|
var containsFalse = false
|
||||||
@@ -117,8 +117,8 @@ private object WhenOnBooleanExhaustivenessChecker : WhenExhaustivenessChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return (if (!containsTrue) listOf(BooleanMissingCase(true)) else listOf()) +
|
return (if (!containsTrue) listOf(BooleanMissingCase(true)) else listOf()) +
|
||||||
(if (!containsFalse) listOf(BooleanMissingCase(false)) else listOf()) +
|
(if (!containsFalse) listOf(BooleanMissingCase(false)) else listOf()) +
|
||||||
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
|
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isApplicable(subjectType: KotlinType): Boolean {
|
override fun isApplicable(subjectType: KotlinType): Boolean {
|
||||||
@@ -126,7 +126,7 @@ private object WhenOnBooleanExhaustivenessChecker : WhenExhaustivenessChecker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ClassMissingCase(val descriptor: ClassDescriptor): WhenMissingCase() {
|
class ClassMissingCase(val descriptor: ClassDescriptor) : WhenMissingCase() {
|
||||||
val classIsSingleton get() = descriptor.kind.isSingleton
|
val classIsSingleton get() = descriptor.kind.isSingleton
|
||||||
|
|
||||||
val classFqName get() = DescriptorUtils.getFqNameFromTopLevelClass(descriptor)
|
val classFqName get() = DescriptorUtils.getFqNameFromTopLevelClass(descriptor)
|
||||||
@@ -138,11 +138,11 @@ class ClassMissingCase(val descriptor: ClassDescriptor): WhenMissingCase() {
|
|||||||
|
|
||||||
internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChecker {
|
internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChecker {
|
||||||
private fun getReference(expression: KtExpression?): KtSimpleNameExpression? =
|
private fun getReference(expression: KtExpression?): KtSimpleNameExpression? =
|
||||||
when (expression) {
|
when (expression) {
|
||||||
is KtSimpleNameExpression -> expression
|
is KtSimpleNameExpression -> expression
|
||||||
is KtQualifiedExpression -> getReference(expression.selectorExpression)
|
is KtQualifiedExpression -> getReference(expression.selectorExpression)
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
|
|
||||||
protected val ClassDescriptor.deepSealedSubclasses: List<ClassDescriptor>
|
protected val ClassDescriptor.deepSealedSubclasses: List<ClassDescriptor>
|
||||||
get() = this.sealedSubclasses.flatMap {
|
get() = this.sealedSubclasses.flatMap {
|
||||||
@@ -154,9 +154,9 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
|
|||||||
get() = (this as? KtWhenConditionIsPattern)?.isNegated ?: false
|
get() = (this as? KtWhenConditionIsPattern)?.isNegated ?: false
|
||||||
|
|
||||||
private fun KtWhenCondition.isRelevant(checkedDescriptor: ClassDescriptor) =
|
private fun KtWhenCondition.isRelevant(checkedDescriptor: ClassDescriptor) =
|
||||||
this !is KtWhenConditionWithExpression ||
|
this !is KtWhenConditionWithExpression ||
|
||||||
DescriptorUtils.isObject(checkedDescriptor) ||
|
DescriptorUtils.isObject(checkedDescriptor) ||
|
||||||
DescriptorUtils.isEnumEntry(checkedDescriptor)
|
DescriptorUtils.isEnumEntry(checkedDescriptor)
|
||||||
|
|
||||||
private fun KtWhenCondition.getCheckedDescriptor(context: BindingContext): ClassDescriptor? {
|
private fun KtWhenCondition.getCheckedDescriptor(context: BindingContext): ClassDescriptor? {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
@@ -175,9 +175,9 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected fun getMissingClassCases(
|
protected fun getMissingClassCases(
|
||||||
whenExpression: KtWhenExpression,
|
whenExpression: KtWhenExpression,
|
||||||
subclasses: Set<ClassDescriptor>,
|
subclasses: Set<ClassDescriptor>,
|
||||||
context: BindingContext
|
context: BindingContext
|
||||||
): List<WhenMissingCase> {
|
): List<WhenMissingCase> {
|
||||||
// when on empty enum / sealed is considered non-exhaustive, see test whenOnEmptySealed
|
// when on empty enum / sealed is considered non-exhaustive, see test whenOnEmptySealed
|
||||||
if (subclasses.isEmpty()) return listOf(UnknownMissingCase)
|
if (subclasses.isEmpty()) return listOf(UnknownMissingCase)
|
||||||
@@ -188,8 +188,8 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
|
|||||||
val negated = condition.negated
|
val negated = condition.negated
|
||||||
val checkedDescriptor = condition.getCheckedDescriptor(context) ?: continue
|
val checkedDescriptor = condition.getCheckedDescriptor(context) ?: continue
|
||||||
val checkedDescriptorSubclasses =
|
val checkedDescriptorSubclasses =
|
||||||
if (checkedDescriptor.modality == Modality.SEALED) checkedDescriptor.deepSealedSubclasses
|
if (checkedDescriptor.modality == Modality.SEALED) checkedDescriptor.deepSealedSubclasses
|
||||||
else listOf(checkedDescriptor)
|
else listOf(checkedDescriptor)
|
||||||
|
|
||||||
// Checks are important only for nested subclasses of the sealed class
|
// Checks are important only for nested subclasses of the sealed class
|
||||||
// In additional, check without "is" is important only for objects
|
// In additional, check without "is" is important only for objects
|
||||||
@@ -201,8 +201,7 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
|
|||||||
if (checkedDescriptors.containsAll(checkedDescriptorSubclasses)) return listOf()
|
if (checkedDescriptors.containsAll(checkedDescriptorSubclasses)) return listOf()
|
||||||
checkedDescriptors.addAll(subclasses)
|
checkedDescriptors.addAll(subclasses)
|
||||||
checkedDescriptors.removeAll(checkedDescriptorSubclasses)
|
checkedDescriptors.removeAll(checkedDescriptorSubclasses)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
checkedDescriptors.addAll(checkedDescriptorSubclasses)
|
checkedDescriptors.addAll(checkedDescriptorSubclasses)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -213,19 +212,19 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
|
|||||||
|
|
||||||
private object WhenOnEnumExhaustivenessChecker : WhenOnClassExhaustivenessChecker() {
|
private object WhenOnEnumExhaustivenessChecker : WhenOnClassExhaustivenessChecker() {
|
||||||
override fun getMissingCases(
|
override fun getMissingCases(
|
||||||
expression: KtWhenExpression,
|
expression: KtWhenExpression,
|
||||||
context: BindingContext,
|
context: BindingContext,
|
||||||
subjectDescriptor: ClassDescriptor?,
|
subjectDescriptor: ClassDescriptor?,
|
||||||
nullable: Boolean
|
nullable: Boolean
|
||||||
): List<WhenMissingCase> {
|
): List<WhenMissingCase> {
|
||||||
assert(isEnumClass(subjectDescriptor)) { "isWhenOnEnumExhaustive should be called with an enum class descriptor" }
|
assert(isEnumClass(subjectDescriptor)) { "isWhenOnEnumExhaustive should be called with an enum class descriptor" }
|
||||||
val entryDescriptors =
|
val entryDescriptors =
|
||||||
DescriptorUtils.getAllDescriptors(subjectDescriptor!!.unsubstitutedInnerClassesScope)
|
DescriptorUtils.getAllDescriptors(subjectDescriptor!!.unsubstitutedInnerClassesScope)
|
||||||
.filter(::isEnumEntry)
|
.filter(::isEnumEntry)
|
||||||
.filterIsInstance<ClassDescriptor>()
|
.filterIsInstance<ClassDescriptor>()
|
||||||
.toSet()
|
.toSet()
|
||||||
return getMissingClassCases(expression, entryDescriptors, context) +
|
return getMissingClassCases(expression, entryDescriptors, context) +
|
||||||
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
|
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isApplicable(subjectType: KotlinType): Boolean {
|
override fun isApplicable(subjectType: KotlinType): Boolean {
|
||||||
@@ -236,10 +235,10 @@ private object WhenOnEnumExhaustivenessChecker : WhenOnClassExhaustivenessChecke
|
|||||||
internal object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChecker() {
|
internal object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChecker() {
|
||||||
|
|
||||||
override fun getMissingCases(
|
override fun getMissingCases(
|
||||||
expression: KtWhenExpression,
|
expression: KtWhenExpression,
|
||||||
context: BindingContext,
|
context: BindingContext,
|
||||||
subjectDescriptor: ClassDescriptor?,
|
subjectDescriptor: ClassDescriptor?,
|
||||||
nullable: Boolean
|
nullable: Boolean
|
||||||
): List<WhenMissingCase> {
|
): List<WhenMissingCase> {
|
||||||
assert(DescriptorUtils.isSealedClass(subjectDescriptor)) {
|
assert(DescriptorUtils.isSealedClass(subjectDescriptor)) {
|
||||||
"isWhenOnSealedClassExhaustive should be called with a sealed class descriptor: $subjectDescriptor"
|
"isWhenOnSealedClassExhaustive should be called with a sealed class descriptor: $subjectDescriptor"
|
||||||
@@ -247,7 +246,7 @@ internal object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChe
|
|||||||
|
|
||||||
val allSubclasses = subjectDescriptor!!.deepSealedSubclasses
|
val allSubclasses = subjectDescriptor!!.deepSealedSubclasses
|
||||||
return getMissingClassCases(expression, allSubclasses.toSet(), context) +
|
return getMissingClassCases(expression, allSubclasses.toSet(), context) +
|
||||||
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
|
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun isApplicable(subjectType: KotlinType): Boolean {
|
override fun isApplicable(subjectType: KotlinType): Boolean {
|
||||||
@@ -258,13 +257,15 @@ internal object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChe
|
|||||||
|
|
||||||
object WhenChecker {
|
object WhenChecker {
|
||||||
|
|
||||||
private val exhaustivenessCheckers = listOf(WhenOnBooleanExhaustivenessChecker,
|
private val exhaustivenessCheckers = listOf(
|
||||||
WhenOnEnumExhaustivenessChecker,
|
WhenOnBooleanExhaustivenessChecker,
|
||||||
WhenOnSealedExhaustivenessChecker)
|
WhenOnEnumExhaustivenessChecker,
|
||||||
|
WhenOnSealedExhaustivenessChecker
|
||||||
|
)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun isWhenByEnum(expression: KtWhenExpression, context: BindingContext) =
|
fun isWhenByEnum(expression: KtWhenExpression, context: BindingContext) =
|
||||||
getClassDescriptorOfTypeIfEnum(whenSubjectType(expression, context)) != null
|
getClassDescriptorOfTypeIfEnum(whenSubjectType(expression, context)) != null
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getClassDescriptorOfTypeIfEnum(type: KotlinType?): ClassDescriptor? {
|
fun getClassDescriptorOfTypeIfEnum(type: KotlinType?): ClassDescriptor? {
|
||||||
@@ -276,26 +277,26 @@ object WhenChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getClassDescriptorOfTypeIfSealed(type: KotlinType?): ClassDescriptor?
|
fun getClassDescriptorOfTypeIfSealed(type: KotlinType?): ClassDescriptor? =
|
||||||
= type?.let { TypeUtils.getClassDescriptor(it) }?.takeIf { DescriptorUtils.isSealedClass(it) }
|
type?.let { TypeUtils.getClassDescriptor(it) }?.takeIf { DescriptorUtils.isSealedClass(it) }
|
||||||
|
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun whenSubjectType(expression: KtWhenExpression, context: BindingContext) =
|
fun whenSubjectType(expression: KtWhenExpression, context: BindingContext) =
|
||||||
expression.subjectExpression?.let { context.get(SMARTCAST, it)?.defaultType ?: context.getType(it) }
|
expression.subjectExpression?.let { context.get(SMARTCAST, it)?.defaultType ?: context.getType(it) }
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getEnumMissingCases(
|
fun getEnumMissingCases(
|
||||||
expression: KtWhenExpression,
|
expression: KtWhenExpression,
|
||||||
context: BindingContext,
|
context: BindingContext,
|
||||||
enumClassDescriptor: ClassDescriptor
|
enumClassDescriptor: ClassDescriptor
|
||||||
) = WhenOnEnumExhaustivenessChecker.getMissingCases(expression, context, enumClassDescriptor, false)
|
) = WhenOnEnumExhaustivenessChecker.getMissingCases(expression, context, enumClassDescriptor, false)
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun getSealedMissingCases(
|
fun getSealedMissingCases(
|
||||||
expression: KtWhenExpression,
|
expression: KtWhenExpression,
|
||||||
context: BindingContext,
|
context: BindingContext,
|
||||||
sealedClassDescriptor: ClassDescriptor
|
sealedClassDescriptor: ClassDescriptor
|
||||||
) = WhenOnSealedExhaustivenessChecker.getMissingCases(expression, context, sealedClassDescriptor, false)
|
) = WhenOnSealedExhaustivenessChecker.getMissingCases(expression, context, sealedClassDescriptor, false)
|
||||||
|
|
||||||
fun getMissingCases(expression: KtWhenExpression, context: BindingContext): List<WhenMissingCase> {
|
fun getMissingCases(expression: KtWhenExpression, context: BindingContext): List<WhenMissingCase> {
|
||||||
@@ -308,15 +309,15 @@ object WhenChecker {
|
|||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun isWhenExhaustive(expression: KtWhenExpression, trace: BindingTrace) =
|
fun isWhenExhaustive(expression: KtWhenExpression, trace: BindingTrace) =
|
||||||
if (getMissingCases(expression, trace.bindingContext).isEmpty()) {
|
if (getMissingCases(expression, trace.bindingContext).isEmpty()) {
|
||||||
trace.record(BindingContext.EXHAUSTIVE_WHEN, expression)
|
trace.record(BindingContext.EXHAUSTIVE_WHEN, expression)
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
fun containsNullCase(expression: KtWhenExpression, context: BindingContext) =
|
fun containsNullCase(expression: KtWhenExpression, context: BindingContext) =
|
||||||
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, true).isEmpty()
|
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, true).isEmpty()
|
||||||
|
|
||||||
fun checkDuplicatedLabels(expression: KtWhenExpression, trace: BindingTrace) {
|
fun checkDuplicatedLabels(expression: KtWhenExpression, trace: BindingTrace) {
|
||||||
if (expression.subjectExpression == null) return
|
if (expression.subjectExpression == null) return
|
||||||
@@ -331,11 +332,11 @@ object WhenChecker {
|
|||||||
is KtWhenConditionWithExpression -> {
|
is KtWhenConditionWithExpression -> {
|
||||||
val constantExpression = condition.expression ?: continue@conditions
|
val constantExpression = condition.expression ?: continue@conditions
|
||||||
val constant = ConstantExpressionEvaluator.getConstant(
|
val constant = ConstantExpressionEvaluator.getConstant(
|
||||||
constantExpression, trace.bindingContext) ?: continue@conditions
|
constantExpression, trace.bindingContext
|
||||||
|
) ?: continue@conditions
|
||||||
if (checkedConstants.contains(constant)) {
|
if (checkedConstants.contains(constant)) {
|
||||||
trace.report(Errors.DUPLICATE_LABEL_IN_WHEN.on(constantExpression))
|
trace.report(Errors.DUPLICATE_LABEL_IN_WHEN.on(constantExpression))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
checkedConstants.add(constant)
|
checkedConstants.add(constant)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,12 +347,12 @@ object WhenChecker {
|
|||||||
val typeWithIsNegation = type to condition.isNegated
|
val typeWithIsNegation = type to condition.isNegated
|
||||||
if (checkedTypes.contains(typeWithIsNegation)) {
|
if (checkedTypes.contains(typeWithIsNegation)) {
|
||||||
trace.report(Errors.DUPLICATE_LABEL_IN_WHEN.on(typeReference))
|
trace.report(Errors.DUPLICATE_LABEL_IN_WHEN.on(typeReference))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
checkedTypes.add(typeWithIsNegation)
|
checkedTypes.add(typeWithIsNegation)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else -> {}
|
else -> {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+66
-60
@@ -58,8 +58,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
|||||||
val worker = builders.pop()
|
val worker = builders.pop()
|
||||||
builder = if (!builders.isEmpty()) {
|
builder = if (!builders.isEmpty()) {
|
||||||
builders.peek()
|
builders.peek()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
return worker
|
return worker
|
||||||
@@ -70,8 +69,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
|||||||
val shouldInlnie = invocationKind != null
|
val shouldInlnie = invocationKind != null
|
||||||
if (builder != null && subroutine is KtFunctionLiteral) {
|
if (builder != null && subroutine is KtFunctionLiteral) {
|
||||||
pushBuilder(subroutine, builder.returnSubroutine, shouldInlnie)
|
pushBuilder(subroutine, builder.returnSubroutine, shouldInlnie)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
pushBuilder(subroutine, subroutine, shouldInlnie)
|
pushBuilder(subroutine, subroutine, shouldInlnie)
|
||||||
}
|
}
|
||||||
delegateBuilder.enterBlockScope(subroutine)
|
delegateBuilder.enterBlockScope(subroutine)
|
||||||
@@ -86,8 +84,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
|||||||
val builder = builders.peek()
|
val builder = builders.peek()
|
||||||
if (invocationKind == null) {
|
if (invocationKind == null) {
|
||||||
builder.declareFunction(subroutine, worker.pseudocode)
|
builder.declareFunction(subroutine, worker.pseudocode)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
builder.declareInlinedFunction(subroutine, worker.pseudocode, invocationKind)
|
builder.declareInlinedFunction(subroutine, worker.pseudocode, invocationKind)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -95,9 +92,9 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inner class ControlFlowInstructionsGeneratorWorker(
|
private inner class ControlFlowInstructionsGeneratorWorker(
|
||||||
scopingElement: KtElement,
|
scopingElement: KtElement,
|
||||||
override val returnSubroutine: KtElement,
|
override val returnSubroutine: KtElement,
|
||||||
shouldInline: Boolean
|
shouldInline: Boolean
|
||||||
) : ControlFlowBuilder {
|
) : ControlFlowBuilder {
|
||||||
|
|
||||||
val pseudocode: PseudocodeImpl = PseudocodeImpl(scopingElement, shouldInline)
|
val pseudocode: PseudocodeImpl = PseudocodeImpl(scopingElement, shouldInline)
|
||||||
@@ -128,12 +125,13 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val info = LoopInfo(
|
val info = LoopInfo(
|
||||||
expression,
|
expression,
|
||||||
createUnboundLabel("loop entry point"),
|
createUnboundLabel("loop entry point"),
|
||||||
createUnboundLabel("loop exit point"),
|
createUnboundLabel("loop exit point"),
|
||||||
createUnboundLabel("body entry point"),
|
createUnboundLabel("body entry point"),
|
||||||
createUnboundLabel("body exit point"),
|
createUnboundLabel("body exit point"),
|
||||||
createUnboundLabel("condition entry point"))
|
createUnboundLabel("condition entry point")
|
||||||
|
)
|
||||||
bindLabel(info.entryPoint)
|
bindLabel(info.entryPoint)
|
||||||
elementToLoopInfo.put(expression, info)
|
elementToLoopInfo.put(expression, info)
|
||||||
return info
|
return info
|
||||||
@@ -158,9 +156,10 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
|||||||
|
|
||||||
override fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind?) {
|
override fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind?) {
|
||||||
val blockInfo = SubroutineInfo(
|
val blockInfo = SubroutineInfo(
|
||||||
subroutine,
|
subroutine,
|
||||||
/* entry point */ createUnboundLabel(),
|
/* entry point */ createUnboundLabel(),
|
||||||
/* exit point */ createUnboundLabel())
|
/* exit point */ createUnboundLabel()
|
||||||
|
)
|
||||||
elementToSubroutineInfo.put(subroutine, blockInfo)
|
elementToSubroutineInfo.put(subroutine, blockInfo)
|
||||||
allBlocks.push(blockInfo)
|
allBlocks.push(blockInfo)
|
||||||
bindLabel(blockInfo.entryPoint)
|
bindLabel(blockInfo.entryPoint)
|
||||||
@@ -173,10 +172,11 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
|||||||
override fun getLoopConditionEntryPoint(loop: KtLoopExpression): Label? = elementToLoopInfo[loop]?.conditionEntryPoint
|
override fun getLoopConditionEntryPoint(loop: KtLoopExpression): Label? = elementToLoopInfo[loop]?.conditionEntryPoint
|
||||||
|
|
||||||
override fun getLoopExitPoint(loop: KtLoopExpression): Label? =// It's quite possible to have null here, see testBreakInsideLocal
|
override fun getLoopExitPoint(loop: KtLoopExpression): Label? =// It's quite possible to have null here, see testBreakInsideLocal
|
||||||
elementToLoopInfo[loop]?.exitPoint
|
elementToLoopInfo[loop]?.exitPoint
|
||||||
|
|
||||||
override fun getSubroutineExitPoint(labelElement: KtElement): Label? =// It's quite possible to have null here, e.g. for non-local returns (see KT-10823)
|
override fun getSubroutineExitPoint(labelElement: KtElement): Label? =
|
||||||
elementToSubroutineInfo[labelElement]?.exitPoint
|
// It's quite possible to have null here, e.g. for non-local returns (see KT-10823)
|
||||||
|
elementToSubroutineInfo[labelElement]?.exitPoint
|
||||||
|
|
||||||
private val currentScope: BlockScope
|
private val currentScope: BlockScope
|
||||||
get() = blockScopes.peek()
|
get() = blockScopes.peek()
|
||||||
@@ -191,8 +191,8 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
|||||||
val currentScope = currentScope
|
val currentScope = currentScope
|
||||||
assert(currentScope.block === block) {
|
assert(currentScope.block === block) {
|
||||||
"Exit from not the current block scope.\n" +
|
"Exit from not the current block scope.\n" +
|
||||||
"Current scope is for a block: " + currentScope.block.text + ".\n" +
|
"Current scope is for a block: " + currentScope.block.text + ".\n" +
|
||||||
"Exit from the scope for: " + block.text
|
"Exit from the scope for: " + block.text
|
||||||
}
|
}
|
||||||
blockScopes.pop()
|
blockScopes.pop()
|
||||||
}
|
}
|
||||||
@@ -252,11 +252,12 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun write(
|
override fun write(
|
||||||
assignment: KtElement,
|
assignment: KtElement,
|
||||||
lValue: KtElement,
|
lValue: KtElement,
|
||||||
rValue: PseudoValue,
|
rValue: PseudoValue,
|
||||||
target: AccessTarget,
|
target: AccessTarget,
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue>) {
|
receiverValues: Map<PseudoValue, ReceiverValue>
|
||||||
|
) {
|
||||||
add(WriteValueInstruction(assignment, currentScope, target, receiverValues, lValue, rValue))
|
add(WriteValueInstruction(assignment, currentScope, target, receiverValues, lValue, rValue))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,22 +343,24 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
|||||||
override fun createAnonymousObject(expression: KtObjectLiteralExpression) = read(expression)
|
override fun createAnonymousObject(expression: KtObjectLiteralExpression) = read(expression)
|
||||||
|
|
||||||
override fun createLambda(expression: KtFunction) =
|
override fun createLambda(expression: KtFunction) =
|
||||||
read(if (expression is KtFunctionLiteral) expression.getParent() as KtLambdaExpression else expression)
|
read(if (expression is KtFunctionLiteral) expression.getParent() as KtLambdaExpression else expression)
|
||||||
|
|
||||||
override fun loadStringTemplate(
|
override fun loadStringTemplate(
|
||||||
expression: KtStringTemplateExpression,
|
expression: KtStringTemplateExpression,
|
||||||
inputValues: List<PseudoValue>
|
inputValues: List<PseudoValue>
|
||||||
): InstructionWithValue =
|
): InstructionWithValue =
|
||||||
if (inputValues.isEmpty()) read(expression)
|
if (inputValues.isEmpty()) read(expression)
|
||||||
else magic(expression, expression, inputValues, MagicKind.STRING_TEMPLATE)
|
else magic(expression, expression, inputValues, MagicKind.STRING_TEMPLATE)
|
||||||
|
|
||||||
override fun magic(
|
override fun magic(
|
||||||
instructionElement: KtElement,
|
instructionElement: KtElement,
|
||||||
valueElement: KtElement?,
|
valueElement: KtElement?,
|
||||||
inputValues: List<PseudoValue>,
|
inputValues: List<PseudoValue>,
|
||||||
kind: MagicKind): MagicInstruction {
|
kind: MagicKind
|
||||||
|
): MagicInstruction {
|
||||||
val instruction = MagicInstruction(
|
val instruction = MagicInstruction(
|
||||||
instructionElement, valueElement, currentScope, inputValues, kind, valueFactory)
|
instructionElement, valueElement, currentScope, inputValues, kind, valueFactory
|
||||||
|
)
|
||||||
add(instruction)
|
add(instruction)
|
||||||
return instruction
|
return instruction
|
||||||
}
|
}
|
||||||
@@ -369,32 +372,35 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun readVariable(
|
override fun readVariable(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
resolvedCall: ResolvedCall<*>,
|
resolvedCall: ResolvedCall<*>,
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue>
|
receiverValues: Map<PseudoValue, ReceiverValue>
|
||||||
) = read(expression, resolvedCall, receiverValues)
|
) = read(expression, resolvedCall, receiverValues)
|
||||||
|
|
||||||
override fun call(
|
override fun call(
|
||||||
valueElement: KtElement,
|
valueElement: KtElement,
|
||||||
resolvedCall: ResolvedCall<*>,
|
resolvedCall: ResolvedCall<*>,
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue>,
|
receiverValues: Map<PseudoValue, ReceiverValue>,
|
||||||
arguments: Map<PseudoValue, ValueParameterDescriptor>): CallInstruction {
|
arguments: Map<PseudoValue, ValueParameterDescriptor>
|
||||||
|
): CallInstruction {
|
||||||
val returnType = resolvedCall.resultingDescriptor.returnType
|
val returnType = resolvedCall.resultingDescriptor.returnType
|
||||||
val instruction = CallInstruction(
|
val instruction = CallInstruction(
|
||||||
valueElement,
|
valueElement,
|
||||||
currentScope,
|
currentScope,
|
||||||
resolvedCall,
|
resolvedCall,
|
||||||
receiverValues,
|
receiverValues,
|
||||||
arguments,
|
arguments,
|
||||||
if (returnType != null && KotlinBuiltIns.isNothing(returnType)) null else valueFactory)
|
if (returnType != null && KotlinBuiltIns.isNothing(returnType)) null else valueFactory
|
||||||
|
)
|
||||||
add(instruction)
|
add(instruction)
|
||||||
return instruction
|
return instruction
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun predefinedOperation(
|
override fun predefinedOperation(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
operation: ControlFlowBuilder.PredefinedOperation,
|
operation: ControlFlowBuilder.PredefinedOperation,
|
||||||
inputValues: List<PseudoValue>): OperationInstruction = magic(expression, expression, inputValues, getMagicKind(operation))
|
inputValues: List<PseudoValue>
|
||||||
|
): OperationInstruction = magic(expression, expression, inputValues, getMagicKind(operation))
|
||||||
|
|
||||||
private fun getMagicKind(operation: ControlFlowBuilder.PredefinedOperation) = when (operation) {
|
private fun getMagicKind(operation: ControlFlowBuilder.PredefinedOperation) = when (operation) {
|
||||||
ControlFlowBuilder.PredefinedOperation.AND -> MagicKind.AND
|
ControlFlowBuilder.PredefinedOperation.AND -> MagicKind.AND
|
||||||
@@ -403,17 +409,17 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun read(
|
override fun read(
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
target: AccessTarget,
|
target: AccessTarget,
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue>
|
receiverValues: Map<PseudoValue, ReceiverValue>
|
||||||
) = ReadValueInstruction(element, currentScope, target, receiverValues, valueFactory).apply {
|
) = ReadValueInstruction(element, currentScope, target, receiverValues, valueFactory).apply {
|
||||||
add(this)
|
add(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun read(
|
private fun read(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
resolvedCall: ResolvedCall<*>? = null,
|
resolvedCall: ResolvedCall<*>? = null,
|
||||||
receiverValues: Map<PseudoValue, ReceiverValue> = emptyMap()
|
receiverValues: Map<PseudoValue, ReceiverValue> = emptyMap()
|
||||||
) = read(expression, if (resolvedCall != null) AccessTarget.Call(resolvedCall) else AccessTarget.BlackBox, receiverValues)
|
) = read(expression, if (resolvedCall != null) AccessTarget.Call(resolvedCall) else AccessTarget.BlackBox, receiverValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -23,28 +23,28 @@ import org.jetbrains.kotlin.types.KotlinType
|
|||||||
import org.jetbrains.kotlin.types.TypeUtils
|
import org.jetbrains.kotlin.types.TypeUtils
|
||||||
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
|
||||||
|
|
||||||
interface TypePredicate: (KotlinType) -> Boolean {
|
interface TypePredicate : (KotlinType) -> Boolean {
|
||||||
override fun invoke(typeToCheck: KotlinType): Boolean
|
override fun invoke(typeToCheck: KotlinType): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
data class SingleType(val targetType: KotlinType): TypePredicate {
|
data class SingleType(val targetType: KotlinType) : TypePredicate {
|
||||||
override fun invoke(typeToCheck: KotlinType): Boolean = KotlinTypeChecker.DEFAULT.equalTypes(typeToCheck, targetType)
|
override fun invoke(typeToCheck: KotlinType): Boolean = KotlinTypeChecker.DEFAULT.equalTypes(typeToCheck, targetType)
|
||||||
override fun toString(): String = targetType.render()
|
override fun toString(): String = targetType.render()
|
||||||
}
|
}
|
||||||
|
|
||||||
data class AllSubtypes(val upperBound: KotlinType): TypePredicate {
|
data class AllSubtypes(val upperBound: KotlinType) : TypePredicate {
|
||||||
override fun invoke(typeToCheck: KotlinType): Boolean = KotlinTypeChecker.DEFAULT.isSubtypeOf(typeToCheck, upperBound)
|
override fun invoke(typeToCheck: KotlinType): Boolean = KotlinTypeChecker.DEFAULT.isSubtypeOf(typeToCheck, upperBound)
|
||||||
|
|
||||||
override fun toString(): String = "{<: ${upperBound.render()}}"
|
override fun toString(): String = "{<: ${upperBound.render()}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ForAllTypes(val typeSets: List<TypePredicate>): TypePredicate {
|
data class ForAllTypes(val typeSets: List<TypePredicate>) : TypePredicate {
|
||||||
override fun invoke(typeToCheck: KotlinType): Boolean = typeSets.all { it(typeToCheck) }
|
override fun invoke(typeToCheck: KotlinType): Boolean = typeSets.all { it(typeToCheck) }
|
||||||
|
|
||||||
override fun toString(): String = "AND{${typeSets.joinToString(", ")}}"
|
override fun toString(): String = "AND{${typeSets.joinToString(", ")}}"
|
||||||
}
|
}
|
||||||
|
|
||||||
data class ForSomeType(val typeSets: List<TypePredicate>): TypePredicate {
|
data class ForSomeType(val typeSets: List<TypePredicate>) : TypePredicate {
|
||||||
override fun invoke(typeToCheck: KotlinType): Boolean = typeSets.any { it(typeToCheck) }
|
override fun invoke(typeToCheck: KotlinType): Boolean = typeSets.any { it(typeToCheck) }
|
||||||
|
|
||||||
override fun toString(): String = "OR{${typeSets.joinToString(", ")}}"
|
override fun toString(): String = "OR{${typeSets.joinToString(", ")}}"
|
||||||
@@ -58,18 +58,18 @@ object AllTypes : TypePredicate {
|
|||||||
|
|
||||||
// todo: simplify computed type predicate when possible
|
// todo: simplify computed type predicate when possible
|
||||||
fun and(predicates: Collection<TypePredicate>): TypePredicate =
|
fun and(predicates: Collection<TypePredicate>): TypePredicate =
|
||||||
when (predicates.size) {
|
when (predicates.size) {
|
||||||
0 -> AllTypes
|
0 -> AllTypes
|
||||||
1 -> predicates.first()
|
1 -> predicates.first()
|
||||||
else -> ForAllTypes(predicates.toList())
|
else -> ForAllTypes(predicates.toList())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun or(predicates: Collection<TypePredicate>): TypePredicate? =
|
fun or(predicates: Collection<TypePredicate>): TypePredicate? =
|
||||||
when (predicates.size) {
|
when (predicates.size) {
|
||||||
0 -> null
|
0 -> null
|
||||||
1 -> predicates.first()
|
1 -> predicates.first()
|
||||||
else -> ForSomeType(predicates.toList())
|
else -> ForSomeType(predicates.toList())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KotlinType.getSubtypesPredicate(): TypePredicate = when {
|
fun KotlinType.getSubtypesPredicate(): TypePredicate = when {
|
||||||
KotlinBuiltIns.isAnyOrNullableAny(this) && isMarkedNullable -> AllTypes
|
KotlinBuiltIns.isAnyOrNullableAny(this) && isMarkedNullable -> AllTypes
|
||||||
@@ -81,4 +81,4 @@ fun KotlinType.getSubtypesPredicate(): TypePredicate = when {
|
|||||||
private fun KotlinType.render(): String = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(this)
|
private fun KotlinType.render(): String = DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(this)
|
||||||
|
|
||||||
fun <T> TypePredicate.expectedTypeFor(keys: Iterable<T>): Map<T, TypePredicate> =
|
fun <T> TypePredicate.expectedTypeFor(keys: Iterable<T>): Map<T, TypePredicate> =
|
||||||
keys.fold(SmartFMap.emptyMap<T, TypePredicate>()) { map, key -> map.plus(key, this) }
|
keys.fold(SmartFMap.emptyMap<T, TypePredicate>()) { map, key -> map.plus(key, this) }
|
||||||
|
|||||||
+3
-3
@@ -24,9 +24,9 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl
|
|||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.Instruction
|
||||||
|
|
||||||
abstract class AbstractJumpInstruction(
|
abstract class AbstractJumpInstruction(
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
val targetLabel: Label,
|
val targetLabel: Label,
|
||||||
blockScope: BlockScope
|
blockScope: BlockScope
|
||||||
) : KtElementInstructionImpl(element, blockScope), JumpInstruction {
|
) : KtElementInstructionImpl(element, blockScope), JumpInstruction {
|
||||||
var resolvedTarget: Instruction? = null
|
var resolvedTarget: Instruction? = null
|
||||||
set(value) {
|
set(value) {
|
||||||
|
|||||||
+6
-6
@@ -27,17 +27,17 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithRe
|
|||||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl
|
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl
|
||||||
|
|
||||||
class NondeterministicJumpInstruction(
|
class NondeterministicJumpInstruction(
|
||||||
element: KtElement,
|
element: KtElement,
|
||||||
targetLabels: List<Label>,
|
targetLabels: List<Label>,
|
||||||
blockScope: BlockScope,
|
blockScope: BlockScope,
|
||||||
private val inputValue: PseudoValue?
|
private val inputValue: PseudoValue?
|
||||||
) : KtElementInstructionImpl(element, blockScope), JumpInstruction {
|
) : KtElementInstructionImpl(element, blockScope), JumpInstruction {
|
||||||
private var _next: Instruction? = null
|
private var _next: Instruction? = null
|
||||||
private val _resolvedTargets: MutableMap<Label, Instruction> = linkedMapOf()
|
private val _resolvedTargets: MutableMap<Label, Instruction> = linkedMapOf()
|
||||||
|
|
||||||
val targetLabels: List<Label> = ArrayList(targetLabels)
|
val targetLabels: List<Label> = ArrayList(targetLabels)
|
||||||
private val resolvedTargets: Map<Label, Instruction>
|
private val resolvedTargets: Map<Label, Instruction>
|
||||||
get() = _resolvedTargets
|
get() = _resolvedTargets
|
||||||
|
|
||||||
fun setResolvedTarget(label: Label, resolvedTarget: Instruction) {
|
fun setResolvedTarget(label: Label, resolvedTarget: Instruction) {
|
||||||
_resolvedTargets[label] = outgoingEdgeTo(resolvedTarget)!!
|
_resolvedTargets[label] = outgoingEdgeTo(resolvedTarget)!!
|
||||||
@@ -76,5 +76,5 @@ class NondeterministicJumpInstruction(
|
|||||||
fun copy(newTargetLabels: MutableList<Label>): Instruction = updateCopyInfo(createCopy(newTargetLabels))
|
fun copy(newTargetLabels: MutableList<Label>): Instruction = updateCopyInfo(createCopy(newTargetLabels))
|
||||||
|
|
||||||
private fun createCopy(newTargetLabels: List<Label>): InstructionImpl =
|
private fun createCopy(newTargetLabels: List<Label>): InstructionImpl =
|
||||||
NondeterministicJumpInstruction(element, newTargetLabels, blockScope, inputValue)
|
NondeterministicJumpInstruction(element, newTargetLabels, blockScope, inputValue)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,8 @@ fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: Recei
|
|||||||
resolvedCall.dispatchReceiver -> {
|
resolvedCall.dispatchReceiver -> {
|
||||||
val rootCallableDescriptors = callableDescriptor.findTopMostOverriddenDescriptors()
|
val rootCallableDescriptors = callableDescriptor.findTopMostOverriddenDescriptors()
|
||||||
return or(rootCallableDescriptors.mapNotNull {
|
return or(rootCallableDescriptors.mapNotNull {
|
||||||
it.dispatchReceiverParameter?.type?.let { TypeUtils.makeNullableIfNeeded(it, resolvedCall.call.isSafeCall()) }?.getSubtypesPredicate()
|
it.dispatchReceiverParameter?.type?.let { TypeUtils.makeNullableIfNeeded(it, resolvedCall.call.isSafeCall()) }
|
||||||
|
?.getSubtypesPredicate()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -72,9 +73,9 @@ fun getReceiverTypePredicate(resolvedCall: ResolvedCall<*>, receiverValue: Recei
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getExpectedTypePredicate(
|
fun getExpectedTypePredicate(
|
||||||
value: PseudoValue,
|
value: PseudoValue,
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
builtIns: KotlinBuiltIns
|
builtIns: KotlinBuiltIns
|
||||||
): TypePredicate {
|
): TypePredicate {
|
||||||
val pseudocode = value.createdAt?.owner ?: return AllTypes
|
val pseudocode = value.createdAt?.owner ?: return AllTypes
|
||||||
val typePredicates = LinkedHashSet<TypePredicate?>()
|
val typePredicates = LinkedHashSet<TypePredicate?>()
|
||||||
@@ -92,8 +93,8 @@ fun getExpectedTypePredicate(
|
|||||||
val callee = call.calleeExpression ?: return null
|
val callee = call.calleeExpression ?: return null
|
||||||
|
|
||||||
val candidates = callee.getReferenceTargets(bindingContext)
|
val candidates = callee.getReferenceTargets(bindingContext)
|
||||||
.filterIsInstance<FunctionDescriptor>()
|
.filterIsInstance<FunctionDescriptor>()
|
||||||
.sortedBy { DescriptorRenderer.FQ_NAMES_IN_TYPES.render(it) }
|
.sortedBy { DescriptorRenderer.FQ_NAMES_IN_TYPES.render(it) }
|
||||||
if (candidates.isEmpty()) return null
|
if (candidates.isEmpty()) return null
|
||||||
|
|
||||||
val explicitReceiver = call.explicitReceiver
|
val explicitReceiver = call.explicitReceiver
|
||||||
@@ -103,17 +104,17 @@ fun getExpectedTypePredicate(
|
|||||||
|
|
||||||
for (candidate in candidates) {
|
for (candidate in candidates) {
|
||||||
val resolutionCandidate = ResolutionCandidate.create(
|
val resolutionCandidate = ResolutionCandidate.create(
|
||||||
call,
|
call,
|
||||||
candidate,
|
candidate,
|
||||||
null,
|
null,
|
||||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
||||||
null
|
null
|
||||||
)
|
)
|
||||||
val candidateCall = ResolvedCallImpl.create(
|
val candidateCall = ResolvedCallImpl.create(
|
||||||
resolutionCandidate,
|
resolutionCandidate,
|
||||||
DelegatingBindingTrace(bindingContext, "Compute type predicates for unresolved call arguments"),
|
DelegatingBindingTrace(bindingContext, "Compute type predicates for unresolved call arguments"),
|
||||||
TracingStrategy.EMPTY,
|
TracingStrategy.EMPTY,
|
||||||
DataFlowInfoForArgumentsImpl(DataFlowInfo.EMPTY, call)
|
DataFlowInfoForArgumentsImpl(DataFlowInfo.EMPTY, call)
|
||||||
)
|
)
|
||||||
val status = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(call, TracingStrategy.EMPTY, candidateCall)
|
val status = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(call, TracingStrategy.EMPTY, candidateCall)
|
||||||
if (!status.isSuccess) continue
|
if (!status.isSuccess) continue
|
||||||
@@ -143,7 +144,7 @@ fun getExpectedTypePredicate(
|
|||||||
when (it) {
|
when (it) {
|
||||||
is ReturnValueInstruction -> {
|
is ReturnValueInstruction -> {
|
||||||
val returnElement = it.element
|
val returnElement = it.element
|
||||||
val functionDescriptor = when(returnElement) {
|
val functionDescriptor = when (returnElement) {
|
||||||
is KtReturnExpression -> returnElement.getTargetFunctionDescriptor(bindingContext)
|
is KtReturnExpression -> returnElement.getTargetFunctionDescriptor(bindingContext)
|
||||||
else -> bindingContext[DECLARATION_TO_DESCRIPTOR, pseudocode.correspondingElement]
|
else -> bindingContext[DECLARATION_TO_DESCRIPTOR, pseudocode.correspondingElement]
|
||||||
}
|
}
|
||||||
@@ -164,8 +165,7 @@ fun getExpectedTypePredicate(
|
|||||||
val receiverValue = it.receiverValues[value]
|
val receiverValue = it.receiverValues[value]
|
||||||
if (receiverValue != null) {
|
if (receiverValue != null) {
|
||||||
typePredicates.add(getReceiverTypePredicate((accessTarget as AccessTarget.Call).resolvedCall, receiverValue))
|
typePredicates.add(getReceiverTypePredicate((accessTarget as AccessTarget.Call).resolvedCall, receiverValue))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val expectedType = when (accessTarget) {
|
val expectedType = when (accessTarget) {
|
||||||
is AccessTarget.Call ->
|
is AccessTarget.Call ->
|
||||||
(accessTarget.resolvedCall.resultingDescriptor as? VariableDescriptor)?.type
|
(accessTarget.resolvedCall.resultingDescriptor as? VariableDescriptor)?.type
|
||||||
@@ -182,8 +182,7 @@ fun getExpectedTypePredicate(
|
|||||||
val receiverValue = it.receiverValues[value]
|
val receiverValue = it.receiverValues[value]
|
||||||
if (receiverValue != null) {
|
if (receiverValue != null) {
|
||||||
typePredicates.add(getReceiverTypePredicate(it.resolvedCall, receiverValue))
|
typePredicates.add(getReceiverTypePredicate(it.resolvedCall, receiverValue))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
it.arguments[value]?.let { parameter ->
|
it.arguments[value]?.let { parameter ->
|
||||||
val expectedType = when (it.resolvedCall.valueArguments[parameter]) {
|
val expectedType = when (it.resolvedCall.valueArguments[parameter]) {
|
||||||
is VarargValueArgument ->
|
is VarargValueArgument ->
|
||||||
@@ -281,8 +280,8 @@ fun Pseudocode.getElementValuesRecursively(element: KtElement): List<PseudoValue
|
|||||||
}
|
}
|
||||||
|
|
||||||
val KtElement.containingDeclarationForPseudocode: KtDeclaration?
|
val KtElement.containingDeclarationForPseudocode: KtDeclaration?
|
||||||
get() = PsiTreeUtil.getParentOfType(this, KtDeclarationWithBody::class.java, KtClassOrObject::class.java, KtScript::class.java)
|
get() = PsiTreeUtil.getParentOfType(this, KtDeclarationWithBody::class.java, KtClassOrObject::class.java, KtScript::class.java)
|
||||||
?: getNonStrictParentOfType<KtProperty>()
|
?: getNonStrictParentOfType<KtProperty>()
|
||||||
|
|
||||||
fun KtDeclaration.getContainingPseudocode(context: BindingContext): Pseudocode? {
|
fun KtDeclaration.getContainingPseudocode(context: BindingContext): Pseudocode? {
|
||||||
val enclosingPseudocodeDeclaration = (this as? KtFunctionLiteral)?.let {
|
val enclosingPseudocodeDeclaration = (this as? KtFunctionLiteral)?.let {
|
||||||
|
|||||||
+9
-9
@@ -44,9 +44,9 @@ class ContractParsingServices(val languageVersionSettings: LanguageVersionSettin
|
|||||||
val contractProvider = ownerDescriptor.getUserData(ContractProviderKey) ?: return
|
val contractProvider = ownerDescriptor.getUserData(ContractProviderKey) ?: return
|
||||||
|
|
||||||
val isFeatureTurnedOn = languageVersionSettings.supportsFeature(LanguageFeature.CallsInPlaceEffect) ||
|
val isFeatureTurnedOn = languageVersionSettings.supportsFeature(LanguageFeature.CallsInPlaceEffect) ||
|
||||||
languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect) ||
|
languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect) ||
|
||||||
// This condition is here for technical purposes of compiling 1.2-runtime with contracts
|
// This condition is here for technical purposes of compiling 1.2-runtime with contracts
|
||||||
languageVersionSettings.getFlag(AnalysisFlag.Flags.allowKotlinPackage)
|
languageVersionSettings.getFlag(AnalysisFlag.Flags.allowKotlinPackage)
|
||||||
|
|
||||||
val contractDescriptor = when {
|
val contractDescriptor = when {
|
||||||
!isFeatureTurnedOn || !isContractDescriptionCallPreciseCheck(expression, trace.bindingContext) -> null
|
!isFeatureTurnedOn || !isContractDescriptionCallPreciseCheck(expression, trace.bindingContext) -> null
|
||||||
@@ -63,20 +63,20 @@ class ContractParsingServices(val languageVersionSettings: LanguageVersionSettin
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun parseContract(expression: KtExpression?, trace: BindingTrace, ownerDescriptor: FunctionDescriptor): ContractDescription? =
|
private fun parseContract(expression: KtExpression?, trace: BindingTrace, ownerDescriptor: FunctionDescriptor): ContractDescription? =
|
||||||
PsiContractParserDispatcher(trace, this).parseContract(expression, ownerDescriptor)
|
PsiContractParserDispatcher(trace, this).parseContract(expression, ownerDescriptor)
|
||||||
|
|
||||||
internal fun isContractDescriptionCall(expression: KtExpression, context: BindingContext): Boolean =
|
internal fun isContractDescriptionCall(expression: KtExpression, context: BindingContext): Boolean =
|
||||||
isContractDescriptionCallFastCheck(expression) && isContractDescriptionCallPreciseCheck(expression, context)
|
isContractDescriptionCallFastCheck(expression) && isContractDescriptionCallPreciseCheck(expression, context)
|
||||||
|
|
||||||
private fun isContractAllowedHere(element: KtElement): Boolean =
|
private fun isContractAllowedHere(element: KtElement): Boolean =
|
||||||
element is KtNamedFunction && element.isTopLevel && element.hasBlockBody() && !element.hasModifier(KtTokens.OPERATOR_KEYWORD)
|
element is KtNamedFunction && element.isTopLevel && element.hasBlockBody() && !element.hasModifier(KtTokens.OPERATOR_KEYWORD)
|
||||||
|
|
||||||
private fun isContractAllowedHere(scope: LexicalScope): Boolean =
|
private fun isContractAllowedHere(scope: LexicalScope): Boolean =
|
||||||
scope.kind == LexicalScopeKind.CODE_BLOCK && (scope.parent as? LexicalScope)?.kind == LexicalScopeKind.FUNCTION_INNER_SCOPE
|
scope.kind == LexicalScopeKind.CODE_BLOCK && (scope.parent as? LexicalScope)?.kind == LexicalScopeKind.FUNCTION_INNER_SCOPE
|
||||||
|
|
||||||
private fun isContractDescriptionCallFastCheck(expression: KtExpression): Boolean =
|
private fun isContractDescriptionCallFastCheck(expression: KtExpression): Boolean =
|
||||||
expression is KtCallExpression && expression.calleeExpression?.text == "contract"
|
expression is KtCallExpression && expression.calleeExpression?.text == "contract"
|
||||||
|
|
||||||
private fun isContractDescriptionCallPreciseCheck(expression: KtExpression, context: BindingContext): Boolean =
|
private fun isContractDescriptionCallPreciseCheck(expression: KtExpression, context: BindingContext): Boolean =
|
||||||
expression.getResolvedCall(context)?.resultingDescriptor?.isContractCallDescriptor() ?: false
|
expression.getResolvedCall(context)?.resultingDescriptor?.isContractCallDescriptor() ?: false
|
||||||
}
|
}
|
||||||
@@ -27,7 +27,8 @@ import org.jetbrains.kotlin.resolve.BindingTrace
|
|||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||||
|
|
||||||
internal class PsiConditionParser(val trace: BindingTrace, val dispatcher: PsiContractParserDispatcher) : KtVisitor<BooleanExpression?, Unit>() {
|
internal class PsiConditionParser(val trace: BindingTrace, val dispatcher: PsiContractParserDispatcher) :
|
||||||
|
KtVisitor<BooleanExpression?, Unit>() {
|
||||||
override fun visitIsExpression(expression: KtIsExpression, data: Unit): BooleanExpression? {
|
override fun visitIsExpression(expression: KtIsExpression, data: Unit): BooleanExpression? {
|
||||||
val variable = dispatcher.parseVariable(expression.leftHandSide) ?: return null
|
val variable = dispatcher.parseVariable(expression.leftHandSide) ?: return null
|
||||||
val typeReference = expression.typeReference ?: return null
|
val typeReference = expression.typeReference ?: return null
|
||||||
@@ -101,11 +102,16 @@ internal class PsiConditionParser(val trace: BindingTrace, val dispatcher: PsiCo
|
|||||||
if (expression.operationToken != KtTokens.EXCL) return super.visitUnaryExpression(expression, data)
|
if (expression.operationToken != KtTokens.EXCL) return super.visitUnaryExpression(expression, data)
|
||||||
val arg = expression.baseExpression?.accept(this, data) ?: return null
|
val arg = expression.baseExpression?.accept(this, data) ?: return null
|
||||||
if (arg !is ContractDescriptionValue) {
|
if (arg !is ContractDescriptionValue) {
|
||||||
trace.report(Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(expression.baseExpression!!, "negations in contract description can be applied only to variables/values"))
|
trace.report(
|
||||||
|
Errors.ERROR_IN_CONTRACT_DESCRIPTION.on(
|
||||||
|
expression.baseExpression!!,
|
||||||
|
"negations in contract description can be applied only to variables/values"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return LogicalNot(arg)
|
return LogicalNot(arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitParenthesizedExpression(expression: KtParenthesizedExpression, data: Unit): BooleanExpression? =
|
override fun visitParenthesizedExpression(expression: KtParenthesizedExpression, data: Unit): BooleanExpression? =
|
||||||
KtPsiUtil.deparenthesize(expression)?.accept(this, data)
|
KtPsiUtil.deparenthesize(expression)?.accept(this, data)
|
||||||
}
|
}
|
||||||
@@ -24,4 +24,5 @@ internal interface PsiEffectParser {
|
|||||||
fun tryParseEffect(expression: KtExpression): EffectDeclaration?
|
fun tryParseEffect(expression: KtExpression): EffectDeclaration?
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class AbstractPsiEffectParser(val trace: BindingTrace, val contractParserDispatcher: PsiContractParserDispatcher) : PsiEffectParser
|
internal abstract class AbstractPsiEffectParser(val trace: BindingTrace, val contractParserDispatcher: PsiContractParserDispatcher) :
|
||||||
|
PsiEffectParser
|
||||||
|
|||||||
@@ -47,7 +47,8 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val DEFAULT: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
@JvmField
|
||||||
|
val DEFAULT: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
||||||
override fun mark(element: PsiElement): List<TextRange> {
|
override fun mark(element: PsiElement): List<TextRange> {
|
||||||
when (element) {
|
when (element) {
|
||||||
is KtObjectLiteralExpression -> {
|
is KtObjectLiteralExpression -> {
|
||||||
@@ -61,8 +62,8 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
is KtObjectDeclaration -> {
|
is KtObjectDeclaration -> {
|
||||||
return markRange(
|
return markRange(
|
||||||
element.getObjectKeyword()!!,
|
element.getObjectKeyword()!!,
|
||||||
element.nameIdentifier ?: element.getObjectKeyword()!!
|
element.nameIdentifier ?: element.getObjectKeyword()!!
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
is KtConstructorDelegationCall -> {
|
is KtConstructorDelegationCall -> {
|
||||||
@@ -75,7 +76,8 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val DECLARATION_RETURN_TYPE: PositioningStrategy<KtDeclaration> = object : PositioningStrategy<KtDeclaration>() {
|
@JvmField
|
||||||
|
val DECLARATION_RETURN_TYPE: PositioningStrategy<KtDeclaration> = object : PositioningStrategy<KtDeclaration>() {
|
||||||
override fun mark(element: KtDeclaration): List<TextRange> {
|
override fun mark(element: KtDeclaration): List<TextRange> {
|
||||||
return markElement(getElementToMark(element))
|
return markElement(getElementToMark(element))
|
||||||
}
|
}
|
||||||
@@ -97,7 +99,8 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val ACTUAL_DECLARATION_NAME: PositioningStrategy<KtNamedDeclaration> = object : DeclarationHeader<KtNamedDeclaration>() {
|
@JvmField
|
||||||
|
val ACTUAL_DECLARATION_NAME: PositioningStrategy<KtNamedDeclaration> = object : DeclarationHeader<KtNamedDeclaration>() {
|
||||||
override fun mark(element: KtNamedDeclaration): List<TextRange> {
|
override fun mark(element: KtNamedDeclaration): List<TextRange> {
|
||||||
val nameIdentifier = element.nameIdentifier
|
val nameIdentifier = element.nameIdentifier
|
||||||
return when {
|
return when {
|
||||||
@@ -112,11 +115,11 @@ object PositioningStrategies {
|
|||||||
get() {
|
get() {
|
||||||
val map = when (factory) {
|
val map = when (factory) {
|
||||||
NO_ACTUAL_FOR_EXPECT ->
|
NO_ACTUAL_FOR_EXPECT ->
|
||||||
NO_ACTUAL_FOR_EXPECT.cast(this).c
|
NO_ACTUAL_FOR_EXPECT.cast(this).c
|
||||||
ACTUAL_WITHOUT_EXPECT ->
|
ACTUAL_WITHOUT_EXPECT ->
|
||||||
ACTUAL_WITHOUT_EXPECT.cast(this).b
|
ACTUAL_WITHOUT_EXPECT.cast(this).b
|
||||||
else ->
|
else ->
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return map.keys.firstOrNull()
|
return map.keys.firstOrNull()
|
||||||
}
|
}
|
||||||
@@ -125,7 +128,8 @@ object PositioningStrategies {
|
|||||||
|
|
||||||
private val classKindTokens = TokenSet.create(KtTokens.CLASS_KEYWORD, KtTokens.OBJECT_KEYWORD, KtTokens.INTERFACE_KEYWORD)
|
private val classKindTokens = TokenSet.create(KtTokens.CLASS_KEYWORD, KtTokens.OBJECT_KEYWORD, KtTokens.INTERFACE_KEYWORD)
|
||||||
|
|
||||||
@JvmField val INCOMPATIBLE_DECLARATION: PositioningStrategy<KtNamedDeclaration> = object : DeclarationHeader<KtNamedDeclaration>() {
|
@JvmField
|
||||||
|
val INCOMPATIBLE_DECLARATION: PositioningStrategy<KtNamedDeclaration> = object : DeclarationHeader<KtNamedDeclaration>() {
|
||||||
override fun markDiagnostic(diagnostic: ParametrizedDiagnostic<out KtNamedDeclaration>): List<TextRange> {
|
override fun markDiagnostic(diagnostic: ParametrizedDiagnostic<out KtNamedDeclaration>): List<TextRange> {
|
||||||
val element = diagnostic.psiElement
|
val element = diagnostic.psiElement
|
||||||
val callableDeclaration = element as? KtCallableDeclaration
|
val callableDeclaration = element as? KtCallableDeclaration
|
||||||
@@ -134,15 +138,14 @@ object PositioningStrategies {
|
|||||||
null, Unknown, is ClassScopes, EnumEntries -> null
|
null, Unknown, is ClassScopes, EnumEntries -> null
|
||||||
ClassKind -> {
|
ClassKind -> {
|
||||||
val startElement =
|
val startElement =
|
||||||
element.modifierList?.getModifier(KtTokens.ENUM_KEYWORD)
|
element.modifierList?.getModifier(KtTokens.ENUM_KEYWORD)
|
||||||
?: element.modifierList?.getModifier(KtTokens.ANNOTATION_KEYWORD)
|
?: element.modifierList?.getModifier(KtTokens.ANNOTATION_KEYWORD)
|
||||||
val endElement =
|
val endElement =
|
||||||
element.node.findChildByType(classKindTokens)?.psi
|
element.node.findChildByType(classKindTokens)?.psi
|
||||||
?: element.nameIdentifier
|
?: element.nameIdentifier
|
||||||
if (startElement != null && endElement != null) {
|
if (startElement != null && endElement != null) {
|
||||||
return markRange(startElement, endElement)
|
return markRange(startElement, endElement)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
endElement
|
endElement
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -181,15 +184,16 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val DECLARATION_NAME: PositioningStrategy<KtNamedDeclaration> = object : DeclarationHeader<KtNamedDeclaration>() {
|
@JvmField
|
||||||
|
val DECLARATION_NAME: PositioningStrategy<KtNamedDeclaration> = object : DeclarationHeader<KtNamedDeclaration>() {
|
||||||
override fun mark(element: KtNamedDeclaration): List<TextRange> {
|
override fun mark(element: KtNamedDeclaration): List<TextRange> {
|
||||||
val nameIdentifier = element.nameIdentifier
|
val nameIdentifier = element.nameIdentifier
|
||||||
if (nameIdentifier != null) {
|
if (nameIdentifier != null) {
|
||||||
if (element is KtClassOrObject) {
|
if (element is KtClassOrObject) {
|
||||||
val startElement =
|
val startElement =
|
||||||
element.getModifierList()?.getModifier(KtTokens.ENUM_KEYWORD)
|
element.getModifierList()?.getModifier(KtTokens.ENUM_KEYWORD)
|
||||||
?: element.node.findChildByType(TokenSet.create(KtTokens.CLASS_KEYWORD, KtTokens.OBJECT_KEYWORD))?.psi
|
?: element.node.findChildByType(TokenSet.create(KtTokens.CLASS_KEYWORD, KtTokens.OBJECT_KEYWORD))?.psi
|
||||||
?: element
|
?: element
|
||||||
|
|
||||||
return markRange(startElement, nameIdentifier)
|
return markRange(startElement, nameIdentifier)
|
||||||
}
|
}
|
||||||
@@ -202,7 +206,8 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val DECLARATION_SIGNATURE: PositioningStrategy<KtDeclaration> = object : DeclarationHeader<KtDeclaration>() {
|
@JvmField
|
||||||
|
val DECLARATION_SIGNATURE: PositioningStrategy<KtDeclaration> = object : DeclarationHeader<KtDeclaration>() {
|
||||||
override fun mark(element: KtDeclaration): List<TextRange> {
|
override fun mark(element: KtDeclaration): List<TextRange> {
|
||||||
when (element) {
|
when (element) {
|
||||||
is KtConstructor<*> -> {
|
is KtConstructor<*> -> {
|
||||||
@@ -212,17 +217,15 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
is KtFunction -> {
|
is KtFunction -> {
|
||||||
val endOfSignatureElement =
|
val endOfSignatureElement =
|
||||||
element.typeReference
|
element.typeReference
|
||||||
?: element.valueParameterList
|
?: element.valueParameterList
|
||||||
?: element.nameIdentifier
|
?: element.nameIdentifier
|
||||||
?: element
|
?: element
|
||||||
val startElement
|
val startElement = if (element is KtFunctionLiteral) {
|
||||||
= if (element is KtFunctionLiteral) {
|
element.getReceiverTypeReference()
|
||||||
element.getReceiverTypeReference()
|
|
||||||
?: element.getValueParameterList()
|
?: element.getValueParameterList()
|
||||||
?: element
|
?: element
|
||||||
}
|
} else element
|
||||||
else element
|
|
||||||
return markRange(startElement, endOfSignatureElement)
|
return markRange(startElement, endOfSignatureElement)
|
||||||
}
|
}
|
||||||
is KtProperty -> {
|
is KtProperty -> {
|
||||||
@@ -231,15 +234,16 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
is KtPropertyAccessor -> {
|
is KtPropertyAccessor -> {
|
||||||
val endOfSignatureElement =
|
val endOfSignatureElement =
|
||||||
element.returnTypeReference
|
element.returnTypeReference
|
||||||
?: element.rightParenthesis?.psi
|
?: element.rightParenthesis?.psi
|
||||||
?: element.namePlaceholder
|
?: element.namePlaceholder
|
||||||
|
|
||||||
return markRange(element, endOfSignatureElement)
|
return markRange(element, endOfSignatureElement)
|
||||||
}
|
}
|
||||||
is KtClass -> {
|
is KtClass -> {
|
||||||
val nameAsDeclaration = element.nameIdentifier ?: return markElement(element)
|
val nameAsDeclaration = element.nameIdentifier ?: return markElement(element)
|
||||||
val primaryConstructorParameterList = element.getPrimaryConstructorParameterList() ?: return markElement(nameAsDeclaration)
|
val primaryConstructorParameterList =
|
||||||
|
element.getPrimaryConstructorParameterList() ?: return markElement(nameAsDeclaration)
|
||||||
return markRange(nameAsDeclaration, primaryConstructorParameterList)
|
return markRange(nameAsDeclaration, primaryConstructorParameterList)
|
||||||
}
|
}
|
||||||
is KtObjectDeclaration -> {
|
is KtObjectDeclaration -> {
|
||||||
@@ -253,7 +257,8 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val DECLARATION_SIGNATURE_OR_DEFAULT: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
@JvmField
|
||||||
|
val DECLARATION_SIGNATURE_OR_DEFAULT: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
||||||
override fun mark(element: PsiElement): List<TextRange> {
|
override fun mark(element: PsiElement): List<TextRange> {
|
||||||
return if (element is KtDeclaration)
|
return if (element is KtDeclaration)
|
||||||
DECLARATION_SIGNATURE.mark(element)
|
DECLARATION_SIGNATURE.mark(element)
|
||||||
@@ -269,26 +274,24 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val NOT_SUPPORTED_IN_INLINE_MOST_RELEVANT: PositioningStrategy<KtDeclaration> = object : PositioningStrategy<KtDeclaration>() {
|
@JvmField
|
||||||
|
val NOT_SUPPORTED_IN_INLINE_MOST_RELEVANT: PositioningStrategy<KtDeclaration> = object : PositioningStrategy<KtDeclaration>() {
|
||||||
override fun mark(element: KtDeclaration): List<TextRange> =
|
override fun mark(element: KtDeclaration): List<TextRange> =
|
||||||
markElement(
|
markElement(
|
||||||
when (element) {
|
when (element) {
|
||||||
is KtClassOrObject ->
|
is KtClassOrObject ->
|
||||||
element.getDeclarationKeyword() ?:
|
element.getDeclarationKeyword() ?: element.nameIdentifier ?: element
|
||||||
element.nameIdentifier ?:
|
|
||||||
element
|
|
||||||
|
|
||||||
is KtNamedFunction ->
|
is KtNamedFunction ->
|
||||||
element.modifierList?.getModifier(KtTokens.INLINE_KEYWORD) ?:
|
element.modifierList?.getModifier(KtTokens.INLINE_KEYWORD) ?: element.funKeyword ?: element
|
||||||
element.funKeyword ?:
|
|
||||||
element
|
|
||||||
|
|
||||||
else -> element
|
else -> element
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val TYPE_PARAMETERS_OR_DECLARATION_SIGNATURE: PositioningStrategy<KtDeclaration> = object : PositioningStrategy<KtDeclaration>() {
|
@JvmField
|
||||||
|
val TYPE_PARAMETERS_OR_DECLARATION_SIGNATURE: PositioningStrategy<KtDeclaration> = object : PositioningStrategy<KtDeclaration>() {
|
||||||
override fun mark(element: KtDeclaration): List<TextRange> {
|
override fun mark(element: KtDeclaration): List<TextRange> {
|
||||||
if (element is KtTypeParameterListOwner) {
|
if (element is KtTypeParameterListOwner) {
|
||||||
val jetTypeParameterList = element.typeParameterList
|
val jetTypeParameterList = element.typeParameterList
|
||||||
@@ -300,19 +303,26 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val ABSTRACT_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.ABSTRACT_KEYWORD)
|
@JvmField
|
||||||
|
val ABSTRACT_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.ABSTRACT_KEYWORD)
|
||||||
|
|
||||||
@JvmField val OPEN_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.OPEN_KEYWORD)
|
@JvmField
|
||||||
|
val OPEN_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.OPEN_KEYWORD)
|
||||||
|
|
||||||
@JvmField val OVERRIDE_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.OVERRIDE_KEYWORD)
|
@JvmField
|
||||||
|
val OVERRIDE_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.OVERRIDE_KEYWORD)
|
||||||
|
|
||||||
@JvmField val PRIVATE_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.PRIVATE_KEYWORD)
|
@JvmField
|
||||||
|
val PRIVATE_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.PRIVATE_KEYWORD)
|
||||||
|
|
||||||
@JvmField val LATEINIT_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.LATEINIT_KEYWORD)
|
@JvmField
|
||||||
|
val LATEINIT_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.LATEINIT_KEYWORD)
|
||||||
|
|
||||||
@JvmField val VARIANCE_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.IN_KEYWORD, KtTokens.OUT_KEYWORD)
|
@JvmField
|
||||||
|
val VARIANCE_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.IN_KEYWORD, KtTokens.OUT_KEYWORD)
|
||||||
|
|
||||||
@JvmField val FOR_REDECLARATION: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
@JvmField
|
||||||
|
val FOR_REDECLARATION: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
||||||
override fun mark(element: PsiElement): List<TextRange> {
|
override fun mark(element: PsiElement): List<TextRange> {
|
||||||
val nameIdentifier = when (element) {
|
val nameIdentifier = when (element) {
|
||||||
is KtNamedDeclaration -> element.nameIdentifier
|
is KtNamedDeclaration -> element.nameIdentifier
|
||||||
@@ -325,7 +335,8 @@ object PositioningStrategies {
|
|||||||
return markElement(nameIdentifier ?: element)
|
return markElement(nameIdentifier ?: element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@JvmField val FOR_UNRESOLVED_REFERENCE: PositioningStrategy<KtReferenceExpression> = object : PositioningStrategy<KtReferenceExpression>() {
|
@JvmField
|
||||||
|
val FOR_UNRESOLVED_REFERENCE: PositioningStrategy<KtReferenceExpression> = object : PositioningStrategy<KtReferenceExpression>() {
|
||||||
override fun mark(element: KtReferenceExpression): List<TextRange> {
|
override fun mark(element: KtReferenceExpression): List<TextRange> {
|
||||||
if (element is KtArrayAccessExpression) {
|
if (element is KtArrayAccessExpression) {
|
||||||
val ranges = element.bracketRanges
|
val ranges = element.bracketRanges
|
||||||
@@ -337,7 +348,8 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun modifierSetPosition(vararg tokens: KtModifierKeywordToken): PositioningStrategy<KtModifierListOwner> {
|
@JvmStatic
|
||||||
|
fun modifierSetPosition(vararg tokens: KtModifierKeywordToken): PositioningStrategy<KtModifierListOwner> {
|
||||||
return object : PositioningStrategy<KtModifierListOwner>() {
|
return object : PositioningStrategy<KtModifierListOwner>() {
|
||||||
override fun mark(element: KtModifierListOwner): List<TextRange> {
|
override fun mark(element: KtModifierListOwner): List<TextRange> {
|
||||||
val modifierList = element.modifierList.sure { "No modifier list, but modifier has been found by the analyzer" }
|
val modifierList = element.modifierList.sure { "No modifier list, but modifier has been found by the analyzer" }
|
||||||
@@ -353,15 +365,18 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val ARRAY_ACCESS: PositioningStrategy<KtArrayAccessExpression> = object : PositioningStrategy<KtArrayAccessExpression>() {
|
@JvmField
|
||||||
|
val ARRAY_ACCESS: PositioningStrategy<KtArrayAccessExpression> = object : PositioningStrategy<KtArrayAccessExpression>() {
|
||||||
override fun mark(element: KtArrayAccessExpression): List<TextRange> {
|
override fun mark(element: KtArrayAccessExpression): List<TextRange> {
|
||||||
return markElement(element.indicesNode)
|
return markElement(element.indicesNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val VISIBILITY_MODIFIER: PositioningStrategy<KtModifierListOwner> = object : PositioningStrategy<KtModifierListOwner>() {
|
@JvmField
|
||||||
|
val VISIBILITY_MODIFIER: PositioningStrategy<KtModifierListOwner> = object : PositioningStrategy<KtModifierListOwner>() {
|
||||||
override fun mark(element: KtModifierListOwner): List<TextRange> {
|
override fun mark(element: KtModifierListOwner): List<TextRange> {
|
||||||
val visibilityTokens = listOf(KtTokens.PRIVATE_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.PUBLIC_KEYWORD, KtTokens.INTERNAL_KEYWORD)
|
val visibilityTokens =
|
||||||
|
listOf(KtTokens.PRIVATE_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.PUBLIC_KEYWORD, KtTokens.INTERNAL_KEYWORD)
|
||||||
val modifierList = element.modifierList
|
val modifierList = element.modifierList
|
||||||
|
|
||||||
val result = visibilityTokens.mapNotNull { modifierList?.getModifier(it)?.textRange }
|
val result = visibilityTokens.mapNotNull { modifierList?.getModifier(it)?.textRange }
|
||||||
@@ -380,38 +395,44 @@ object PositioningStrategies {
|
|||||||
is KtPropertyAccessor -> element.namePlaceholder
|
is KtPropertyAccessor -> element.namePlaceholder
|
||||||
is KtAnonymousInitializer -> element
|
is KtAnonymousInitializer -> element
|
||||||
else -> throw IllegalArgumentException(
|
else -> throw IllegalArgumentException(
|
||||||
"Can't find text range for element '${element::class.java.canonicalName}' with the text '${element.text}'")
|
"Can't find text range for element '${element::class.java.canonicalName}' with the text '${element.text}'"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return markElement(elementToMark)
|
return markElement(elementToMark)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val VARIANCE_IN_PROJECTION: PositioningStrategy<KtTypeProjection> = object : PositioningStrategy<KtTypeProjection>() {
|
@JvmField
|
||||||
|
val VARIANCE_IN_PROJECTION: PositioningStrategy<KtTypeProjection> = object : PositioningStrategy<KtTypeProjection>() {
|
||||||
override fun mark(element: KtTypeProjection): List<TextRange> {
|
override fun mark(element: KtTypeProjection): List<TextRange> {
|
||||||
return markElement(element.projectionToken!!)
|
return markElement(element.projectionToken!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val PARAMETER_DEFAULT_VALUE: PositioningStrategy<KtParameter> = object : PositioningStrategy<KtParameter>() {
|
@JvmField
|
||||||
|
val PARAMETER_DEFAULT_VALUE: PositioningStrategy<KtParameter> = object : PositioningStrategy<KtParameter>() {
|
||||||
override fun mark(element: KtParameter): List<TextRange> {
|
override fun mark(element: KtParameter): List<TextRange> {
|
||||||
return markNode(element.defaultValue!!.node)
|
return markNode(element.defaultValue!!.node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val PARAMETER_VARARG_MODIFIER: PositioningStrategy<KtParameter> = object : PositioningStrategy<KtParameter>() {
|
@JvmField
|
||||||
|
val PARAMETER_VARARG_MODIFIER: PositioningStrategy<KtParameter> = object : PositioningStrategy<KtParameter>() {
|
||||||
override fun mark(element: KtParameter): List<TextRange> {
|
override fun mark(element: KtParameter): List<TextRange> {
|
||||||
val varargModifier = element.modifierList!!.getModifier(KtTokens.VARARG_KEYWORD)!!
|
val varargModifier = element.modifierList!!.getModifier(KtTokens.VARARG_KEYWORD)!!
|
||||||
return markNode(varargModifier.node)
|
return markNode(varargModifier.node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val CALL_ELEMENT: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
@JvmField
|
||||||
|
val CALL_ELEMENT: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
||||||
override fun mark(element: PsiElement): List<TextRange> {
|
override fun mark(element: PsiElement): List<TextRange> {
|
||||||
return markElement((element as? KtCallElement)?.calleeExpression ?: element)
|
return markElement((element as? KtCallElement)?.calleeExpression ?: element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val DECLARATION_WITH_BODY: PositioningStrategy<KtDeclarationWithBody> = object : PositioningStrategy<KtDeclarationWithBody>() {
|
@JvmField
|
||||||
|
val DECLARATION_WITH_BODY: PositioningStrategy<KtDeclarationWithBody> = object : PositioningStrategy<KtDeclarationWithBody>() {
|
||||||
override fun mark(element: KtDeclarationWithBody): List<TextRange> {
|
override fun mark(element: KtDeclarationWithBody): List<TextRange> {
|
||||||
val lastBracketRange = (element.bodyExpression as? KtBlockExpression)?.lastBracketRange
|
val lastBracketRange = (element.bodyExpression as? KtBlockExpression)?.lastBracketRange
|
||||||
return if (lastBracketRange != null)
|
return if (lastBracketRange != null)
|
||||||
@@ -425,7 +446,8 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val VAL_OR_VAR_NODE: PositioningStrategy<KtNamedDeclaration> = object : PositioningStrategy<KtNamedDeclaration>() {
|
@JvmField
|
||||||
|
val VAL_OR_VAR_NODE: PositioningStrategy<KtNamedDeclaration> = object : PositioningStrategy<KtNamedDeclaration>() {
|
||||||
override fun mark(element: KtNamedDeclaration): List<TextRange> {
|
override fun mark(element: KtNamedDeclaration): List<TextRange> {
|
||||||
return when (element) {
|
return when (element) {
|
||||||
is KtParameter -> markElement(element.valOrVarKeyword ?: element)
|
is KtParameter -> markElement(element.valOrVarKeyword ?: element)
|
||||||
@@ -435,41 +457,47 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val ELSE_ENTRY: PositioningStrategy<KtWhenEntry> = object : PositioningStrategy<KtWhenEntry>() {
|
@JvmField
|
||||||
|
val ELSE_ENTRY: PositioningStrategy<KtWhenEntry> = object : PositioningStrategy<KtWhenEntry>() {
|
||||||
override fun mark(element: KtWhenEntry): List<TextRange> {
|
override fun mark(element: KtWhenEntry): List<TextRange> {
|
||||||
return markElement(element.elseKeyword!!)
|
return markElement(element.elseKeyword!!)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val WHEN_EXPRESSION: PositioningStrategy<KtWhenExpression> = object : PositioningStrategy<KtWhenExpression>() {
|
@JvmField
|
||||||
|
val WHEN_EXPRESSION: PositioningStrategy<KtWhenExpression> = object : PositioningStrategy<KtWhenExpression>() {
|
||||||
override fun mark(element: KtWhenExpression): List<TextRange> {
|
override fun mark(element: KtWhenExpression): List<TextRange> {
|
||||||
return markElement(element.whenKeyword)
|
return markElement(element.whenKeyword)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val WHEN_CONDITION_IN_RANGE: PositioningStrategy<KtWhenConditionInRange> = object : PositioningStrategy<KtWhenConditionInRange>() {
|
@JvmField
|
||||||
|
val WHEN_CONDITION_IN_RANGE: PositioningStrategy<KtWhenConditionInRange> = object : PositioningStrategy<KtWhenConditionInRange>() {
|
||||||
override fun mark(element: KtWhenConditionInRange): List<TextRange> {
|
override fun mark(element: KtWhenConditionInRange): List<TextRange> {
|
||||||
return markElement(element.operationReference)
|
return markElement(element.operationReference)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val SPECIAL_CONSTRUCT_TOKEN: PositioningStrategy<KtExpression> = object : PositioningStrategy<KtExpression>() {
|
@JvmField
|
||||||
|
val SPECIAL_CONSTRUCT_TOKEN: PositioningStrategy<KtExpression> = object : PositioningStrategy<KtExpression>() {
|
||||||
override fun mark(element: KtExpression): List<TextRange> =
|
override fun mark(element: KtExpression): List<TextRange> =
|
||||||
when (element) {
|
when (element) {
|
||||||
is KtWhenExpression -> markElement(element.whenKeyword)
|
is KtWhenExpression -> markElement(element.whenKeyword)
|
||||||
is KtIfExpression -> markElement(element.ifKeyword)
|
is KtIfExpression -> markElement(element.ifKeyword)
|
||||||
is KtOperationExpression -> markElement(element.operationReference)
|
is KtOperationExpression -> markElement(element.operationReference)
|
||||||
else -> error("Expression is not an if, when or operation expression: ${element.getElementTextWithContext()}")
|
else -> error("Expression is not an if, when or operation expression: ${element.getElementTextWithContext()}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val NULLABLE_TYPE: PositioningStrategy<KtNullableType> = object : PositioningStrategy<KtNullableType>() {
|
@JvmField
|
||||||
|
val NULLABLE_TYPE: PositioningStrategy<KtNullableType> = object : PositioningStrategy<KtNullableType>() {
|
||||||
override fun mark(element: KtNullableType): List<TextRange> {
|
override fun mark(element: KtNullableType): List<TextRange> {
|
||||||
return markNode(element.questionMarkNode)
|
return markNode(element.questionMarkNode)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val CALL_EXPRESSION: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
@JvmField
|
||||||
|
val CALL_EXPRESSION: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
||||||
override fun mark(element: PsiElement): List<TextRange> {
|
override fun mark(element: PsiElement): List<TextRange> {
|
||||||
if (element is KtCallExpression) {
|
if (element is KtCallExpression) {
|
||||||
return markRange(element, element.typeArgumentList ?: element.calleeExpression ?: element)
|
return markRange(element, element.typeArgumentList ?: element.calleeExpression ?: element)
|
||||||
@@ -478,13 +506,15 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val VALUE_ARGUMENTS: PositioningStrategy<KtElement> = object : PositioningStrategy<KtElement>() {
|
@JvmField
|
||||||
|
val VALUE_ARGUMENTS: PositioningStrategy<KtElement> = object : PositioningStrategy<KtElement>() {
|
||||||
override fun mark(element: KtElement): List<TextRange> {
|
override fun mark(element: KtElement): List<TextRange> {
|
||||||
return markElement((element as? KtValueArgumentList)?.rightParenthesis ?: element)
|
return markElement((element as? KtValueArgumentList)?.rightParenthesis ?: element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val FUNCTION_PARAMETERS: PositioningStrategy<KtFunction> = object : PositioningStrategy<KtFunction>() {
|
@JvmField
|
||||||
|
val FUNCTION_PARAMETERS: PositioningStrategy<KtFunction> = object : PositioningStrategy<KtFunction>() {
|
||||||
override fun mark(element: KtFunction): List<TextRange> {
|
override fun mark(element: KtFunction): List<TextRange> {
|
||||||
val valueParameterList = element.valueParameterList
|
val valueParameterList = element.valueParameterList
|
||||||
if (valueParameterList != null) {
|
if (valueParameterList != null) {
|
||||||
@@ -497,7 +527,8 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val CUT_CHAR_QUOTES: PositioningStrategy<KtElement> = object : PositioningStrategy<KtElement>() {
|
@JvmField
|
||||||
|
val CUT_CHAR_QUOTES: PositioningStrategy<KtElement> = object : PositioningStrategy<KtElement>() {
|
||||||
override fun mark(element: KtElement): List<TextRange> {
|
override fun mark(element: KtElement): List<TextRange> {
|
||||||
if (element is KtConstantExpression) {
|
if (element is KtConstantExpression) {
|
||||||
if (element.node.elementType == KtNodeTypes.CHARACTER_CONSTANT) {
|
if (element.node.elementType == KtNodeTypes.CHARACTER_CONSTANT) {
|
||||||
@@ -509,7 +540,8 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val LONG_LITERAL_SUFFIX: PositioningStrategy<KtElement> = object : PositioningStrategy<KtElement>() {
|
@JvmField
|
||||||
|
val LONG_LITERAL_SUFFIX: PositioningStrategy<KtElement> = object : PositioningStrategy<KtElement>() {
|
||||||
override fun mark(element: KtElement): List<TextRange> {
|
override fun mark(element: KtElement): List<TextRange> {
|
||||||
if (element is KtConstantExpression) {
|
if (element is KtConstantExpression) {
|
||||||
if (element.node.elementType == KtNodeTypes.INTEGER_CONSTANT) {
|
if (element.node.elementType == KtNodeTypes.INTEGER_CONSTANT) {
|
||||||
@@ -521,19 +553,22 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val UNREACHABLE_CODE: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
@JvmField
|
||||||
|
val UNREACHABLE_CODE: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
||||||
override fun markDiagnostic(diagnostic: ParametrizedDiagnostic<out PsiElement>): List<TextRange> {
|
override fun markDiagnostic(diagnostic: ParametrizedDiagnostic<out PsiElement>): List<TextRange> {
|
||||||
return Errors.UNREACHABLE_CODE.cast(diagnostic).a
|
return Errors.UNREACHABLE_CODE.cast(diagnostic).a
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val AS_TYPE: PositioningStrategy<KtBinaryExpressionWithTypeRHS> = object : PositioningStrategy<KtBinaryExpressionWithTypeRHS>() {
|
@JvmField
|
||||||
|
val AS_TYPE: PositioningStrategy<KtBinaryExpressionWithTypeRHS> = object : PositioningStrategy<KtBinaryExpressionWithTypeRHS>() {
|
||||||
override fun mark(element: KtBinaryExpressionWithTypeRHS): List<TextRange> {
|
override fun mark(element: KtBinaryExpressionWithTypeRHS): List<TextRange> {
|
||||||
return markRange(element.operationReference, element)
|
return markRange(element.operationReference, element)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val COMPANION_OBJECT: PositioningStrategy<KtObjectDeclaration> = object : PositioningStrategy<KtObjectDeclaration>() {
|
@JvmField
|
||||||
|
val COMPANION_OBJECT: PositioningStrategy<KtObjectDeclaration> = object : PositioningStrategy<KtObjectDeclaration>() {
|
||||||
override fun mark(element: KtObjectDeclaration): List<TextRange> {
|
override fun mark(element: KtObjectDeclaration): List<TextRange> {
|
||||||
if (element.hasModifier(KtTokens.COMPANION_KEYWORD)) {
|
if (element.hasModifier(KtTokens.COMPANION_KEYWORD)) {
|
||||||
return modifierSetPosition(KtTokens.COMPANION_KEYWORD).mark(element)
|
return modifierSetPosition(KtTokens.COMPANION_KEYWORD).mark(element)
|
||||||
@@ -542,38 +577,43 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val SECONDARY_CONSTRUCTOR_DELEGATION_CALL: PositioningStrategy<KtConstructorDelegationCall> =
|
@JvmField
|
||||||
object : PositioningStrategy<KtConstructorDelegationCall>() {
|
val SECONDARY_CONSTRUCTOR_DELEGATION_CALL: PositioningStrategy<KtConstructorDelegationCall> =
|
||||||
override fun mark(element: KtConstructorDelegationCall): List<TextRange> {
|
object : PositioningStrategy<KtConstructorDelegationCall>() {
|
||||||
if (element.isImplicit) {
|
override fun mark(element: KtConstructorDelegationCall): List<TextRange> {
|
||||||
val constructor = element.getStrictParentOfType<KtSecondaryConstructor>()!!
|
if (element.isImplicit) {
|
||||||
val valueParameterList = constructor.valueParameterList ?: return markElement(constructor)
|
val constructor = element.getStrictParentOfType<KtSecondaryConstructor>()!!
|
||||||
return markRange(constructor.getConstructorKeyword(), valueParameterList.lastChild)
|
val valueParameterList = constructor.valueParameterList ?: return markElement(constructor)
|
||||||
}
|
return markRange(constructor.getConstructorKeyword(), valueParameterList.lastChild)
|
||||||
return markElement(element.calleeExpression ?: element)
|
|
||||||
}
|
}
|
||||||
|
return markElement(element.calleeExpression ?: element)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@JvmField val DELEGATOR_SUPER_CALL: PositioningStrategy<KtEnumEntry> = object: PositioningStrategy<KtEnumEntry>() {
|
@JvmField
|
||||||
|
val DELEGATOR_SUPER_CALL: PositioningStrategy<KtEnumEntry> = object : PositioningStrategy<KtEnumEntry>() {
|
||||||
override fun mark(element: KtEnumEntry): List<TextRange> {
|
override fun mark(element: KtEnumEntry): List<TextRange> {
|
||||||
val specifiers = element.superTypeListEntries
|
val specifiers = element.superTypeListEntries
|
||||||
return markElement(if (specifiers.isEmpty()) element else specifiers[0])
|
return markElement(if (specifiers.isEmpty()) element else specifiers[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val UNUSED_VALUE: PositioningStrategy<KtBinaryExpression> = object: PositioningStrategy<KtBinaryExpression>() {
|
@JvmField
|
||||||
|
val UNUSED_VALUE: PositioningStrategy<KtBinaryExpression> = object : PositioningStrategy<KtBinaryExpression>() {
|
||||||
override fun mark(element: KtBinaryExpression): List<TextRange> {
|
override fun mark(element: KtBinaryExpression): List<TextRange> {
|
||||||
return listOf(TextRange(element.left!!.startOffset, element.operationReference.endOffset))
|
return listOf(TextRange(element.left!!.startOffset, element.operationReference.endOffset))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val USELESS_ELVIS: PositioningStrategy<KtBinaryExpression> = object: PositioningStrategy<KtBinaryExpression>() {
|
@JvmField
|
||||||
|
val USELESS_ELVIS: PositioningStrategy<KtBinaryExpression> = object : PositioningStrategy<KtBinaryExpression>() {
|
||||||
override fun mark(element: KtBinaryExpression): List<TextRange> {
|
override fun mark(element: KtBinaryExpression): List<TextRange> {
|
||||||
return listOf(TextRange(element.operationReference.startOffset, element.endOffset))
|
return listOf(TextRange(element.operationReference.startOffset, element.endOffset))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val IMPORT_ALIAS: PositioningStrategy<KtImportDirective> = object: PositioningStrategy<KtImportDirective>() {
|
@JvmField
|
||||||
|
val IMPORT_ALIAS: PositioningStrategy<KtImportDirective> = object : PositioningStrategy<KtImportDirective>() {
|
||||||
override fun mark(element: KtImportDirective): List<TextRange> {
|
override fun mark(element: KtImportDirective): List<TextRange> {
|
||||||
element.alias?.nameIdentifier?.let { return markElement(it) }
|
element.alias?.nameIdentifier?.let { return markElement(it) }
|
||||||
element.importedReference?.let {
|
element.importedReference?.let {
|
||||||
@@ -586,7 +626,8 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val RETURN_WITH_LABEL: PositioningStrategy<KtReturnExpression> = object: PositioningStrategy<KtReturnExpression>() {
|
@JvmField
|
||||||
|
val RETURN_WITH_LABEL: PositioningStrategy<KtReturnExpression> = object : PositioningStrategy<KtReturnExpression>() {
|
||||||
override fun mark(element: KtReturnExpression): List<TextRange> {
|
override fun mark(element: KtReturnExpression): List<TextRange> {
|
||||||
val labeledExpression = element.labeledExpression
|
val labeledExpression = element.labeledExpression
|
||||||
if (labeledExpression != null) {
|
if (labeledExpression != null) {
|
||||||
@@ -597,7 +638,8 @@ object PositioningStrategies {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val RECEIVER: PositioningStrategy<KtCallableDeclaration> = object : DeclarationHeader<KtCallableDeclaration>() {
|
@JvmField
|
||||||
|
val RECEIVER: PositioningStrategy<KtCallableDeclaration> = object : DeclarationHeader<KtCallableDeclaration>() {
|
||||||
override fun mark(element: KtCallableDeclaration): List<TextRange> {
|
override fun mark(element: KtCallableDeclaration): List<TextRange> {
|
||||||
element.receiverTypeReference?.let { return markElement(it) }
|
element.receiverTypeReference?.let { return markElement(it) }
|
||||||
return DEFAULT.mark(element)
|
return DEFAULT.mark(element)
|
||||||
|
|||||||
+4
-3
@@ -20,10 +20,11 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
|
import org.jetbrains.kotlin.descriptors.ClassifierDescriptorWithTypeParameters
|
||||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
import org.jetbrains.kotlin.renderer.DescriptorRenderer
|
||||||
|
|
||||||
fun <P : Any> renderParameter(parameter: P, renderer: DiagnosticParameterRenderer<P>?, context: RenderingContext): Any
|
fun <P : Any> renderParameter(parameter: P, renderer: DiagnosticParameterRenderer<P>?, context: RenderingContext): Any =
|
||||||
= renderer?.render(parameter, context) ?: parameter
|
renderer?.render(parameter, context) ?: parameter
|
||||||
|
|
||||||
fun ClassifierDescriptorWithTypeParameters.renderKindWithName(): String = DescriptorRenderer.getClassifierKindPrefix(this) + " '" + name + "'"
|
fun ClassifierDescriptorWithTypeParameters.renderKindWithName(): String =
|
||||||
|
DescriptorRenderer.getClassifierKindPrefix(this) + " '" + name + "'"
|
||||||
|
|
||||||
fun ClassDescriptor.renderKind(): String = DescriptorRenderer.getClassifierKindPrefix(this)
|
fun ClassDescriptor.renderKind(): String = DescriptorRenderer.getClassifierKindPrefix(this)
|
||||||
|
|
||||||
|
|||||||
@@ -57,27 +57,33 @@ object Renderers {
|
|||||||
|
|
||||||
private val LOG = Logger.getInstance(Renderers::class.java)
|
private val LOG = Logger.getInstance(Renderers::class.java)
|
||||||
|
|
||||||
@JvmField val TO_STRING = Renderer<Any> {
|
@JvmField
|
||||||
element ->
|
val TO_STRING = Renderer<Any> { element ->
|
||||||
if (element is DeclarationDescriptor) {
|
if (element is DeclarationDescriptor) {
|
||||||
LOG.warn("Diagnostic renderer TO_STRING was used to render an instance of DeclarationDescriptor.\n"
|
LOG.warn(
|
||||||
+ "This is usually a bad idea, because descriptors' toString() includes some debug information, "
|
"Diagnostic renderer TO_STRING was used to render an instance of DeclarationDescriptor.\n"
|
||||||
+ "which should not be seen by the user.\nDescriptor: " + element)
|
+ "This is usually a bad idea, because descriptors' toString() includes some debug information, "
|
||||||
|
+ "which should not be seen by the user.\nDescriptor: " + element
|
||||||
|
)
|
||||||
}
|
}
|
||||||
element.toString()
|
element.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val STRING = Renderer<String> { it }
|
@JvmField
|
||||||
|
val STRING = Renderer<String> { it }
|
||||||
|
|
||||||
@JvmField val THROWABLE = Renderer<Throwable> {
|
@JvmField
|
||||||
|
val THROWABLE = Renderer<Throwable> {
|
||||||
val writer = StringWriter()
|
val writer = StringWriter()
|
||||||
it.printStackTrace(PrintWriter(writer))
|
it.printStackTrace(PrintWriter(writer))
|
||||||
StringUtil.first(writer.toString(), 2048, true)
|
StringUtil.first(writer.toString(), 2048, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val NAME = Renderer<Named> { it.name.asString() }
|
@JvmField
|
||||||
|
val NAME = Renderer<Named> { it.name.asString() }
|
||||||
|
|
||||||
@JvmField val PLATFORM = Renderer<ModuleDescriptor> {
|
@JvmField
|
||||||
|
val PLATFORM = Renderer<ModuleDescriptor> {
|
||||||
val platform = it.getMultiTargetPlatform()
|
val platform = it.getMultiTargetPlatform()
|
||||||
" ${it.getCapability(ModuleInfo.Capability)?.displayedName ?: ""}" + when (platform) {
|
" ${it.getCapability(ModuleInfo.Capability)?.displayedName ?: ""}" + when (platform) {
|
||||||
MultiTargetPlatform.Common -> ""
|
MultiTargetPlatform.Common -> ""
|
||||||
@@ -86,13 +92,15 @@ object Renderers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val VISIBILITY = Renderer<Visibility> {
|
@JvmField
|
||||||
|
val VISIBILITY = Renderer<Visibility> {
|
||||||
if (it == Visibilities.INVISIBLE_FAKE)
|
if (it == Visibilities.INVISIBLE_FAKE)
|
||||||
"invisible (private in a supertype)"
|
"invisible (private in a supertype)"
|
||||||
else it.displayName
|
else it.displayName
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val DECLARATION_NAME_WITH_KIND = Renderer<DeclarationDescriptor> {
|
@JvmField
|
||||||
|
val DECLARATION_NAME_WITH_KIND = Renderer<DeclarationDescriptor> {
|
||||||
val name = it.name.asString()
|
val name = it.name.asString()
|
||||||
when (it) {
|
when (it) {
|
||||||
is PackageFragmentDescriptor -> "package '$name'"
|
is PackageFragmentDescriptor -> "package '$name'"
|
||||||
@@ -108,7 +116,8 @@ object Renderers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val CAPITALIZED_DECLARATION_NAME_WITH_KIND_AND_PLATFORM = ContextDependentRenderer<DeclarationDescriptor> { descriptor, context ->
|
@JvmField
|
||||||
|
val CAPITALIZED_DECLARATION_NAME_WITH_KIND_AND_PLATFORM = ContextDependentRenderer<DeclarationDescriptor> { descriptor, context ->
|
||||||
val declarationWithNameAndKind = DECLARATION_NAME_WITH_KIND.render(descriptor, context)
|
val declarationWithNameAndKind = DECLARATION_NAME_WITH_KIND.render(descriptor, context)
|
||||||
val withPlatform = if (descriptor is MemberDescriptor && descriptor.isActual)
|
val withPlatform = if (descriptor is MemberDescriptor && descriptor.isActual)
|
||||||
"actual $declarationWithNameAndKind"
|
"actual $declarationWithNameAndKind"
|
||||||
@@ -119,37 +128,40 @@ object Renderers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@JvmField val NAME_OF_CONTAINING_DECLARATION_OR_FILE = Renderer<DeclarationDescriptor> {
|
@JvmField
|
||||||
|
val NAME_OF_CONTAINING_DECLARATION_OR_FILE = Renderer<DeclarationDescriptor> {
|
||||||
if (DescriptorUtils.isTopLevelDeclaration(it) && it is DeclarationDescriptorWithVisibility && it.visibility == Visibilities.PRIVATE) {
|
if (DescriptorUtils.isTopLevelDeclaration(it) && it is DeclarationDescriptorWithVisibility && it.visibility == Visibilities.PRIVATE) {
|
||||||
"file"
|
"file"
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val containingDeclaration = it.containingDeclaration
|
val containingDeclaration = it.containingDeclaration
|
||||||
if (containingDeclaration is PackageFragmentDescriptor) {
|
if (containingDeclaration is PackageFragmentDescriptor) {
|
||||||
containingDeclaration.fqName.asString().wrapIntoQuotes()
|
containingDeclaration.fqName.asString().wrapIntoQuotes()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
containingDeclaration!!.name.asString().wrapIntoQuotes()
|
containingDeclaration!!.name.asString().wrapIntoQuotes()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val ELEMENT_TEXT = Renderer<PsiElement> { it.text }
|
@JvmField
|
||||||
|
val ELEMENT_TEXT = Renderer<PsiElement> { it.text }
|
||||||
|
|
||||||
@JvmField val DECLARATION_NAME = Renderer<KtNamedDeclaration> { it.nameAsSafeName.asString() }
|
@JvmField
|
||||||
|
val DECLARATION_NAME = Renderer<KtNamedDeclaration> { it.nameAsSafeName.asString() }
|
||||||
|
|
||||||
@JvmField val RENDER_CLASS_OR_OBJECT = Renderer {
|
@JvmField
|
||||||
classOrObject: KtClassOrObject ->
|
val RENDER_CLASS_OR_OBJECT = Renderer { classOrObject: KtClassOrObject ->
|
||||||
val name = classOrObject.name?.let { " ${it.wrapIntoQuotes()}" } ?: ""
|
val name = classOrObject.name?.let { " ${it.wrapIntoQuotes()}" } ?: ""
|
||||||
if (classOrObject is KtClass) "Class" + name else "Object" + name
|
if (classOrObject is KtClass) "Class" + name else "Object" + name
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val RENDER_CLASS_OR_OBJECT_NAME = Renderer<ClassifierDescriptorWithTypeParameters> { it.renderKindWithName() }
|
@JvmField
|
||||||
|
val RENDER_CLASS_OR_OBJECT_NAME = Renderer<ClassifierDescriptorWithTypeParameters> { it.renderKindWithName() }
|
||||||
|
|
||||||
@JvmField val RENDER_TYPE = SmartTypeRenderer(DescriptorRenderer.FQ_NAMES_IN_TYPES.withOptions { parameterNamesInFunctionalTypes = false })
|
@JvmField
|
||||||
|
val RENDER_TYPE = SmartTypeRenderer(DescriptorRenderer.FQ_NAMES_IN_TYPES.withOptions { parameterNamesInFunctionalTypes = false })
|
||||||
|
|
||||||
@JvmField val RENDER_POSITION_VARIANCE = Renderer {
|
@JvmField
|
||||||
variance: Variance ->
|
val RENDER_POSITION_VARIANCE = Renderer { variance: Variance ->
|
||||||
when (variance) {
|
when (variance) {
|
||||||
Variance.INVARIANT -> "invariant"
|
Variance.INVARIANT -> "invariant"
|
||||||
Variance.IN_VARIANCE -> "in"
|
Variance.IN_VARIANCE -> "in"
|
||||||
@@ -157,17 +169,17 @@ object Renderers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val AMBIGUOUS_CALLS = Renderer {
|
@JvmField
|
||||||
calls: Collection<ResolvedCall<*>> ->
|
val AMBIGUOUS_CALLS = Renderer { calls: Collection<ResolvedCall<*>> ->
|
||||||
val descriptors = calls.map { it.resultingDescriptor }
|
val descriptors = calls.map { it.resultingDescriptor }
|
||||||
val context = RenderingContext.Impl(descriptors)
|
val context = RenderingContext.Impl(descriptors)
|
||||||
descriptors
|
descriptors
|
||||||
.sortedWith(MemberComparator.INSTANCE)
|
.sortedWith(MemberComparator.INSTANCE)
|
||||||
.joinToString(separator = "\n", prefix = "\n") { FQ_NAMES_IN_TYPES.render(it, context) }
|
.joinToString(separator = "\n", prefix = "\n") { FQ_NAMES_IN_TYPES.render(it, context) }
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun <T> commaSeparated(itemRenderer: DiagnosticParameterRenderer<T>) = ContextDependentRenderer<Collection<T>> {
|
@JvmStatic
|
||||||
collection, context ->
|
fun <T> commaSeparated(itemRenderer: DiagnosticParameterRenderer<T>) = ContextDependentRenderer<Collection<T>> { collection, context ->
|
||||||
buildString {
|
buildString {
|
||||||
val iterator = collection.iterator()
|
val iterator = collection.iterator()
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
@@ -180,31 +192,39 @@ object Renderers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS_RENDERER = Renderer<InferenceErrorData> {
|
@JvmField
|
||||||
|
val TYPE_INFERENCE_CONFLICTING_SUBSTITUTIONS_RENDERER = Renderer<InferenceErrorData> {
|
||||||
renderConflictingSubstitutionsInferenceError(it, TabledDescriptorRenderer.create()).toString()
|
renderConflictingSubstitutionsInferenceError(it, TabledDescriptorRenderer.create()).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR_RENDERER = Renderer<InferenceErrorData> {
|
@JvmField
|
||||||
|
val TYPE_INFERENCE_PARAMETER_CONSTRAINT_ERROR_RENDERER = Renderer<InferenceErrorData> {
|
||||||
renderParameterConstraintError(it, TabledDescriptorRenderer.create()).toString()
|
renderParameterConstraintError(it, TabledDescriptorRenderer.create()).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER = Renderer<InferenceErrorData> {
|
@JvmField
|
||||||
|
val TYPE_INFERENCE_NO_INFORMATION_FOR_PARAMETER_RENDERER = Renderer<InferenceErrorData> {
|
||||||
renderNoInformationForParameterError(it, TabledDescriptorRenderer.create()).toString()
|
renderNoInformationForParameterError(it, TabledDescriptorRenderer.create()).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER = Renderer<InferenceErrorData> {
|
@JvmField
|
||||||
|
val TYPE_INFERENCE_UPPER_BOUND_VIOLATED_RENDERER = Renderer<InferenceErrorData> {
|
||||||
renderUpperBoundViolatedInferenceError(it, TabledDescriptorRenderer.create()).toString()
|
renderUpperBoundViolatedInferenceError(it, TabledDescriptorRenderer.create()).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val TYPE_INFERENCE_CANNOT_CAPTURE_TYPES_RENDERER = Renderer<InferenceErrorData> {
|
@JvmField
|
||||||
|
val TYPE_INFERENCE_CANNOT_CAPTURE_TYPES_RENDERER = Renderer<InferenceErrorData> {
|
||||||
renderCannotCaptureTypeParameterError(it, TabledDescriptorRenderer.create()).toString()
|
renderCannotCaptureTypeParameterError(it, TabledDescriptorRenderer.create()).toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun renderConflictingSubstitutionsInferenceError(
|
@JvmStatic
|
||||||
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
fun renderConflictingSubstitutionsInferenceError(
|
||||||
|
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
||||||
): TabledDescriptorRenderer {
|
): TabledDescriptorRenderer {
|
||||||
LOG.assertTrue(inferenceErrorData.constraintSystem.status.hasConflictingConstraints(),
|
LOG.assertTrue(
|
||||||
debugMessage("Conflicting substitutions inference error renderer is applied for incorrect status", inferenceErrorData))
|
inferenceErrorData.constraintSystem.status.hasConflictingConstraints(),
|
||||||
|
debugMessage("Conflicting substitutions inference error renderer is applied for incorrect status", inferenceErrorData)
|
||||||
|
)
|
||||||
|
|
||||||
val substitutedDescriptors = Lists.newArrayList<CallableDescriptor>()
|
val substitutedDescriptors = Lists.newArrayList<CallableDescriptor>()
|
||||||
val substitutors = ConstraintsUtil.getSubstitutorsForConflictingParameters(inferenceErrorData.constraintSystem)
|
val substitutors = ConstraintsUtil.getSubstitutorsForConflictingParameters(inferenceErrorData.constraintSystem)
|
||||||
@@ -219,10 +239,12 @@ object Renderers {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
result.text(newText()
|
result.text(
|
||||||
.normal("Cannot infer type parameter ")
|
newText()
|
||||||
.strong(firstConflictingVariable.name)
|
.normal("Cannot infer type parameter ")
|
||||||
.normal(" in "))
|
.strong(firstConflictingVariable.name)
|
||||||
|
.normal(" in ")
|
||||||
|
)
|
||||||
val table = newTable()
|
val table = newTable()
|
||||||
result.table(table)
|
result.table(table)
|
||||||
table.descriptor(inferenceErrorData.descriptor).text("None of the following substitutions")
|
table.descriptor(inferenceErrorData.descriptor).text("None of the following substitutions")
|
||||||
@@ -249,29 +271,33 @@ object Renderers {
|
|||||||
table.functionArgumentTypeList(receiverType, parameterTypes, { errorPositions.contains(it) })
|
table.functionArgumentTypeList(receiverType, parameterTypes, { errorPositions.contains(it) })
|
||||||
}
|
}
|
||||||
|
|
||||||
table.text("can be applied to").functionArgumentTypeList(inferenceErrorData.receiverArgumentType, inferenceErrorData.valueArgumentsTypes)
|
table.text("can be applied to")
|
||||||
|
.functionArgumentTypeList(inferenceErrorData.receiverArgumentType, inferenceErrorData.valueArgumentsTypes)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun renderParameterConstraintError(
|
@JvmStatic
|
||||||
inferenceErrorData: InferenceErrorData, renderer: TabledDescriptorRenderer
|
fun renderParameterConstraintError(
|
||||||
|
inferenceErrorData: InferenceErrorData, renderer: TabledDescriptorRenderer
|
||||||
): TabledDescriptorRenderer {
|
): TabledDescriptorRenderer {
|
||||||
val constraintErrors = inferenceErrorData.constraintSystem.status.constraintErrors
|
val constraintErrors = inferenceErrorData.constraintSystem.status.constraintErrors
|
||||||
val errorPositions = constraintErrors.filter { it is ParameterConstraintError }.map { it.constraintPosition }
|
val errorPositions = constraintErrors.filter { it is ParameterConstraintError }.map { it.constraintPosition }
|
||||||
return renderer.table(
|
return renderer.table(
|
||||||
TabledDescriptorRenderer
|
TabledDescriptorRenderer
|
||||||
.newTable()
|
.newTable()
|
||||||
.descriptor(inferenceErrorData.descriptor)
|
.descriptor(inferenceErrorData.descriptor)
|
||||||
.text("cannot be applied to")
|
.text("cannot be applied to")
|
||||||
.functionArgumentTypeList(inferenceErrorData.receiverArgumentType,
|
.functionArgumentTypeList(inferenceErrorData.receiverArgumentType,
|
||||||
inferenceErrorData.valueArgumentsTypes,
|
inferenceErrorData.valueArgumentsTypes,
|
||||||
{ errorPositions.contains(it) }))
|
{ errorPositions.contains(it) })
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@JvmStatic fun renderNoInformationForParameterError(
|
@JvmStatic
|
||||||
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
fun renderNoInformationForParameterError(
|
||||||
|
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
||||||
): TabledDescriptorRenderer {
|
): TabledDescriptorRenderer {
|
||||||
val firstUnknownVariable = inferenceErrorData.constraintSystem.typeVariables.firstOrNull { variable ->
|
val firstUnknownVariable = inferenceErrorData.constraintSystem.typeVariables.firstOrNull { variable ->
|
||||||
inferenceErrorData.constraintSystem.getTypeBounds(variable).values.isEmpty()
|
inferenceErrorData.constraintSystem.getTypeBounds(variable).values.isEmpty()
|
||||||
@@ -280,21 +306,28 @@ object Renderers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return result
|
||||||
.text(newText().normal("Not enough information to infer parameter ")
|
.text(
|
||||||
.strong(firstUnknownVariable.name)
|
newText().normal("Not enough information to infer parameter ")
|
||||||
.normal(" in "))
|
.strong(firstUnknownVariable.name)
|
||||||
.table(newTable()
|
.normal(" in ")
|
||||||
.descriptor(inferenceErrorData.descriptor)
|
)
|
||||||
.text("Please specify it explicitly."))
|
.table(
|
||||||
|
newTable()
|
||||||
|
.descriptor(inferenceErrorData.descriptor)
|
||||||
|
.text("Please specify it explicitly.")
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun renderUpperBoundViolatedInferenceError(
|
@JvmStatic
|
||||||
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
fun renderUpperBoundViolatedInferenceError(
|
||||||
|
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
||||||
): TabledDescriptorRenderer {
|
): TabledDescriptorRenderer {
|
||||||
val constraintSystem = inferenceErrorData.constraintSystem
|
val constraintSystem = inferenceErrorData.constraintSystem
|
||||||
val status = constraintSystem.status
|
val status = constraintSystem.status
|
||||||
LOG.assertTrue(status.hasViolatedUpperBound(),
|
LOG.assertTrue(
|
||||||
debugMessage("Upper bound violated renderer is applied for incorrect status", inferenceErrorData))
|
status.hasViolatedUpperBound(),
|
||||||
|
debugMessage("Upper bound violated renderer is applied for incorrect status", inferenceErrorData)
|
||||||
|
)
|
||||||
|
|
||||||
val systemWithoutWeakConstraints = constraintSystem.filterConstraintsOut(TYPE_BOUND_POSITION)
|
val systemWithoutWeakConstraints = constraintSystem.filterConstraintsOut(TYPE_BOUND_POSITION)
|
||||||
val typeParameterDescriptor = inferenceErrorData.descriptor.typeParameters.firstOrNull {
|
val typeParameterDescriptor = inferenceErrorData.descriptor.typeParameters.firstOrNull {
|
||||||
@@ -304,7 +337,7 @@ object Renderers {
|
|||||||
if (typeParameterDescriptor == null) {
|
if (typeParameterDescriptor == null) {
|
||||||
if (inferenceErrorData.descriptor is TypeAliasConstructorDescriptor) {
|
if (inferenceErrorData.descriptor is TypeAliasConstructorDescriptor) {
|
||||||
renderUpperBoundViolatedInferenceErrorForTypeAliasConstructor(
|
renderUpperBoundViolatedInferenceErrorForTypeAliasConstructor(
|
||||||
inferenceErrorData, result, systemWithoutWeakConstraints
|
inferenceErrorData, result, systemWithoutWeakConstraints
|
||||||
)?.let {
|
)?.let {
|
||||||
return it
|
return it
|
||||||
}
|
}
|
||||||
@@ -313,7 +346,12 @@ object Renderers {
|
|||||||
return if (status.hasConflictingConstraints())
|
return if (status.hasConflictingConstraints())
|
||||||
renderConflictingSubstitutionsInferenceError(inferenceErrorData, result)
|
renderConflictingSubstitutionsInferenceError(inferenceErrorData, result)
|
||||||
else {
|
else {
|
||||||
LOG.error(debugMessage("There is no type parameter with violated upper bound for 'upper bound violated' error", inferenceErrorData))
|
LOG.error(
|
||||||
|
debugMessage(
|
||||||
|
"There is no type parameter with violated upper bound for 'upper bound violated' error",
|
||||||
|
inferenceErrorData
|
||||||
|
)
|
||||||
|
)
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,21 +359,30 @@ object Renderers {
|
|||||||
val typeVariable = systemWithoutWeakConstraints.descriptorToVariable(inferenceErrorData.call.toHandle(), typeParameterDescriptor)
|
val typeVariable = systemWithoutWeakConstraints.descriptorToVariable(inferenceErrorData.call.toHandle(), typeParameterDescriptor)
|
||||||
val inferredValueForTypeParameter = systemWithoutWeakConstraints.getTypeBounds(typeVariable).value
|
val inferredValueForTypeParameter = systemWithoutWeakConstraints.getTypeBounds(typeVariable).value
|
||||||
if (inferredValueForTypeParameter == null) {
|
if (inferredValueForTypeParameter == null) {
|
||||||
LOG.error(debugMessage("System without weak constraints is not successful, there is no value for type parameter " +
|
LOG.error(
|
||||||
typeParameterDescriptor.name + "\n: " + systemWithoutWeakConstraints, inferenceErrorData))
|
debugMessage(
|
||||||
|
"System without weak constraints is not successful, there is no value for type parameter " +
|
||||||
|
typeParameterDescriptor.name + "\n: " + systemWithoutWeakConstraints, inferenceErrorData
|
||||||
|
)
|
||||||
|
)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
result.text(newText()
|
result.text(
|
||||||
.normal("Type parameter bound for ")
|
newText()
|
||||||
.strong(typeParameterDescriptor.name)
|
.normal("Type parameter bound for ")
|
||||||
.normal(" in "))
|
.strong(typeParameterDescriptor.name)
|
||||||
.table(newTable()
|
.normal(" in ")
|
||||||
.descriptor(inferenceErrorData.descriptor))
|
)
|
||||||
|
.table(
|
||||||
|
newTable()
|
||||||
|
.descriptor(inferenceErrorData.descriptor)
|
||||||
|
)
|
||||||
|
|
||||||
var violatedUpperBound: KotlinType? = null
|
var violatedUpperBound: KotlinType? = null
|
||||||
for (upperBound in typeParameterDescriptor.upperBounds) {
|
for (upperBound in typeParameterDescriptor.upperBounds) {
|
||||||
val upperBoundWithSubstitutedInferredTypes = systemWithoutWeakConstraints.resultingSubstitutor.substitute(upperBound, Variance.INVARIANT)
|
val upperBoundWithSubstitutedInferredTypes =
|
||||||
|
systemWithoutWeakConstraints.resultingSubstitutor.substitute(upperBound, Variance.INVARIANT)
|
||||||
if (upperBoundWithSubstitutedInferredTypes != null
|
if (upperBoundWithSubstitutedInferredTypes != null
|
||||||
&& !KotlinTypeChecker.DEFAULT.isSubtypeOf(inferredValueForTypeParameter, upperBoundWithSubstitutedInferredTypes)) {
|
&& !KotlinTypeChecker.DEFAULT.isSubtypeOf(inferredValueForTypeParameter, upperBoundWithSubstitutedInferredTypes)) {
|
||||||
violatedUpperBound = upperBoundWithSubstitutedInferredTypes
|
violatedUpperBound = upperBoundWithSubstitutedInferredTypes
|
||||||
@@ -343,26 +390,32 @@ object Renderers {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (violatedUpperBound == null) {
|
if (violatedUpperBound == null) {
|
||||||
LOG.error(debugMessage("Type parameter (chosen as violating its upper bound)" +
|
LOG.error(
|
||||||
typeParameterDescriptor.name + " violates no bounds after substitution", inferenceErrorData))
|
debugMessage(
|
||||||
|
"Type parameter (chosen as violating its upper bound)" +
|
||||||
|
typeParameterDescriptor.name + " violates no bounds after substitution", inferenceErrorData
|
||||||
|
)
|
||||||
|
)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: context should be in fact shared for the table and these two types
|
// TODO: context should be in fact shared for the table and these two types
|
||||||
val context = RenderingContext.of(inferredValueForTypeParameter, violatedUpperBound)
|
val context = RenderingContext.of(inferredValueForTypeParameter, violatedUpperBound)
|
||||||
val typeRenderer = result.typeRenderer
|
val typeRenderer = result.typeRenderer
|
||||||
result.text(newText()
|
result.text(
|
||||||
.normal(" is not satisfied: inferred type ")
|
newText()
|
||||||
.error(typeRenderer.render(inferredValueForTypeParameter, context))
|
.normal(" is not satisfied: inferred type ")
|
||||||
.normal(" is not a subtype of ")
|
.error(typeRenderer.render(inferredValueForTypeParameter, context))
|
||||||
.strong(typeRenderer.render(violatedUpperBound, context)))
|
.normal(" is not a subtype of ")
|
||||||
|
.strong(typeRenderer.render(violatedUpperBound, context))
|
||||||
|
)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderUpperBoundViolatedInferenceErrorForTypeAliasConstructor(
|
private fun renderUpperBoundViolatedInferenceErrorForTypeAliasConstructor(
|
||||||
inferenceErrorData: InferenceErrorData,
|
inferenceErrorData: InferenceErrorData,
|
||||||
result: TabledDescriptorRenderer,
|
result: TabledDescriptorRenderer,
|
||||||
systemWithoutWeakConstraints: ConstraintSystem
|
systemWithoutWeakConstraints: ConstraintSystem
|
||||||
): TabledDescriptorRenderer? {
|
): TabledDescriptorRenderer? {
|
||||||
val descriptor = inferenceErrorData.descriptor
|
val descriptor = inferenceErrorData.descriptor
|
||||||
if (descriptor !is TypeAliasConstructorDescriptor) {
|
if (descriptor !is TypeAliasConstructorDescriptor) {
|
||||||
@@ -391,12 +444,16 @@ object Renderers {
|
|||||||
val context = RenderingContext.of(violatingInferredType, violatedUpperBound)
|
val context = RenderingContext.of(violatingInferredType, violatedUpperBound)
|
||||||
val typeRenderer = result.typeRenderer
|
val typeRenderer = result.typeRenderer
|
||||||
|
|
||||||
result.text(newText().normal("Type parameter bound for ").strong(constraintInfo.typeParameter.name)
|
result.text(
|
||||||
.normal(" in type inferred from type alias expansion for "))
|
newText().normal("Type parameter bound for ").strong(constraintInfo.typeParameter.name)
|
||||||
.table(newTable().descriptor(inferenceErrorData.descriptor))
|
.normal(" in type inferred from type alias expansion for ")
|
||||||
|
)
|
||||||
|
.table(newTable().descriptor(inferenceErrorData.descriptor))
|
||||||
|
|
||||||
result.text(newText().normal(" is not satisfied: inferred type ").error(typeRenderer.render(violatingInferredType, context))
|
result.text(
|
||||||
.normal(" is not a subtype of ").strong(typeRenderer.render(violatedUpperBound, context)))
|
newText().normal(" is not satisfied: inferred type ").error(typeRenderer.render(violatingInferredType, context))
|
||||||
|
.normal(" is not a subtype of ").strong(typeRenderer.render(violatedUpperBound, context))
|
||||||
|
)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -404,8 +461,9 @@ object Renderers {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun renderCannotCaptureTypeParameterError(
|
@JvmStatic
|
||||||
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
fun renderCannotCaptureTypeParameterError(
|
||||||
|
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
||||||
): TabledDescriptorRenderer {
|
): TabledDescriptorRenderer {
|
||||||
val system = inferenceErrorData.constraintSystem
|
val system = inferenceErrorData.constraintSystem
|
||||||
val errors = system.status.constraintErrors
|
val errors = system.status.constraintErrors
|
||||||
@@ -419,7 +477,12 @@ object Renderers {
|
|||||||
val boundWithCapturedType = typeBounds.bounds.firstOrNull { it.constrainingType.isCaptured() }
|
val boundWithCapturedType = typeBounds.bounds.firstOrNull { it.constrainingType.isCaptured() }
|
||||||
val capturedTypeConstructor = boundWithCapturedType?.constrainingType?.constructor as? CapturedTypeConstructor
|
val capturedTypeConstructor = boundWithCapturedType?.constrainingType?.constructor as? CapturedTypeConstructor
|
||||||
if (capturedTypeConstructor == null) {
|
if (capturedTypeConstructor == null) {
|
||||||
LOG.error(debugMessage("There is no captured type in bounds, but there is an error 'cannot capture type parameter'", inferenceErrorData))
|
LOG.error(
|
||||||
|
debugMessage(
|
||||||
|
"There is no captured type in bounds, but there is an error 'cannot capture type parameter'",
|
||||||
|
inferenceErrorData
|
||||||
|
)
|
||||||
|
)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -431,20 +494,25 @@ object Renderers {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val explanation =
|
val explanation =
|
||||||
"Type parameter has an upper bound ${result.typeRenderer.render(upperBound, RenderingContext.of(upperBound)).wrapIntoQuotes()}" +
|
"Type parameter has an upper bound ${result.typeRenderer.render(
|
||||||
" that cannot be satisfied capturing 'in' projection"
|
upperBound,
|
||||||
|
RenderingContext.of(upperBound)
|
||||||
|
).wrapIntoQuotes()}" +
|
||||||
|
" that cannot be satisfied capturing 'in' projection"
|
||||||
|
|
||||||
result.text(newText().normal(
|
result.text(
|
||||||
|
newText().normal(
|
||||||
typeParameter.name.wrapIntoQuotes() +
|
typeParameter.name.wrapIntoQuotes() +
|
||||||
" cannot capture " +
|
" cannot capture " +
|
||||||
"${capturedTypeConstructor.typeProjection.toString().wrapIntoQuotes()}. " +
|
"${capturedTypeConstructor.typeProjection.toString().wrapIntoQuotes()}. " +
|
||||||
explanation
|
explanation
|
||||||
))
|
)
|
||||||
|
)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val CLASSES_OR_SEPARATED = Renderer<Collection<ClassDescriptor>> {
|
@JvmField
|
||||||
descriptors ->
|
val CLASSES_OR_SEPARATED = Renderer<Collection<ClassDescriptor>> { descriptors ->
|
||||||
buildString {
|
buildString {
|
||||||
var index = 0
|
var index = 0
|
||||||
for (descriptor in descriptors) {
|
for (descriptor in descriptors) {
|
||||||
@@ -452,17 +520,18 @@ object Renderers {
|
|||||||
index++
|
index++
|
||||||
if (index <= descriptors.size - 2) {
|
if (index <= descriptors.size - 2) {
|
||||||
append(", ")
|
append(", ")
|
||||||
}
|
} else if (index == descriptors.size - 1) {
|
||||||
else if (index == descriptors.size - 1) {
|
|
||||||
append(" or ")
|
append(" or ")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderTypes(types: Collection<KotlinType>, context: RenderingContext) = StringUtil.join(types, { RENDER_TYPE.render(it, context) }, ", ")
|
private fun renderTypes(types: Collection<KotlinType>, context: RenderingContext) =
|
||||||
|
StringUtil.join(types, { RENDER_TYPE.render(it, context) }, ", ")
|
||||||
|
|
||||||
@JvmField val RENDER_COLLECTION_OF_TYPES = ContextDependentRenderer<Collection<KotlinType>> { types, context -> renderTypes(types, context) }
|
@JvmField
|
||||||
|
val RENDER_COLLECTION_OF_TYPES = ContextDependentRenderer<Collection<KotlinType>> { types, context -> renderTypes(types, context) }
|
||||||
|
|
||||||
fun renderConstraintSystem(constraintSystem: ConstraintSystem, shortTypeBounds: Boolean): String {
|
fun renderConstraintSystem(constraintSystem: ConstraintSystem, shortTypeBounds: Boolean): String {
|
||||||
val typeBounds = linkedSetOf<TypeBounds>()
|
val typeBounds = linkedSetOf<TypeBounds>()
|
||||||
@@ -470,8 +539,8 @@ object Renderers {
|
|||||||
typeBounds.add(constraintSystem.getTypeBounds(variable))
|
typeBounds.add(constraintSystem.getTypeBounds(variable))
|
||||||
}
|
}
|
||||||
return "type parameter bounds:\n" +
|
return "type parameter bounds:\n" +
|
||||||
StringUtil.join(typeBounds, { renderTypeBounds(it, short = shortTypeBounds) }, "\n") + "\n\n" + "status:\n" +
|
StringUtil.join(typeBounds, { renderTypeBounds(it, short = shortTypeBounds) }, "\n") + "\n\n" + "status:\n" +
|
||||||
ConstraintsUtil.getDebugMessageForStatus(constraintSystem.status)
|
ConstraintsUtil.getDebugMessageForStatus(constraintSystem.status)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renderTypeBounds(typeBounds: TypeBounds, short: Boolean): String {
|
private fun renderTypeBounds(typeBounds: TypeBounds, short: Boolean): String {
|
||||||
@@ -482,14 +551,13 @@ object Renderers {
|
|||||||
else -> ":= "
|
else -> ":= "
|
||||||
}
|
}
|
||||||
val renderer = if (short) DescriptorRenderer.SHORT_NAMES_IN_TYPES else DescriptorRenderer.FQ_NAMES_IN_TYPES
|
val renderer = if (short) DescriptorRenderer.SHORT_NAMES_IN_TYPES else DescriptorRenderer.FQ_NAMES_IN_TYPES
|
||||||
val renderedBound = arrow + renderer.renderType(bound.constrainingType) + if (!bound.isProper) "*" else ""
|
val renderedBound = arrow + renderer.renderType(bound.constrainingType) + if (!bound.isProper) "*" else ""
|
||||||
if (short) renderedBound else renderedBound + '(' + bound.position + ')'
|
if (short) renderedBound else renderedBound + '(' + bound.position + ')'
|
||||||
}
|
}
|
||||||
val typeVariableName = typeBounds.typeVariable.name
|
val typeVariableName = typeBounds.typeVariable.name
|
||||||
return if (typeBounds.bounds.isEmpty()) {
|
return if (typeBounds.bounds.isEmpty()) {
|
||||||
typeVariableName.asString()
|
typeVariableName.asString()
|
||||||
}
|
} else
|
||||||
else
|
|
||||||
"$typeVariableName ${StringUtil.join(typeBounds.bounds, renderBound, ", ")}"
|
"$typeVariableName ${StringUtil.join(typeBounds.bounds, renderBound, ", ")}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -503,8 +571,7 @@ object Renderers {
|
|||||||
val context = RenderingContext.Empty
|
val context = RenderingContext.Empty
|
||||||
if (TypeUtils.noExpectedType(inferenceErrorData.expectedType)) {
|
if (TypeUtils.noExpectedType(inferenceErrorData.expectedType)) {
|
||||||
append(inferenceErrorData.expectedType)
|
append(inferenceErrorData.expectedType)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
append(RENDER_TYPE.render(inferenceErrorData.expectedType, context))
|
append(RENDER_TYPE.render(inferenceErrorData.expectedType, context))
|
||||||
}
|
}
|
||||||
append("\nArgument types:\n")
|
append("\nArgument types:\n")
|
||||||
@@ -519,26 +586,33 @@ object Renderers {
|
|||||||
|
|
||||||
private val WHEN_MISSING_LIMIT = 7
|
private val WHEN_MISSING_LIMIT = 7
|
||||||
|
|
||||||
@JvmField val RENDER_WHEN_MISSING_CASES = Renderer<List<WhenMissingCase>> {
|
@JvmField
|
||||||
|
val RENDER_WHEN_MISSING_CASES = Renderer<List<WhenMissingCase>> {
|
||||||
if (!it.hasUnknown) {
|
if (!it.hasUnknown) {
|
||||||
val list = it.joinToString(", ", limit = WHEN_MISSING_LIMIT) { "'$it'" }
|
val list = it.joinToString(", ", limit = WHEN_MISSING_LIMIT) { "'$it'" }
|
||||||
val branches = if (it.size > 1) "branches" else "branch"
|
val branches = if (it.size > 1) "branches" else "branch"
|
||||||
"$list $branches or 'else' branch instead"
|
"$list $branches or 'else' branch instead"
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
"'else' branch"
|
"'else' branch"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmField val FQ_NAMES_IN_TYPES = DescriptorRenderer.FQ_NAMES_IN_TYPES.asRenderer()
|
@JvmField
|
||||||
@JvmField val COMPACT = DescriptorRenderer.COMPACT.asRenderer()
|
val FQ_NAMES_IN_TYPES = DescriptorRenderer.FQ_NAMES_IN_TYPES.asRenderer()
|
||||||
@JvmField val COMPACT_WITHOUT_SUPERTYPES = DescriptorRenderer.COMPACT_WITHOUT_SUPERTYPES.asRenderer()
|
@JvmField
|
||||||
@JvmField val WITHOUT_MODIFIERS = DescriptorRenderer.withOptions {
|
val COMPACT = DescriptorRenderer.COMPACT.asRenderer()
|
||||||
|
@JvmField
|
||||||
|
val COMPACT_WITHOUT_SUPERTYPES = DescriptorRenderer.COMPACT_WITHOUT_SUPERTYPES.asRenderer()
|
||||||
|
@JvmField
|
||||||
|
val WITHOUT_MODIFIERS = DescriptorRenderer.withOptions {
|
||||||
modifiers = emptySet()
|
modifiers = emptySet()
|
||||||
}.asRenderer()
|
}.asRenderer()
|
||||||
@JvmField val SHORT_NAMES_IN_TYPES = DescriptorRenderer.SHORT_NAMES_IN_TYPES.asRenderer()
|
@JvmField
|
||||||
@JvmField val COMPACT_WITH_MODIFIERS = DescriptorRenderer.COMPACT_WITH_MODIFIERS.asRenderer()
|
val SHORT_NAMES_IN_TYPES = DescriptorRenderer.SHORT_NAMES_IN_TYPES.asRenderer()
|
||||||
@JvmField val DEPRECATION_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.withOptions {
|
@JvmField
|
||||||
|
val COMPACT_WITH_MODIFIERS = DescriptorRenderer.COMPACT_WITH_MODIFIERS.asRenderer()
|
||||||
|
@JvmField
|
||||||
|
val DEPRECATION_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.withOptions {
|
||||||
withoutTypeParameters = false
|
withoutTypeParameters = false
|
||||||
receiverAfterName = false
|
receiverAfterName = false
|
||||||
renderAccessors = true
|
renderAccessors = true
|
||||||
|
|||||||
+8
-7
@@ -37,7 +37,7 @@ private class AdaptiveClassifierNamePolicy(private val ambiguousNames: List<Name
|
|||||||
return when {
|
return when {
|
||||||
hasUniqueName(classifier) -> ClassifierNamePolicy.SHORT.renderClassifier(classifier, renderer)
|
hasUniqueName(classifier) -> ClassifierNamePolicy.SHORT.renderClassifier(classifier, renderer)
|
||||||
classifier is ClassDescriptor ||
|
classifier is ClassDescriptor ||
|
||||||
classifier is TypeAliasDescriptor ->
|
classifier is TypeAliasDescriptor ->
|
||||||
ClassifierNamePolicy.FULLY_QUALIFIED.renderClassifier(classifier, renderer)
|
ClassifierNamePolicy.FULLY_QUALIFIED.renderClassifier(classifier, renderer)
|
||||||
classifier is TypeParameterDescriptor -> {
|
classifier is TypeParameterDescriptor -> {
|
||||||
val name = classifier.name
|
val name = classifier.name
|
||||||
@@ -55,7 +55,7 @@ private class AdaptiveClassifierNamePolicy(private val ambiguousNames: List<Name
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun DescriptorRenderer.renderAmbiguousTypeParameter(
|
private fun DescriptorRenderer.renderAmbiguousTypeParameter(
|
||||||
typeParameter: TypeParameterDescriptor, index: Int, firstOccurence: Boolean
|
typeParameter: TypeParameterDescriptor, index: Int, firstOccurence: Boolean
|
||||||
) = buildString {
|
) = buildString {
|
||||||
append(typeParameter.name)
|
append(typeParameter.name)
|
||||||
append("#$index")
|
append("#$index")
|
||||||
@@ -68,7 +68,7 @@ private class AdaptiveClassifierNamePolicy(private val ambiguousNames: List<Name
|
|||||||
private val ADAPTIVE_CLASSIFIER_POLICY_KEY = object : RenderingContext.Key<ClassifierNamePolicy>("ADAPTIVE_CLASSIFIER_POLICY") {
|
private val ADAPTIVE_CLASSIFIER_POLICY_KEY = object : RenderingContext.Key<ClassifierNamePolicy>("ADAPTIVE_CLASSIFIER_POLICY") {
|
||||||
override fun compute(objectsToRender: Collection<Any?>): ClassifierNamePolicy {
|
override fun compute(objectsToRender: Collection<Any?>): ClassifierNamePolicy {
|
||||||
val ambiguousNames =
|
val ambiguousNames =
|
||||||
collectClassifiersFqNames(objectsToRender).groupBy { it.shortNameOrSpecial() }.filter { it.value.size > 1 }.map { it.key }
|
collectClassifiersFqNames(objectsToRender).groupBy { it.shortNameOrSpecial() }.filter { it.value.size > 1 }.map { it.key }
|
||||||
return AdaptiveClassifierNamePolicy(ambiguousNames)
|
return AdaptiveClassifierNamePolicy(ambiguousNames)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,8 +83,7 @@ private fun collectMentionedClassifiersFqNames(contextObjects: Collection<Any?>,
|
|||||||
}
|
}
|
||||||
|
|
||||||
contextObjects.filterIsInstance<KotlinType>().forEach { diagnosticType ->
|
contextObjects.filterIsInstance<KotlinType>().forEach { diagnosticType ->
|
||||||
diagnosticType.contains {
|
diagnosticType.contains { innerType ->
|
||||||
innerType ->
|
|
||||||
innerType.addMentionedTypeConstructor()
|
innerType.addMentionedTypeConstructor()
|
||||||
innerType.getAbbreviation()?.addMentionedTypeConstructor()
|
innerType.getAbbreviation()?.addMentionedTypeConstructor()
|
||||||
false
|
false
|
||||||
@@ -101,12 +100,14 @@ private fun collectMentionedClassifiersFqNames(contextObjects: Collection<Any?>,
|
|||||||
collectMentionedClassifiersFqNames(it.upperBounds, result)
|
collectMentionedClassifiersFqNames(it.upperBounds, result)
|
||||||
}
|
}
|
||||||
contextObjects.filterIsInstance<CallableDescriptor>().forEach {
|
contextObjects.filterIsInstance<CallableDescriptor>().forEach {
|
||||||
collectMentionedClassifiersFqNames(listOf(
|
collectMentionedClassifiersFqNames(
|
||||||
|
listOf(
|
||||||
it.typeParameters,
|
it.typeParameters,
|
||||||
it.returnType,
|
it.returnType,
|
||||||
it.valueParameters,
|
it.valueParameters,
|
||||||
it.dispatchReceiverParameter?.type,
|
it.dispatchReceiverParameter?.type,
|
||||||
it.extensionReceiverParameter?.type
|
it.extensionReceiverParameter?.type
|
||||||
), result)
|
), result
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,9 +38,9 @@ import org.jetbrains.kotlin.types.expressions.LocalClassDescriptorHolder
|
|||||||
import org.jetbrains.kotlin.types.expressions.LocalLazyDeclarationResolver
|
import org.jetbrains.kotlin.types.expressions.LocalLazyDeclarationResolver
|
||||||
|
|
||||||
fun StorageComponentContainer.configureModule(
|
fun StorageComponentContainer.configureModule(
|
||||||
moduleContext: ModuleContext,
|
moduleContext: ModuleContext,
|
||||||
platform: TargetPlatform,
|
platform: TargetPlatform,
|
||||||
platformVersion: TargetPlatformVersion
|
platformVersion: TargetPlatformVersion
|
||||||
) {
|
) {
|
||||||
useInstance(moduleContext)
|
useInstance(moduleContext)
|
||||||
useInstance(moduleContext.module)
|
useInstance(moduleContext.module)
|
||||||
@@ -54,7 +54,7 @@ fun StorageComponentContainer.configureModule(
|
|||||||
platform.platformConfigurator.configureModuleComponents(this)
|
platform.platformConfigurator.configureModuleComponents(this)
|
||||||
|
|
||||||
for (extension in StorageComponentContainerContributor.getInstances(moduleContext.project)) {
|
for (extension in StorageComponentContainerContributor.getInstances(moduleContext.project)) {
|
||||||
extension.registerModuleComponents(this, platform, moduleContext.module)
|
extension.registerModuleComponents(this, platform, moduleContext.module)
|
||||||
}
|
}
|
||||||
|
|
||||||
configurePlatformIndependentComponents()
|
configurePlatformIndependentComponents()
|
||||||
@@ -66,22 +66,22 @@ private fun StorageComponentContainer.configurePlatformIndependentComponents() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun StorageComponentContainer.configureModule(
|
fun StorageComponentContainer.configureModule(
|
||||||
moduleContext: ModuleContext,
|
moduleContext: ModuleContext,
|
||||||
platform: TargetPlatform,
|
platform: TargetPlatform,
|
||||||
platformVersion: TargetPlatformVersion,
|
platformVersion: TargetPlatformVersion,
|
||||||
trace: BindingTrace
|
trace: BindingTrace
|
||||||
) {
|
) {
|
||||||
configureModule(moduleContext, platform, platformVersion)
|
configureModule(moduleContext, platform, platformVersion)
|
||||||
useInstance(trace)
|
useInstance(trace)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createContainerForBodyResolve(
|
fun createContainerForBodyResolve(
|
||||||
moduleContext: ModuleContext,
|
moduleContext: ModuleContext,
|
||||||
bindingTrace: BindingTrace,
|
bindingTrace: BindingTrace,
|
||||||
platform: TargetPlatform,
|
platform: TargetPlatform,
|
||||||
statementFilter: StatementFilter,
|
statementFilter: StatementFilter,
|
||||||
targetPlatformVersion: TargetPlatformVersion,
|
targetPlatformVersion: TargetPlatformVersion,
|
||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
): StorageComponentContainer = createContainer("BodyResolve", platform) {
|
): StorageComponentContainer = createContainer("BodyResolve", platform) {
|
||||||
configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
|
configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
|
||||||
|
|
||||||
@@ -95,13 +95,13 @@ fun createContainerForBodyResolve(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createContainerForLazyBodyResolve(
|
fun createContainerForLazyBodyResolve(
|
||||||
moduleContext: ModuleContext,
|
moduleContext: ModuleContext,
|
||||||
kotlinCodeAnalyzer: KotlinCodeAnalyzer,
|
kotlinCodeAnalyzer: KotlinCodeAnalyzer,
|
||||||
bindingTrace: BindingTrace,
|
bindingTrace: BindingTrace,
|
||||||
platform: TargetPlatform,
|
platform: TargetPlatform,
|
||||||
bodyResolveCache: BodyResolveCache,
|
bodyResolveCache: BodyResolveCache,
|
||||||
targetPlatformVersion: TargetPlatformVersion,
|
targetPlatformVersion: TargetPlatformVersion,
|
||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
): StorageComponentContainer = createContainer("LazyBodyResolve", platform) {
|
): StorageComponentContainer = createContainer("LazyBodyResolve", platform) {
|
||||||
configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
|
configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
|
||||||
|
|
||||||
@@ -115,14 +115,14 @@ fun createContainerForLazyBodyResolve(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createContainerForLazyLocalClassifierAnalyzer(
|
fun createContainerForLazyLocalClassifierAnalyzer(
|
||||||
moduleContext: ModuleContext,
|
moduleContext: ModuleContext,
|
||||||
bindingTrace: BindingTrace,
|
bindingTrace: BindingTrace,
|
||||||
platform: TargetPlatform,
|
platform: TargetPlatform,
|
||||||
lookupTracker: LookupTracker,
|
lookupTracker: LookupTracker,
|
||||||
targetPlatformVersion: TargetPlatformVersion,
|
targetPlatformVersion: TargetPlatformVersion,
|
||||||
languageVersionSettings: LanguageVersionSettings,
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
statementFilter: StatementFilter,
|
statementFilter: StatementFilter,
|
||||||
localClassDescriptorHolder: LocalClassDescriptorHolder
|
localClassDescriptorHolder: LocalClassDescriptorHolder
|
||||||
): StorageComponentContainer = createContainer("LocalClassifierAnalyzer", platform) {
|
): StorageComponentContainer = createContainer("LocalClassifierAnalyzer", platform) {
|
||||||
configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
|
configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
|
||||||
|
|
||||||
@@ -147,13 +147,13 @@ fun createContainerForLazyLocalClassifierAnalyzer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createContainerForLazyResolve(
|
fun createContainerForLazyResolve(
|
||||||
moduleContext: ModuleContext,
|
moduleContext: ModuleContext,
|
||||||
declarationProviderFactory: DeclarationProviderFactory,
|
declarationProviderFactory: DeclarationProviderFactory,
|
||||||
bindingTrace: BindingTrace,
|
bindingTrace: BindingTrace,
|
||||||
platform: TargetPlatform,
|
platform: TargetPlatform,
|
||||||
targetPlatformVersion: TargetPlatformVersion,
|
targetPlatformVersion: TargetPlatformVersion,
|
||||||
targetEnvironment: TargetEnvironment,
|
targetEnvironment: TargetEnvironment,
|
||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
): StorageComponentContainer = createContainer("LazyResolve", platform) {
|
): StorageComponentContainer = createContainer("LazyResolve", platform) {
|
||||||
configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
|
configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
|
||||||
|
|
||||||
@@ -168,12 +168,12 @@ fun createContainerForLazyResolve(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createLazyResolveSession(moduleContext: ModuleContext, files: Collection<KtFile>): ResolveSession =
|
fun createLazyResolveSession(moduleContext: ModuleContext, files: Collection<KtFile>): ResolveSession =
|
||||||
createContainerForLazyResolve(
|
createContainerForLazyResolve(
|
||||||
moduleContext,
|
moduleContext,
|
||||||
FileBasedDeclarationProviderFactory(moduleContext.storageManager, files),
|
FileBasedDeclarationProviderFactory(moduleContext.storageManager, files),
|
||||||
BindingTraceContext(),
|
BindingTraceContext(),
|
||||||
TargetPlatform.Common,
|
TargetPlatform.Common,
|
||||||
TargetPlatformVersion.NoVersion,
|
TargetPlatformVersion.NoVersion,
|
||||||
CompilerEnvironment,
|
CompilerEnvironment,
|
||||||
LanguageVersionSettingsImpl.DEFAULT
|
LanguageVersionSettingsImpl.DEFAULT
|
||||||
).get<ResolveSession>()
|
).get<ResolveSession>()
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ class MainFunctionDetector {
|
|||||||
/** Assumes that the function declaration is already resolved and the descriptor can be found in the `bindingContext`. */
|
/** Assumes that the function declaration is already resolved and the descriptor can be found in the `bindingContext`. */
|
||||||
constructor(bindingContext: BindingContext) {
|
constructor(bindingContext: BindingContext) {
|
||||||
this.getFunctionDescriptor = { function ->
|
this.getFunctionDescriptor = { function ->
|
||||||
bindingContext.get(BindingContext.FUNCTION, function) ?: throw IllegalStateException("No descriptor resolved for " + function + " " + function.text)
|
bindingContext.get(BindingContext.FUNCTION, function)
|
||||||
|
?: throw IllegalStateException("No descriptor resolved for " + function + " " + function.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -83,9 +84,9 @@ class MainFunctionDetector {
|
|||||||
private fun getMainFunction(module: ModuleDescriptor, packageView: PackageViewDescriptor): FunctionDescriptor? {
|
private fun getMainFunction(module: ModuleDescriptor, packageView: PackageViewDescriptor): FunctionDescriptor? {
|
||||||
for (packageFragment in packageView.fragments.filter { it.module == module }) {
|
for (packageFragment in packageView.fragments.filter { it.module == module }) {
|
||||||
DescriptorUtils.getAllDescriptors(packageFragment.getMemberScope())
|
DescriptorUtils.getAllDescriptors(packageFragment.getMemberScope())
|
||||||
.filterIsInstance<FunctionDescriptor>()
|
.filterIsInstance<FunctionDescriptor>()
|
||||||
.firstOrNull { isMain(it) }
|
.firstOrNull { isMain(it) }
|
||||||
?.let { return it }
|
?.let { return it }
|
||||||
}
|
}
|
||||||
|
|
||||||
for (subpackageName in module.getSubPackagesOf(packageView.fqName, MemberScope.ALL_NAME_FILTER)) {
|
for (subpackageName in module.getSubPackagesOf(packageView.fqName, MemberScope.ALL_NAME_FILTER)) {
|
||||||
@@ -108,7 +109,7 @@ class MainFunctionDetector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val parameters = descriptor.valueParameters.mapTo(mutableListOf()) { it.type }
|
val parameters = descriptor.valueParameters.mapTo(mutableListOf()) { it.type }
|
||||||
descriptor.extensionReceiverParameter?.type?.let {parameters += it}
|
descriptor.extensionReceiverParameter?.type?.let { parameters += it }
|
||||||
|
|
||||||
if (parameters.size != 1 || !descriptor.typeParameters.isEmpty()) return false
|
if (parameters.size != 1 || !descriptor.typeParameters.isEmpty()) return false
|
||||||
|
|
||||||
@@ -127,14 +128,14 @@ class MainFunctionDetector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val returnType = descriptor.returnType
|
val returnType = descriptor.returnType
|
||||||
if (returnType == null || !KotlinBuiltIns.isUnit(returnType)) return false
|
if (returnType == null || !KotlinBuiltIns.isUnit(returnType)) return false
|
||||||
|
|
||||||
if (DescriptorUtils.isTopLevelDeclaration(descriptor)) return true
|
if (DescriptorUtils.isTopLevelDeclaration(descriptor)) return true
|
||||||
|
|
||||||
val containingDeclaration = descriptor.containingDeclaration
|
val containingDeclaration = descriptor.containingDeclaration
|
||||||
return containingDeclaration is ClassDescriptor
|
return containingDeclaration is ClassDescriptor
|
||||||
&& containingDeclaration.kind.isSingleton
|
&& containingDeclaration.kind.isSingleton
|
||||||
&& (descriptor.hasJvmStaticAnnotation() || !checkJvmStaticAnnotation)
|
&& (descriptor.hasJvmStaticAnnotation() || !checkJvmStaticAnnotation)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getJVMFunctionName(functionDescriptor: FunctionDescriptor): String {
|
private fun getJVMFunctionName(functionDescriptor: FunctionDescriptor): String {
|
||||||
|
|||||||
@@ -29,14 +29,17 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
|||||||
*/
|
*/
|
||||||
class KDocLinkParser : PsiParser {
|
class KDocLinkParser : PsiParser {
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic fun parseMarkdownLink(root: IElementType, chameleon: ASTNode): ASTNode {
|
@JvmStatic
|
||||||
|
fun parseMarkdownLink(root: IElementType, chameleon: ASTNode): ASTNode {
|
||||||
val parentElement = chameleon.treeParent.psi
|
val parentElement = chameleon.treeParent.psi
|
||||||
val project = parentElement.project
|
val project = parentElement.project
|
||||||
val builder = PsiBuilderFactory.getInstance().createBuilder(project,
|
val builder = PsiBuilderFactory.getInstance().createBuilder(
|
||||||
chameleon,
|
project,
|
||||||
KotlinLexer(),
|
chameleon,
|
||||||
root.language,
|
KotlinLexer(),
|
||||||
chameleon.text)
|
root.language,
|
||||||
|
chameleon.text
|
||||||
|
)
|
||||||
val parser = KDocLinkParser()
|
val parser = KDocLinkParser()
|
||||||
|
|
||||||
return parser.parse(root, builder).firstChildNode
|
return parser.parse(root, builder).firstChildNode
|
||||||
@@ -60,8 +63,7 @@ class KDocLinkParser : PsiParser {
|
|||||||
if (builder.tokenType == KtTokens.RBRACKET) {
|
if (builder.tokenType == KtTokens.RBRACKET) {
|
||||||
builder.advanceLexer()
|
builder.advanceLexer()
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (!builder.eof()) {
|
if (!builder.eof()) {
|
||||||
builder.error("Expression expected")
|
builder.error("Expression expected")
|
||||||
while (!builder.eof()) {
|
while (!builder.eof()) {
|
||||||
|
|||||||
@@ -32,18 +32,17 @@ class KDocSection(node: ASTNode) : KDocTag(node) {
|
|||||||
* or null for the default section).
|
* or null for the default section).
|
||||||
*/
|
*/
|
||||||
override fun getName(): String? =
|
override fun getName(): String? =
|
||||||
(firstChild as? KDocTag)?.name
|
(firstChild as? KDocTag)?.name
|
||||||
|
|
||||||
override fun getSubjectName(): String? =
|
override fun getSubjectName(): String? =
|
||||||
(firstChild as? KDocTag)?.getSubjectName()
|
(firstChild as? KDocTag)?.getSubjectName()
|
||||||
|
|
||||||
override fun getContent(): String =
|
override fun getContent(): String =
|
||||||
(firstChild as? KDocTag)?.getContent() ?: super.getContent()
|
(firstChild as? KDocTag)?.getContent() ?: super.getContent()
|
||||||
|
|
||||||
fun findTagsByName(name: String): List<KDocTag> {
|
fun findTagsByName(name: String): List<KDocTag> {
|
||||||
return getChildrenOfType<KDocTag>().filter { it.name == name }
|
return getChildrenOfType<KDocTag>().filter { it.name == name }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun findTagByName(name: String): KDocTag?
|
fun findTagByName(name: String): KDocTag? = findTagsByName(name).firstOrNull()
|
||||||
= findTagsByName(name).firstOrNull()
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,9 +67,9 @@ open class KDocTag(node: ASTNode) : KDocElementImpl(node) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun childrenAfterTagName(): List<ASTNode> =
|
private fun childrenAfterTagName(): List<ASTNode> =
|
||||||
node.getChildren(null)
|
node.getChildren(null)
|
||||||
.dropWhile { it.elementType == KDocTokens.TAG_NAME }
|
.dropWhile { it.elementType == KDocTokens.TAG_NAME }
|
||||||
.dropWhile { it.elementType == TokenType.WHITE_SPACE }
|
.dropWhile { it.elementType == TokenType.WHITE_SPACE }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the content of this tag (all text following the tag name and the subject if present,
|
* Returns the content of this tag (all text following the tag name and the subject if present,
|
||||||
@@ -109,8 +109,7 @@ open class KDocTag(node: ASTNode) : KDocElementImpl(node) {
|
|||||||
if (!isCodeBlock())
|
if (!isCodeBlock())
|
||||||
indentedCodeBlock = indentedCodeBlock || node.text.startsWith(indentationWhiteSpaces) || node.text.startsWith("\t")
|
indentedCodeBlock = indentedCodeBlock || node.text.startsWith(indentationWhiteSpaces) || node.text.startsWith("\t")
|
||||||
startCodeBlock()
|
startCodeBlock()
|
||||||
}
|
} else if (KDocTokens.CONTENT_TOKENS.contains(type)) {
|
||||||
else if (KDocTokens.CONTENT_TOKENS.contains(type)) {
|
|
||||||
flushCodeBlock()
|
flushCodeBlock()
|
||||||
indentedCodeBlock = false
|
indentedCodeBlock = false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -63,7 +63,9 @@ class KotlinParserDefinition : ParserDefinition {
|
|||||||
|
|
||||||
return when (elementType) {
|
return when (elementType) {
|
||||||
is KtStubElementType<*, *> -> elementType.createPsiFromAst(astNode)
|
is KtStubElementType<*, *> -> elementType.createPsiFromAst(astNode)
|
||||||
KtNodeTypes.TYPE_CODE_FRAGMENT, KtNodeTypes.EXPRESSION_CODE_FRAGMENT, KtNodeTypes.BLOCK_CODE_FRAGMENT -> ASTWrapperPsiElement(astNode)
|
KtNodeTypes.TYPE_CODE_FRAGMENT, KtNodeTypes.EXPRESSION_CODE_FRAGMENT, KtNodeTypes.BLOCK_CODE_FRAGMENT -> ASTWrapperPsiElement(
|
||||||
|
astNode
|
||||||
|
)
|
||||||
is KDocElementType -> elementType.createPsi(astNode)
|
is KDocElementType -> elementType.createPsi(astNode)
|
||||||
KDocTokens.MARKDOWN_LINK -> KDocLink(astNode)
|
KDocTokens.MARKDOWN_LINK -> KDocLink(astNode)
|
||||||
else -> (elementType as KtNodeType).createPsi(astNode)
|
else -> (elementType as KtNodeType).createPsi(astNode)
|
||||||
|
|||||||
+15
-8
@@ -23,7 +23,8 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
|||||||
|
|
||||||
object PrecedingCommentsBinder : WhitespacesAndCommentsBinder {
|
object PrecedingCommentsBinder : WhitespacesAndCommentsBinder {
|
||||||
override fun getEdgePosition(
|
override fun getEdgePosition(
|
||||||
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int {
|
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter
|
||||||
|
): Int {
|
||||||
if (tokens.isEmpty()) return 0
|
if (tokens.isEmpty()) return 0
|
||||||
|
|
||||||
// 1. bind doc comment
|
// 1. bind doc comment
|
||||||
@@ -44,7 +45,7 @@ object PrecedingCommentsBinder : WhitespacesAndCommentsBinder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> break@tokens
|
else -> break@tokens
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +55,8 @@ object PrecedingCommentsBinder : WhitespacesAndCommentsBinder {
|
|||||||
|
|
||||||
object PrecedingDocCommentsBinder : WhitespacesAndCommentsBinder {
|
object PrecedingDocCommentsBinder : WhitespacesAndCommentsBinder {
|
||||||
override fun getEdgePosition(
|
override fun getEdgePosition(
|
||||||
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int {
|
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter
|
||||||
|
): Int {
|
||||||
if (tokens.isEmpty()) return 0
|
if (tokens.isEmpty()) return 0
|
||||||
|
|
||||||
for (idx in tokens.indices.reversed()) {
|
for (idx in tokens.indices.reversed()) {
|
||||||
@@ -68,7 +70,8 @@ object PrecedingDocCommentsBinder : WhitespacesAndCommentsBinder {
|
|||||||
// Binds comments on the same line
|
// Binds comments on the same line
|
||||||
object TrailingCommentsBinder : WhitespacesAndCommentsBinder {
|
object TrailingCommentsBinder : WhitespacesAndCommentsBinder {
|
||||||
override fun getEdgePosition(
|
override fun getEdgePosition(
|
||||||
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int {
|
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter
|
||||||
|
): Int {
|
||||||
if (tokens.isEmpty()) return 0
|
if (tokens.isEmpty()) return 0
|
||||||
|
|
||||||
var result = 0
|
var result = 0
|
||||||
@@ -89,7 +92,8 @@ object TrailingCommentsBinder : WhitespacesAndCommentsBinder {
|
|||||||
|
|
||||||
private class AllCommentsBinder(val isTrailing: Boolean) : WhitespacesAndCommentsBinder {
|
private class AllCommentsBinder(val isTrailing: Boolean) : WhitespacesAndCommentsBinder {
|
||||||
override fun getEdgePosition(
|
override fun getEdgePosition(
|
||||||
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int {
|
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter
|
||||||
|
): Int {
|
||||||
if (tokens.isEmpty()) return 0
|
if (tokens.isEmpty()) return 0
|
||||||
|
|
||||||
val size = tokens.size
|
val size = tokens.size
|
||||||
@@ -110,14 +114,16 @@ val TRAILING_ALL_COMMENTS_BINDER: WhitespacesAndCommentsBinder = AllCommentsBind
|
|||||||
|
|
||||||
object DoNotBindAnything : WhitespacesAndCommentsBinder {
|
object DoNotBindAnything : WhitespacesAndCommentsBinder {
|
||||||
override fun getEdgePosition(
|
override fun getEdgePosition(
|
||||||
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int {
|
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter
|
||||||
|
): Int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object BindFirstShebangWithWhitespaceOnly : WhitespacesAndCommentsBinder {
|
object BindFirstShebangWithWhitespaceOnly : WhitespacesAndCommentsBinder {
|
||||||
override fun getEdgePosition(
|
override fun getEdgePosition(
|
||||||
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int {
|
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter
|
||||||
|
): Int {
|
||||||
if (tokens.firstOrNull() == KtTokens.SHEBANG_COMMENT) {
|
if (tokens.firstOrNull() == KtTokens.SHEBANG_COMMENT) {
|
||||||
return if (tokens.getOrNull(1) == KtTokens.WHITE_SPACE) 2 else 1
|
return if (tokens.getOrNull(1) == KtTokens.WHITE_SPACE) 2 else 1
|
||||||
}
|
}
|
||||||
@@ -128,7 +134,8 @@ object BindFirstShebangWithWhitespaceOnly : WhitespacesAndCommentsBinder {
|
|||||||
|
|
||||||
class BindAll(val isTrailing: Boolean) : WhitespacesAndCommentsBinder {
|
class BindAll(val isTrailing: Boolean) : WhitespacesAndCommentsBinder {
|
||||||
override fun getEdgePosition(
|
override fun getEdgePosition(
|
||||||
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int {
|
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter
|
||||||
|
): Int {
|
||||||
return if (!isTrailing) 0 else tokens.size
|
return if (!isTrailing) 0 else tokens.size
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import gnu.trove.TIntArrayList
|
|||||||
import org.jetbrains.kotlin.psi.psiUtil.getContentRange
|
import org.jetbrains.kotlin.psi.psiUtil.getContentRange
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.isSingleQuoted
|
import org.jetbrains.kotlin.psi.psiUtil.isSingleQuoted
|
||||||
|
|
||||||
class KotlinStringLiteralTextEscaper(host: KtStringTemplateExpression): LiteralTextEscaper<KtStringTemplateExpression>(host) {
|
class KotlinStringLiteralTextEscaper(host: KtStringTemplateExpression) : LiteralTextEscaper<KtStringTemplateExpression>(host) {
|
||||||
private var sourceOffsets: IntArray? = null
|
private var sourceOffsets: IntArray? = null
|
||||||
|
|
||||||
override fun decode(rangeInsideHost: TextRange, outChars: StringBuilder): Boolean {
|
override fun decode(rangeInsideHost: TextRange, outChars: StringBuilder): Boolean {
|
||||||
|
|||||||
+2
-2
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
|||||||
// This node represents "fake" reference expression for ENUM_ENTRY(arguments) constructor syntax
|
// This node represents "fake" reference expression for ENUM_ENTRY(arguments) constructor syntax
|
||||||
// It uses the superclass enum node to provide access to the real constructor name
|
// It uses the superclass enum node to provide access to the real constructor name
|
||||||
class KtEnumEntrySuperclassReferenceExpression :
|
class KtEnumEntrySuperclassReferenceExpression :
|
||||||
KtExpressionImplStub<KotlinEnumEntrySuperclassReferenceExpressionStub>, KtSimpleNameExpression {
|
KtExpressionImplStub<KotlinEnumEntrySuperclassReferenceExpressionStub>, KtSimpleNameExpression {
|
||||||
|
|
||||||
constructor(node: ASTNode) : super(node)
|
constructor(node: ASTNode) : super(node)
|
||||||
|
|
||||||
@@ -37,7 +37,7 @@ class KtEnumEntrySuperclassReferenceExpression :
|
|||||||
|
|
||||||
// It is the owner enum class (not an enum entry but the whole enum)
|
// It is the owner enum class (not an enum entry but the whole enum)
|
||||||
private val referencedElement: KtClass
|
private val referencedElement: KtClass
|
||||||
get() = calcReferencedElement()!!
|
get() = calcReferencedElement()!!
|
||||||
|
|
||||||
private fun calcReferencedElement(): KtClass? {
|
private fun calcReferencedElement(): KtClass? {
|
||||||
val owner = this.getStrictParentOfType<KtEnumEntry>()
|
val owner = this.getStrictParentOfType<KtEnumEntry>()
|
||||||
|
|||||||
@@ -35,7 +35,8 @@ abstract class KtExpressionImpl(node: ASTNode) : KtElementImpl(node), KtExpressi
|
|||||||
}
|
}
|
||||||
is KtSimpleNameStringTemplateEntry -> {
|
is KtSimpleNameStringTemplateEntry -> {
|
||||||
if (newElement !is KtSimpleNameExpression && !newElement.isThisWithoutLabel()) {
|
if (newElement !is KtSimpleNameExpression && !newElement.isThisWithoutLabel()) {
|
||||||
val newEntry = parent.replace(KtPsiFactory(expression).createBlockStringTemplateEntry(newElement)) as KtBlockStringTemplateEntry
|
val newEntry =
|
||||||
|
parent.replace(KtPsiFactory(expression).createBlockStringTemplateEntry(newElement)) as KtBlockStringTemplateEntry
|
||||||
return newEntry.expression!!
|
return newEntry.expression!!
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ class KtPrimaryConstructor : KtConstructor<KtPrimaryConstructor> {
|
|||||||
if (this.modifierList == null) {
|
if (this.modifierList == null) {
|
||||||
getConstructorKeyword()?.delete()
|
getConstructorKeyword()?.delete()
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (modifier == KtTokens.PUBLIC_KEYWORD) return
|
if (modifier == KtTokens.PUBLIC_KEYWORD) return
|
||||||
val newModifierList = KtPsiFactory(this).createModifierList(modifier)
|
val newModifierList = KtPsiFactory(this).createModifierList(modifier)
|
||||||
addBefore(newModifierList, getOrCreateConstructorKeyword())
|
addBefore(newModifierList, getOrCreateConstructorKeyword())
|
||||||
@@ -62,8 +61,7 @@ class KtPrimaryConstructor : KtConstructor<KtPrimaryConstructor> {
|
|||||||
val modifierList = modifierList
|
val modifierList = modifierList
|
||||||
return if (modifierList != null) {
|
return if (modifierList != null) {
|
||||||
modifierList.addBefore(annotationEntry, modifierList.firstChild) as KtAnnotationEntry
|
modifierList.addBefore(annotationEntry, modifierList.firstChild) as KtAnnotationEntry
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val parameterList = valueParameterList!!
|
val parameterList = valueParameterList!!
|
||||||
val newModifierList = KtPsiFactory(project).createModifierList(annotationEntry.text)
|
val newModifierList = KtPsiFactory(project).createModifierList(annotationEntry.text)
|
||||||
(addBefore(newModifierList, parameterList) as KtModifierList).annotationEntries.first()
|
(addBefore(newModifierList, parameterList) as KtModifierList).annotationEntries.first()
|
||||||
|
|||||||
@@ -26,10 +26,11 @@ import org.jetbrains.kotlin.resolve.TargetPlatform
|
|||||||
fun KtPsiFactory(project: Project?, markGenerated: Boolean = true): KtPsiFactory = KtPsiFactory(project!!, markGenerated)
|
fun KtPsiFactory(project: Project?, markGenerated: Boolean = true): KtPsiFactory = KtPsiFactory(project!!, markGenerated)
|
||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun KtPsiFactory(elementForProject: PsiElement, markGenerated: Boolean = true): KtPsiFactory = KtPsiFactory(elementForProject.project, markGenerated)
|
fun KtPsiFactory(elementForProject: PsiElement, markGenerated: Boolean = true): KtPsiFactory =
|
||||||
|
KtPsiFactory(elementForProject.project, markGenerated)
|
||||||
|
|
||||||
private val DO_NOT_ANALYZE_NOTIFICATION = "This file was created by KtPsiFactory and should not be analyzed\n" +
|
private val DO_NOT_ANALYZE_NOTIFICATION = "This file was created by KtPsiFactory and should not be analyzed\n" +
|
||||||
"Use createAnalyzableFile to create file that can be analyzed\n"
|
"Use createAnalyzableFile to create file that can be analyzed\n"
|
||||||
|
|
||||||
var KtFile.doNotAnalyze: String? by UserDataProperty(Key.create("DO_NOT_ANALYZE"))
|
var KtFile.doNotAnalyze: String? by UserDataProperty(Key.create("DO_NOT_ANALYZE"))
|
||||||
var KtFile.analysisContext: PsiElement? by UserDataProperty(Key.create("ANALYSIS_CONTEXT"))
|
var KtFile.analysisContext: PsiElement? by UserDataProperty(Key.create("ANALYSIS_CONTEXT"))
|
||||||
@@ -72,7 +73,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createThisExpression() =
|
fun createThisExpression() =
|
||||||
(createExpression("this.x") as KtQualifiedExpression).receiverExpression as KtThisExpression
|
(createExpression("this.x") as KtQualifiedExpression).receiverExpression as KtThisExpression
|
||||||
|
|
||||||
fun createThisExpression(qualifier: String) =
|
fun createThisExpression(qualifier: String) =
|
||||||
(createExpression("this@$qualifier.x") as KtQualifiedExpression).receiverExpression as KtThisExpression
|
(createExpression("this@$qualifier.x") as KtQualifiedExpression).receiverExpression as KtThisExpression
|
||||||
@@ -109,7 +110,8 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createFunctionTypeParameter(typeReference: KtTypeReference): KtParameter {
|
fun createFunctionTypeParameter(typeReference: KtTypeReference): KtParameter {
|
||||||
return (createType("(A) -> B").typeElement as KtFunctionType).parameters.first().apply { this.typeReference!!.replace(typeReference) }
|
return (createType("(A) -> B").typeElement as KtFunctionType).parameters.first()
|
||||||
|
.apply { this.typeReference!!.replace(typeReference) }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createTypeAlias(name: String, typeParameters: List<String>, typeElement: KtTypeElement): KtTypeAlias {
|
fun createTypeAlias(name: String, typeParameters: List<String>, typeElement: KtTypeElement): KtTypeAlias {
|
||||||
@@ -184,7 +186,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
|||||||
return createFileAnnotationListWithAnnotation(annotationText).annotationEntries.first()
|
return createFileAnnotationListWithAnnotation(annotationText).annotationEntries.first()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createFileAnnotationListWithAnnotation(annotationText: String) : KtFileAnnotationList {
|
fun createFileAnnotationListWithAnnotation(annotationText: String): KtFileAnnotationList {
|
||||||
return createFile("@file:$annotationText").fileAnnotationList!!
|
return createFile("@file:$annotationText").fileAnnotationList!!
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +195,14 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun doCreateFile(fileName: String, text: String): KtFile {
|
private fun doCreateFile(fileName: String, text: String): KtFile {
|
||||||
return PsiFileFactory.getInstance(project).createFileFromText(fileName, KotlinFileType.INSTANCE, text, LocalTimeCounter.currentTime(), false, markGenerated) as KtFile
|
return PsiFileFactory.getInstance(project).createFileFromText(
|
||||||
|
fileName,
|
||||||
|
KotlinFileType.INSTANCE,
|
||||||
|
text,
|
||||||
|
LocalTimeCounter.currentTime(),
|
||||||
|
false,
|
||||||
|
markGenerated
|
||||||
|
) as KtFile
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createFile(fileName: String, text: String): KtFile {
|
fun createFile(fileName: String, text: String): KtFile {
|
||||||
@@ -217,13 +226,19 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createPhysicalFile(fileName: String, text: String): KtFile {
|
fun createPhysicalFile(fileName: String, text: String): KtFile {
|
||||||
return PsiFileFactory.getInstance(project).createFileFromText(fileName, KotlinFileType.INSTANCE, text, LocalTimeCounter.currentTime(), true) as KtFile
|
return PsiFileFactory.getInstance(project).createFileFromText(
|
||||||
|
fileName,
|
||||||
|
KotlinFileType.INSTANCE,
|
||||||
|
text,
|
||||||
|
LocalTimeCounter.currentTime(),
|
||||||
|
true
|
||||||
|
) as KtFile
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createProperty(modifiers: String?, name: String, type: String?, isVar: Boolean, initializer: String?): KtProperty {
|
fun createProperty(modifiers: String?, name: String, type: String?, isVar: Boolean, initializer: String?): KtProperty {
|
||||||
val text = modifiers.let { "$it "} +
|
val text = modifiers.let { "$it " } +
|
||||||
(if (isVar) " var " else " val ") + name +
|
(if (isVar) " var " else " val ") + name +
|
||||||
(if (type != null) ":" + type else "") + (if (initializer == null) "" else " = " + initializer)
|
(if (type != null) ":" + type else "") + (if (initializer == null) "" else " = " + initializer)
|
||||||
return createProperty(text)
|
return createProperty(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +348,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
|||||||
return createClass("class A(){}").getBody()!!
|
return createClass("class A(){}").getBody()!!
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createParameter(text : String): KtParameter {
|
fun createParameter(text: String): KtParameter {
|
||||||
return createClass("class A($text)").primaryConstructorParameters.first()
|
return createClass("class A($text)").primaryConstructorParameters.first()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,13 +361,13 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
|||||||
fun createTypeParameter(text: String) = createTypeParameterList("<$text>").parameters.first()!!
|
fun createTypeParameter(text: String) = createTypeParameterList("<$text>").parameters.first()!!
|
||||||
|
|
||||||
fun createLambdaParameterListIfAny(text: String) =
|
fun createLambdaParameterListIfAny(text: String) =
|
||||||
createLambdaExpression(text, "0").functionLiteral.valueParameterList
|
createLambdaExpression(text, "0").functionLiteral.valueParameterList
|
||||||
|
|
||||||
fun createLambdaParameterList(text: String) = createLambdaParameterListIfAny(text)!!
|
fun createLambdaParameterList(text: String) = createLambdaParameterListIfAny(text)!!
|
||||||
|
|
||||||
fun createLambdaExpression(parameters: String, body: String): KtLambdaExpression =
|
fun createLambdaExpression(parameters: String, body: String): KtLambdaExpression =
|
||||||
(if (parameters.isNotEmpty()) createExpression("{ $parameters -> $body }")
|
(if (parameters.isNotEmpty()) createExpression("{ $parameters -> $body }")
|
||||||
else createExpression("{ $body }")) as KtLambdaExpression
|
else createExpression("{ $body }")) as KtLambdaExpression
|
||||||
|
|
||||||
|
|
||||||
fun createEnumEntry(text: String): KtEnumEntry {
|
fun createEnumEntry(text: String): KtEnumEntry {
|
||||||
@@ -404,7 +419,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
|||||||
throw IllegalArgumentException("import path must not be empty")
|
throw IllegalArgumentException("import path must not be empty")
|
||||||
}
|
}
|
||||||
|
|
||||||
val file = createFile(buildString { appendImport (importPath) })
|
val file = createFile(buildString { appendImport(importPath) })
|
||||||
return file.importDirectives.first()
|
return file.importDirectives.first()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,7 +450,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createPrimaryConstructor(text: String = ""): KtPrimaryConstructor {
|
fun createPrimaryConstructor(text: String = ""): KtPrimaryConstructor {
|
||||||
return createClass(if (text.isNotEmpty())"class A $text" else "class A()" ).primaryConstructor!!
|
return createClass(if (text.isNotEmpty()) "class A $text" else "class A()").primaryConstructor!!
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createPrimaryConstructorWithModifiers(modifiers: String?): KtPrimaryConstructor {
|
fun createPrimaryConstructorWithModifiers(modifiers: String?): KtPrimaryConstructor {
|
||||||
@@ -443,10 +458,9 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createConstructorKeyword(): PsiElement =
|
fun createConstructorKeyword(): PsiElement =
|
||||||
createClass("class A constructor()").primaryConstructor!!.getConstructorKeyword()!!
|
createClass("class A constructor()").primaryConstructor!!.getConstructorKeyword()!!
|
||||||
|
|
||||||
fun createLabeledExpression(labelName: String): KtLabeledExpression
|
fun createLabeledExpression(labelName: String): KtLabeledExpression = createExpression("$labelName@ 1") as KtLabeledExpression
|
||||||
= createExpression("$labelName@ 1") as KtLabeledExpression
|
|
||||||
|
|
||||||
fun createTypeCodeFragment(text: String, context: PsiElement?): KtTypeCodeFragment {
|
fun createTypeCodeFragment(text: String, context: PsiElement?): KtTypeCodeFragment {
|
||||||
return KtTypeCodeFragment(project, "fragment.kt", text, context)
|
return KtTypeCodeFragment(project, "fragment.kt", text, context)
|
||||||
@@ -512,6 +526,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
|||||||
TYPE_CONSTRAINTS,
|
TYPE_CONSTRAINTS,
|
||||||
DONE
|
DONE
|
||||||
}
|
}
|
||||||
|
|
||||||
private val sb = StringBuilder()
|
private val sb = StringBuilder()
|
||||||
private var state = State.MODIFIERS
|
private var state = State.MODIFIERS
|
||||||
|
|
||||||
@@ -820,7 +835,8 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
|||||||
return BlockWrapper(block, expression)
|
return BlockWrapper(block, expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
private class BlockWrapper(fakeBlockExpression: KtBlockExpression, private val expression: KtExpression) : KtBlockExpression(fakeBlockExpression.node), KtPsiUtil.KtExpressionWrapper {
|
private class BlockWrapper(fakeBlockExpression: KtBlockExpression, private val expression: KtExpression) :
|
||||||
|
KtBlockExpression(fakeBlockExpression.node), KtPsiUtil.KtExpressionWrapper {
|
||||||
override fun getStatements(): List<KtExpression> {
|
override fun getStatements(): List<KtExpression> {
|
||||||
return listOf(expression)
|
return listOf(expression)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -30,22 +30,22 @@ class KtTypeAlias : KtTypeParameterListOwnerStub<KotlinTypeAliasStub>, KtNamedDe
|
|||||||
constructor(stub: KotlinTypeAliasStub) : super(stub, KtStubElementTypes.TYPEALIAS)
|
constructor(stub: KotlinTypeAliasStub) : super(stub, KtStubElementTypes.TYPEALIAS)
|
||||||
|
|
||||||
override fun <R, D> accept(visitor: KtVisitor<R, D>, data: D): R =
|
override fun <R, D> accept(visitor: KtVisitor<R, D>, data: D): R =
|
||||||
visitor.visitTypeAlias(this, data)
|
visitor.visitTypeAlias(this, data)
|
||||||
|
|
||||||
fun isTopLevel(): Boolean =
|
fun isTopLevel(): Boolean =
|
||||||
stub?.isTopLevel() ?: parent is KtFile
|
stub?.isTopLevel() ?: parent is KtFile
|
||||||
|
|
||||||
@IfNotParsed
|
@IfNotParsed
|
||||||
fun getTypeAliasKeyword(): PsiElement? =
|
fun getTypeAliasKeyword(): PsiElement? =
|
||||||
findChildByType(KtTokens.TYPE_ALIAS_KEYWORD)
|
findChildByType(KtTokens.TYPE_ALIAS_KEYWORD)
|
||||||
|
|
||||||
@IfNotParsed
|
@IfNotParsed
|
||||||
fun getTypeReference(): KtTypeReference? {
|
fun getTypeReference(): KtTypeReference? {
|
||||||
return if (stub != null) {
|
return if (stub != null) {
|
||||||
val typeReferences = getStubOrPsiChildrenAsList<KtTypeReference, KotlinPlaceHolderStub<KtTypeReference>>(KtStubElementTypes.TYPE_REFERENCE)
|
val typeReferences =
|
||||||
|
getStubOrPsiChildrenAsList<KtTypeReference, KotlinPlaceHolderStub<KtTypeReference>>(KtStubElementTypes.TYPE_REFERENCE)
|
||||||
typeReferences[0]
|
typeReferences[0]
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
findChildByType(KtNodeTypes.TYPE_REFERENCE)
|
findChildByType(KtNodeTypes.TYPE_REFERENCE)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,10 +21,10 @@ import com.intellij.psi.PsiElement
|
|||||||
import org.jetbrains.kotlin.KtNodeTypes
|
import org.jetbrains.kotlin.KtNodeTypes
|
||||||
|
|
||||||
class KtTypeCodeFragment(
|
class KtTypeCodeFragment(
|
||||||
project: Project,
|
project: Project,
|
||||||
name: String,
|
name: String,
|
||||||
text: CharSequence,
|
text: CharSequence,
|
||||||
context: PsiElement?
|
context: PsiElement?
|
||||||
) : KtCodeFragment(project, name, text, null, KtNodeTypes.TYPE_CODE_FRAGMENT, context) {
|
) : KtCodeFragment(project, name, text, null, KtNodeTypes.TYPE_CODE_FRAGMENT, context) {
|
||||||
override fun getContentElement() = findChildByClass(KtTypeReference::class.java)
|
override fun getContentElement() = findChildByClass(KtTypeReference::class.java)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,9 +26,9 @@ import org.jetbrains.kotlin.psi.psiUtil.siblings
|
|||||||
|
|
||||||
private fun KtModifierListOwner.addModifierList(newModifierList: KtModifierList): KtModifierList {
|
private fun KtModifierListOwner.addModifierList(newModifierList: KtModifierList): KtModifierList {
|
||||||
val anchor = firstChild!!
|
val anchor = firstChild!!
|
||||||
.siblings(forward = true)
|
.siblings(forward = true)
|
||||||
.dropWhile { it is PsiComment || it is PsiWhiteSpace }
|
.dropWhile { it is PsiComment || it is PsiWhiteSpace }
|
||||||
.first()
|
.first()
|
||||||
return addBefore(newModifierList, anchor) as KtModifierList
|
return addBefore(newModifierList, anchor) as KtModifierList
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -40,8 +40,7 @@ fun KtModifierListOwner.setModifierList(newModifierList: KtModifierList) {
|
|||||||
val currentModifierList = modifierList
|
val currentModifierList = modifierList
|
||||||
if (currentModifierList != null) {
|
if (currentModifierList != null) {
|
||||||
currentModifierList.replace(newModifierList)
|
currentModifierList.replace(newModifierList)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
addModifierList(newModifierList)
|
addModifierList(newModifierList)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,8 +49,7 @@ fun addModifier(owner: KtModifierListOwner, modifier: KtModifierKeywordToken) {
|
|||||||
val modifierList = owner.modifierList
|
val modifierList = owner.modifierList
|
||||||
if (modifierList == null) {
|
if (modifierList == null) {
|
||||||
createModifierList(modifier.value, owner)
|
createModifierList(modifier.value, owner)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
addModifier(modifierList, modifier)
|
addModifier(modifierList, modifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -60,8 +58,7 @@ fun addAnnotationEntry(owner: KtModifierListOwner, annotationEntry: KtAnnotation
|
|||||||
val modifierList = owner.modifierList
|
val modifierList = owner.modifierList
|
||||||
return if (modifierList == null) {
|
return if (modifierList == null) {
|
||||||
createModifierList(annotationEntry.text, owner).annotationEntries.first()
|
createModifierList(annotationEntry.text, owner).annotationEntries.first()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
modifierList.addBefore(annotationEntry, modifierList.firstChild) as KtAnnotationEntry
|
modifierList.addBefore(annotationEntry, modifierList.firstChild) as KtAnnotationEntry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,8 +68,8 @@ internal fun addModifier(modifierList: KtModifierList, modifier: KtModifierKeywo
|
|||||||
|
|
||||||
val newModifier = KtPsiFactory(modifierList).createModifier(modifier)
|
val newModifier = KtPsiFactory(modifierList).createModifier(modifier)
|
||||||
val modifierToReplace = MODIFIERS_TO_REPLACE[modifier]
|
val modifierToReplace = MODIFIERS_TO_REPLACE[modifier]
|
||||||
?.mapNotNull { modifierList.getModifier(it) }
|
?.mapNotNull { modifierList.getModifier(it) }
|
||||||
?.firstOrNull()
|
?.firstOrNull()
|
||||||
|
|
||||||
if (modifier == FINAL_KEYWORD && !modifierList.hasModifier(OVERRIDE_KEYWORD)) {
|
if (modifier == FINAL_KEYWORD && !modifierList.hasModifier(OVERRIDE_KEYWORD)) {
|
||||||
if (modifierToReplace != null) {
|
if (modifierToReplace != null) {
|
||||||
@@ -85,8 +82,7 @@ internal fun addModifier(modifierList: KtModifierList, modifier: KtModifierKeywo
|
|||||||
}
|
}
|
||||||
if (modifierToReplace != null && modifierList.firstChild == modifierList.lastChild) {
|
if (modifierToReplace != null && modifierList.firstChild == modifierList.lastChild) {
|
||||||
modifierToReplace.replace(newModifier)
|
modifierToReplace.replace(newModifier)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
modifierToReplace?.delete()
|
modifierToReplace?.delete()
|
||||||
val newModifierOrder = MODIFIERS_ORDER.indexOf(modifier)
|
val newModifierOrder = MODIFIERS_ORDER.indexOf(modifier)
|
||||||
|
|
||||||
@@ -129,34 +125,36 @@ fun sortModifiers(modifiers: List<KtModifierKeywordToken>): List<KtModifierKeywo
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val MODIFIERS_TO_REPLACE = mapOf(
|
private val MODIFIERS_TO_REPLACE = mapOf(
|
||||||
OVERRIDE_KEYWORD to listOf(OPEN_KEYWORD),
|
OVERRIDE_KEYWORD to listOf(OPEN_KEYWORD),
|
||||||
ABSTRACT_KEYWORD to listOf(OPEN_KEYWORD, FINAL_KEYWORD),
|
ABSTRACT_KEYWORD to listOf(OPEN_KEYWORD, FINAL_KEYWORD),
|
||||||
OPEN_KEYWORD to listOf(FINAL_KEYWORD, ABSTRACT_KEYWORD),
|
OPEN_KEYWORD to listOf(FINAL_KEYWORD, ABSTRACT_KEYWORD),
|
||||||
FINAL_KEYWORD to listOf(ABSTRACT_KEYWORD, OPEN_KEYWORD),
|
FINAL_KEYWORD to listOf(ABSTRACT_KEYWORD, OPEN_KEYWORD),
|
||||||
PUBLIC_KEYWORD to listOf(PROTECTED_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD),
|
PUBLIC_KEYWORD to listOf(PROTECTED_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD),
|
||||||
PROTECTED_KEYWORD to listOf(PUBLIC_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD),
|
PROTECTED_KEYWORD to listOf(PUBLIC_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD),
|
||||||
PRIVATE_KEYWORD to listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, INTERNAL_KEYWORD),
|
PRIVATE_KEYWORD to listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, INTERNAL_KEYWORD),
|
||||||
INTERNAL_KEYWORD to listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD),
|
INTERNAL_KEYWORD to listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD),
|
||||||
HEADER_KEYWORD to listOf(IMPL_KEYWORD, ACTUAL_KEYWORD, EXPECT_KEYWORD),
|
HEADER_KEYWORD to listOf(IMPL_KEYWORD, ACTUAL_KEYWORD, EXPECT_KEYWORD),
|
||||||
IMPL_KEYWORD to listOf(HEADER_KEYWORD, EXPECT_KEYWORD, ACTUAL_KEYWORD),
|
IMPL_KEYWORD to listOf(HEADER_KEYWORD, EXPECT_KEYWORD, ACTUAL_KEYWORD),
|
||||||
EXPECT_KEYWORD to listOf(IMPL_KEYWORD, ACTUAL_KEYWORD, HEADER_KEYWORD),
|
EXPECT_KEYWORD to listOf(IMPL_KEYWORD, ACTUAL_KEYWORD, HEADER_KEYWORD),
|
||||||
ACTUAL_KEYWORD to listOf(HEADER_KEYWORD, EXPECT_KEYWORD, IMPL_KEYWORD)
|
ACTUAL_KEYWORD to listOf(HEADER_KEYWORD, EXPECT_KEYWORD, IMPL_KEYWORD)
|
||||||
)
|
)
|
||||||
|
|
||||||
val MODIFIERS_ORDER = listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD,
|
val MODIFIERS_ORDER = listOf(
|
||||||
HEADER_KEYWORD, IMPL_KEYWORD, EXPECT_KEYWORD, ACTUAL_KEYWORD,
|
PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD,
|
||||||
FINAL_KEYWORD, OPEN_KEYWORD, ABSTRACT_KEYWORD, SEALED_KEYWORD,
|
HEADER_KEYWORD, IMPL_KEYWORD, EXPECT_KEYWORD, ACTUAL_KEYWORD,
|
||||||
CONST_KEYWORD,
|
FINAL_KEYWORD, OPEN_KEYWORD, ABSTRACT_KEYWORD, SEALED_KEYWORD,
|
||||||
EXTERNAL_KEYWORD,
|
CONST_KEYWORD,
|
||||||
OVERRIDE_KEYWORD,
|
EXTERNAL_KEYWORD,
|
||||||
LATEINIT_KEYWORD,
|
OVERRIDE_KEYWORD,
|
||||||
TAILREC_KEYWORD,
|
LATEINIT_KEYWORD,
|
||||||
VARARG_KEYWORD,
|
TAILREC_KEYWORD,
|
||||||
SUSPEND_KEYWORD,
|
VARARG_KEYWORD,
|
||||||
INNER_KEYWORD,
|
SUSPEND_KEYWORD,
|
||||||
ENUM_KEYWORD, ANNOTATION_KEYWORD,
|
INNER_KEYWORD,
|
||||||
COMPANION_KEYWORD,
|
ENUM_KEYWORD, ANNOTATION_KEYWORD,
|
||||||
INLINE_KEYWORD,
|
COMPANION_KEYWORD,
|
||||||
INFIX_KEYWORD,
|
INLINE_KEYWORD,
|
||||||
OPERATOR_KEYWORD,
|
INFIX_KEYWORD,
|
||||||
DATA_KEYWORD)
|
OPERATOR_KEYWORD,
|
||||||
|
DATA_KEYWORD
|
||||||
|
)
|
||||||
|
|||||||
@@ -28,8 +28,7 @@ val SUPPRESS_DIAGNOSTICS_IN_DEBUG_MODE: Key<Boolean> = Key.create<Boolean>("SUPP
|
|||||||
fun KtElement.suppressDiagnosticsInDebugMode(): Boolean {
|
fun KtElement.suppressDiagnosticsInDebugMode(): Boolean {
|
||||||
return if (this is KtFile) {
|
return if (this is KtFile) {
|
||||||
this.suppressDiagnosticsInDebugMode
|
this.suppressDiagnosticsInDebugMode
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val file = this.containingFile
|
val file = this.containingFile
|
||||||
file is KtFile && file.suppressDiagnosticsInDebugMode
|
file is KtFile && file.suppressDiagnosticsInDebugMode
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,23 +31,32 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
|||||||
import org.jetbrains.kotlin.renderer.render
|
import org.jetbrains.kotlin.renderer.render
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
fun KtPsiFactory.createExpressionByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtExpression
|
fun KtPsiFactory.createExpressionByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtExpression =
|
||||||
= createByPattern(pattern, *args, reformat = reformat) { createExpression(it) }
|
createByPattern(pattern, *args, reformat = reformat) { createExpression(it) }
|
||||||
|
|
||||||
fun KtPsiFactory.createValueArgumentListByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtValueArgumentList
|
fun KtPsiFactory.createValueArgumentListByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtValueArgumentList =
|
||||||
= createByPattern(pattern, *args, reformat = reformat) { createCallArguments(it) }
|
createByPattern(pattern, *args, reformat = reformat) { createCallArguments(it) }
|
||||||
|
|
||||||
fun <TDeclaration : KtDeclaration> KtPsiFactory.createDeclarationByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): TDeclaration
|
fun <TDeclaration : KtDeclaration> KtPsiFactory.createDeclarationByPattern(
|
||||||
= createByPattern(pattern, *args, reformat = reformat) { createDeclaration<TDeclaration>(it) }
|
pattern: String,
|
||||||
|
vararg args: Any,
|
||||||
|
reformat: Boolean = true
|
||||||
|
): TDeclaration = createByPattern(pattern, *args, reformat = reformat) { createDeclaration<TDeclaration>(it) }
|
||||||
|
|
||||||
fun KtPsiFactory.createDestructuringDeclarationByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtDestructuringDeclaration
|
fun KtPsiFactory.createDestructuringDeclarationByPattern(
|
||||||
= createByPattern(pattern, *args, reformat = reformat) { createDestructuringDeclaration(it) }
|
pattern: String,
|
||||||
|
vararg args: Any,
|
||||||
|
reformat: Boolean = true
|
||||||
|
): KtDestructuringDeclaration = createByPattern(pattern, *args, reformat = reformat) { createDestructuringDeclaration(it) }
|
||||||
|
|
||||||
private abstract class ArgumentType<T : Any>(val klass: Class<T>)
|
private abstract class ArgumentType<T : Any>(val klass: Class<T>)
|
||||||
|
|
||||||
private class PlainTextArgumentType<T : Any>(klass: Class<T>, val toPlainText: (T) -> String) : ArgumentType<T>(klass)
|
private class PlainTextArgumentType<T : Any>(klass: Class<T>, val toPlainText: (T) -> String) : ArgumentType<T>(klass)
|
||||||
|
|
||||||
private abstract class PsiElementPlaceholderArgumentType<T : Any, TPlaceholder : PsiElement>(klass: Class<T>, val placeholderClass: Class<TPlaceholder>) : ArgumentType<T>(klass) {
|
private abstract class PsiElementPlaceholderArgumentType<T : Any, TPlaceholder : PsiElement>(
|
||||||
|
klass: Class<T>,
|
||||||
|
val placeholderClass: Class<TPlaceholder>
|
||||||
|
) : ArgumentType<T>(klass) {
|
||||||
abstract fun replacePlaceholderElement(placeholder: TPlaceholder, argument: T): PsiChildRange
|
abstract fun replacePlaceholderElement(placeholder: TPlaceholder, argument: T): PsiChildRange
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -64,7 +73,8 @@ private class PsiElementArgumentType<T : PsiElement>(klass: Class<T>) : PsiEleme
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private object PsiChildRangeArgumentType : PsiElementPlaceholderArgumentType<PsiChildRange, KtElement>(PsiChildRange::class.java, KtElement::class.java) {
|
private object PsiChildRangeArgumentType :
|
||||||
|
PsiElementPlaceholderArgumentType<PsiChildRange, KtElement>(PsiChildRange::class.java, KtElement::class.java) {
|
||||||
override fun replacePlaceholderElement(placeholder: KtElement, argument: PsiChildRange): PsiChildRange {
|
override fun replacePlaceholderElement(placeholder: KtElement, argument: PsiChildRange): PsiChildRange {
|
||||||
val project = placeholder.project
|
val project = placeholder.project
|
||||||
val codeStyleManager = CodeStyleManager.getInstance(project)
|
val codeStyleManager = CodeStyleManager.getInstance(project)
|
||||||
@@ -79,8 +89,7 @@ private object PsiChildRangeArgumentType : PsiElementPlaceholderArgumentType<Psi
|
|||||||
codeStyleManager.reformatNewlyAddedElement(last.node.treeParent, last.node)
|
codeStyleManager.reformatNewlyAddedElement(last.node.treeParent, last.node)
|
||||||
}
|
}
|
||||||
PsiChildRange(first, last)
|
PsiChildRange(first, last)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
placeholder.delete()
|
placeholder.delete()
|
||||||
PsiChildRange.EMPTY
|
PsiChildRange.EMPTY
|
||||||
}
|
}
|
||||||
@@ -88,20 +97,25 @@ private object PsiChildRangeArgumentType : PsiElementPlaceholderArgumentType<Psi
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val SUPPORTED_ARGUMENT_TYPES = listOf(
|
private val SUPPORTED_ARGUMENT_TYPES = listOf(
|
||||||
PsiElementArgumentType(KtExpression::class.java),
|
PsiElementArgumentType(KtExpression::class.java),
|
||||||
PsiElementArgumentType(KtTypeReference::class.java),
|
PsiElementArgumentType(KtTypeReference::class.java),
|
||||||
PlainTextArgumentType(String::class.java, toPlainText = { it }),
|
PlainTextArgumentType(String::class.java, toPlainText = { it }),
|
||||||
PlainTextArgumentType(Name::class.java, toPlainText = Name::render),
|
PlainTextArgumentType(Name::class.java, toPlainText = Name::render),
|
||||||
PsiChildRangeArgumentType
|
PsiChildRangeArgumentType
|
||||||
)
|
)
|
||||||
|
|
||||||
@TestOnly
|
@TestOnly
|
||||||
var CREATEBYPATTERN_MAY_NOT_REFORMAT = false
|
var CREATEBYPATTERN_MAY_NOT_REFORMAT = false
|
||||||
|
|
||||||
fun <TElement : KtElement> createByPattern(pattern: String, vararg args: Any, reformat: Boolean = true, factory: (String) -> TElement): TElement {
|
fun <TElement : KtElement> createByPattern(
|
||||||
|
pattern: String,
|
||||||
|
vararg args: Any,
|
||||||
|
reformat: Boolean = true,
|
||||||
|
factory: (String) -> TElement
|
||||||
|
): TElement {
|
||||||
val argumentTypes = args.map { arg ->
|
val argumentTypes = args.map { arg ->
|
||||||
SUPPORTED_ARGUMENT_TYPES.firstOrNull { it.klass.isInstance(arg) }
|
SUPPORTED_ARGUMENT_TYPES.firstOrNull { it.klass.isInstance(arg) }
|
||||||
?: throw IllegalArgumentException("Unsupported argument type: ${arg::class.java}, should be one of: ${SUPPORTED_ARGUMENT_TYPES.joinToString { it.klass.simpleName }}")
|
?: throw IllegalArgumentException("Unsupported argument type: ${arg::class.java}, should be one of: ${SUPPORTED_ARGUMENT_TYPES.joinToString { it.klass.simpleName }}")
|
||||||
}
|
}
|
||||||
|
|
||||||
// convert arguments that can be converted into plain text
|
// convert arguments that can be converted into plain text
|
||||||
@@ -155,17 +169,16 @@ fun <TElement : KtElement> createByPattern(pattern: String, vararg args: Any, re
|
|||||||
throw java.lang.IllegalArgumentException("Reformatting is not allowed in the current context; please change the invocation to use reformat=false")
|
throw java.lang.IllegalArgumentException("Reformatting is not allowed in the current context; please change the invocation to use reformat=false")
|
||||||
}
|
}
|
||||||
val stringPlaceholderRanges = allPlaceholders
|
val stringPlaceholderRanges = allPlaceholders
|
||||||
.filter { args[it.key] is String }
|
.filter { args[it.key] is String }
|
||||||
.flatMap { it.value }
|
.flatMap { it.value }
|
||||||
.map { it.range }
|
.map { it.range }
|
||||||
.filterNot { it.isEmpty }
|
.filterNot { it.isEmpty }
|
||||||
.sortedByDescending { it.startOffset }
|
.sortedByDescending { it.startOffset }
|
||||||
|
|
||||||
// reformat whole text except for String arguments (as they can contain user's formatting to be preserved)
|
// reformat whole text except for String arguments (as they can contain user's formatting to be preserved)
|
||||||
resultElement = if (stringPlaceholderRanges.none()) {
|
resultElement = if (stringPlaceholderRanges.none()) {
|
||||||
codeStyleManager.reformat(resultElement, true) as TElement
|
codeStyleManager.reformat(resultElement, true) as TElement
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
var bound = resultElement.endOffset - 1
|
var bound = resultElement.endOffset - 1
|
||||||
for (range in stringPlaceholderRanges) {
|
for (range in stringPlaceholderRanges) {
|
||||||
// we extend reformatting range by 1 to the right because otherwise some of spaces are not reformatted
|
// we extend reformatting range by 1 to the right because otherwise some of spaces are not reformatted
|
||||||
@@ -223,8 +236,7 @@ private fun processPattern(pattern: String, args: List<Any>): PatternData {
|
|||||||
val nextChar = charOrNull(++i)
|
val nextChar = charOrNull(++i)
|
||||||
if (nextChar == '$') {
|
if (nextChar == '$') {
|
||||||
append(nextChar)
|
append(nextChar)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
check(nextChar?.isDigit() ?: false, "unclosed '$'")
|
check(nextChar?.isDigit() ?: false, "unclosed '$'")
|
||||||
|
|
||||||
val lastIndex = (i..pattern.length - 1).firstOrNull { !pattern[it].isDigit() } ?: pattern.length
|
val lastIndex = (i..pattern.length - 1).firstOrNull { !pattern[it].isDigit() } ?: pattern.length
|
||||||
@@ -235,8 +247,7 @@ private fun processPattern(pattern: String, args: List<Any>): PatternData {
|
|||||||
val arg: Any? = if (n < args.size) args[n] else null /* report wrong number of arguments later */
|
val arg: Any? = if (n < args.size) args[n] else null /* report wrong number of arguments later */
|
||||||
val placeholderText = if (charOrNull(i) != ':' || charOrNull(i + 1) != '\'') {
|
val placeholderText = if (charOrNull(i) != ':' || charOrNull(i + 1) != '\'') {
|
||||||
arg as? String ?: "xyz"
|
arg as? String ?: "xyz"
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
check(arg !is String, "do not specify placeholder text for $$n - plain text argument passed")
|
check(arg !is String, "do not specify placeholder text for $$n - plain text argument passed")
|
||||||
i += 2 // skip ':' and '\''
|
i += 2 // skip ':' and '\''
|
||||||
val endIndex = pattern.indexOf('\'', i)
|
val endIndex = pattern.indexOf('\'', i)
|
||||||
@@ -252,8 +263,7 @@ private fun processPattern(pattern: String, args: List<Any>): PatternData {
|
|||||||
ranges.getOrPut(n, { ArrayList() }).add(Placeholder(range, placeholderText))
|
ranges.getOrPut(n, { ArrayList() }).add(Placeholder(range, placeholderText))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
append(c)
|
append(c)
|
||||||
}
|
}
|
||||||
i++
|
i++
|
||||||
|
|||||||
@@ -152,25 +152,24 @@ fun KtExpression.getQualifiedExpressionForReceiverOrThis(): KtExpression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun KtExpression.isDotReceiver(): Boolean =
|
fun KtExpression.isDotReceiver(): Boolean =
|
||||||
(parent as? KtDotQualifiedExpression)?.receiverExpression == this
|
(parent as? KtDotQualifiedExpression)?.receiverExpression == this
|
||||||
|
|
||||||
// ---------- Block expression -------------------------------------------------------------------------------------------------------------
|
// ---------- Block expression -------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
fun KtElement.blockExpressionsOrSingle(): Sequence<KtElement> =
|
fun KtElement.blockExpressionsOrSingle(): Sequence<KtElement> =
|
||||||
if (this is KtBlockExpression) statements.asSequence() else sequenceOf(this)
|
if (this is KtBlockExpression) statements.asSequence() else sequenceOf(this)
|
||||||
|
|
||||||
fun KtExpression.lastBlockStatementOrThis(): KtExpression
|
fun KtExpression.lastBlockStatementOrThis(): KtExpression = (this as? KtBlockExpression)?.statements?.lastOrNull() ?: this
|
||||||
= (this as? KtBlockExpression)?.statements?.lastOrNull() ?: this
|
|
||||||
|
|
||||||
fun KtBlockExpression.contentRange(): PsiChildRange {
|
fun KtBlockExpression.contentRange(): PsiChildRange {
|
||||||
val first = (lBrace?.nextSibling ?: firstChild)
|
val first = (lBrace?.nextSibling ?: firstChild)
|
||||||
?.siblings(withItself = false)
|
?.siblings(withItself = false)
|
||||||
?.firstOrNull { it !is PsiWhiteSpace }
|
?.firstOrNull { it !is PsiWhiteSpace }
|
||||||
val rBrace = rBrace
|
val rBrace = rBrace
|
||||||
if (first == rBrace) return PsiChildRange.EMPTY
|
if (first == rBrace) return PsiChildRange.EMPTY
|
||||||
val last = rBrace!!
|
val last = rBrace!!
|
||||||
.siblings(forward = false, withItself = false)
|
.siblings(forward = false, withItself = false)
|
||||||
.first { it !is PsiWhiteSpace }
|
.first { it !is PsiWhiteSpace }
|
||||||
if (last == lBrace) return PsiChildRange.EMPTY
|
if (last == lBrace) return PsiChildRange.EMPTY
|
||||||
return PsiChildRange(first, last)
|
return PsiChildRange(first, last)
|
||||||
}
|
}
|
||||||
@@ -248,8 +247,7 @@ fun KtAnnotationsContainer.collectAnnotationEntriesFromStubOrPsi(): List<KtAnnot
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun StubElement<*>.collectAnnotationEntriesFromStubElement(): List<KtAnnotationEntry> {
|
private fun StubElement<*>.collectAnnotationEntriesFromStubElement(): List<KtAnnotationEntry> {
|
||||||
return childrenStubs.flatMap {
|
return childrenStubs.flatMap { child ->
|
||||||
child ->
|
|
||||||
when (child.stubType) {
|
when (child.stubType) {
|
||||||
KtNodeTypes.ANNOTATION_ENTRY -> listOf(child.psi as KtAnnotationEntry)
|
KtNodeTypes.ANNOTATION_ENTRY -> listOf(child.psi as KtAnnotationEntry)
|
||||||
KtNodeTypes.ANNOTATION -> (child.psi as KtAnnotation).entries
|
KtNodeTypes.ANNOTATION -> (child.psi as KtAnnotation).entries
|
||||||
@@ -283,14 +281,17 @@ inline fun <reified T : KtElement> forEachDescendantOfTypeVisitor(noinline block
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : KtElement, R> flatMapDescendantsOfTypeVisitor(accumulator: MutableCollection<R>, noinline map: (T) -> Collection<R>): KtVisitorVoid {
|
inline fun <reified T : KtElement, R> flatMapDescendantsOfTypeVisitor(
|
||||||
|
accumulator: MutableCollection<R>,
|
||||||
|
noinline map: (T) -> Collection<R>
|
||||||
|
): KtVisitorVoid {
|
||||||
return forEachDescendantOfTypeVisitor<T> { accumulator.addAll(map(it)) }
|
return forEachDescendantOfTypeVisitor<T> { accumulator.addAll(map(it)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------- Other -----------------------------------------------------------------------------------------------------------------------
|
// ----------- Other -----------------------------------------------------------------------------------------------------------------------
|
||||||
|
|
||||||
fun KtClassOrObject.effectiveDeclarations(): List<KtDeclaration> {
|
fun KtClassOrObject.effectiveDeclarations(): List<KtDeclaration> {
|
||||||
return when(this) {
|
return when (this) {
|
||||||
is KtClass -> getDeclarations() + getPrimaryConstructorParameters().filter { p -> p.hasValOrVar() }
|
is KtClass -> getDeclarations() + getPrimaryConstructorParameters().filter { p -> p.hasValOrVar() }
|
||||||
else -> declarations
|
else -> declarations
|
||||||
}
|
}
|
||||||
@@ -368,7 +369,7 @@ fun KtSimpleNameExpression.isCallee(): Boolean {
|
|||||||
is KtBinaryExpression -> parent.operationReference == this
|
is KtBinaryExpression -> parent.operationReference == this
|
||||||
else -> {
|
else -> {
|
||||||
val callElement =
|
val callElement =
|
||||||
getStrictParentOfType<KtUserType>()
|
getStrictParentOfType<KtUserType>()
|
||||||
?.getStrictParentOfType<KtTypeReference>()
|
?.getStrictParentOfType<KtTypeReference>()
|
||||||
?.getStrictParentOfType<KtConstructorCalleeExpression>()
|
?.getStrictParentOfType<KtConstructorCalleeExpression>()
|
||||||
?.getStrictParentOfType<KtCallElement>()
|
?.getStrictParentOfType<KtCallElement>()
|
||||||
@@ -376,8 +377,7 @@ fun KtSimpleNameExpression.isCallee(): Boolean {
|
|||||||
if (callElement != null) {
|
if (callElement != null) {
|
||||||
val ktConstructorCalleeExpression = callElement.calleeExpression as? KtConstructorCalleeExpression
|
val ktConstructorCalleeExpression = callElement.calleeExpression as? KtConstructorCalleeExpression
|
||||||
(ktConstructorCalleeExpression?.typeReference?.typeElement as? KtUserType)?.referenceExpression == this
|
(ktConstructorCalleeExpression?.typeReference?.typeElement as? KtUserType)?.referenceExpression == this
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -387,8 +387,7 @@ fun KtSimpleNameExpression.isCallee(): Boolean {
|
|||||||
val KtStringTemplateExpression.plainContent: String
|
val KtStringTemplateExpression.plainContent: String
|
||||||
get() = getContentRange().substring(text)
|
get() = getContentRange().substring(text)
|
||||||
|
|
||||||
fun KtStringTemplateExpression.isSingleQuoted(): Boolean
|
fun KtStringTemplateExpression.isSingleQuoted(): Boolean = node.firstChildNode.textLength == 1
|
||||||
= node.firstChildNode.textLength == 1
|
|
||||||
|
|
||||||
fun KtNamedDeclaration.getValueParameters(): List<KtParameter> {
|
fun KtNamedDeclaration.getValueParameters(): List<KtParameter> {
|
||||||
return getValueParameterList()?.parameters ?: Collections.emptyList()
|
return getValueParameterList()?.parameters ?: Collections.emptyList()
|
||||||
@@ -409,13 +408,13 @@ fun KtLambdaArgument.getLambdaArgumentName(bindingContext: BindingContext): Name
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun KtExpression.asAssignment(): KtBinaryExpression? =
|
fun KtExpression.asAssignment(): KtBinaryExpression? =
|
||||||
if (KtPsiUtil.isAssignment(this)) this as KtBinaryExpression else null
|
if (KtPsiUtil.isAssignment(this)) this as KtBinaryExpression else null
|
||||||
|
|
||||||
private fun KtModifierList.modifierFromTokenSet(set: TokenSet): PsiElement? {
|
private fun KtModifierList.modifierFromTokenSet(set: TokenSet): PsiElement? {
|
||||||
return set.types
|
return set.types
|
||||||
.asSequence()
|
.asSequence()
|
||||||
.map { getModifier(it as KtModifierKeywordToken) }
|
.map { getModifier(it as KtModifierKeywordToken) }
|
||||||
.firstOrNull { it != null }
|
.firstOrNull { it != null }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,34 +422,34 @@ private fun KtModifierListOwner.modifierFromTokenSet(set: TokenSet) = modifierLi
|
|||||||
|
|
||||||
fun KtModifierList.visibilityModifier() = modifierFromTokenSet(KtTokens.VISIBILITY_MODIFIERS)
|
fun KtModifierList.visibilityModifier() = modifierFromTokenSet(KtTokens.VISIBILITY_MODIFIERS)
|
||||||
|
|
||||||
fun KtModifierList.visibilityModifierType(): KtModifierKeywordToken?
|
fun KtModifierList.visibilityModifierType(): KtModifierKeywordToken? = visibilityModifier()?.node?.elementType as KtModifierKeywordToken?
|
||||||
= visibilityModifier()?.node?.elementType as KtModifierKeywordToken?
|
|
||||||
|
|
||||||
fun KtModifierListOwner.visibilityModifier() = modifierList?.modifierFromTokenSet(KtTokens.VISIBILITY_MODIFIERS)
|
fun KtModifierListOwner.visibilityModifier() = modifierList?.modifierFromTokenSet(KtTokens.VISIBILITY_MODIFIERS)
|
||||||
|
|
||||||
fun KtModifierListOwner.visibilityModifierType(): KtModifierKeywordToken?
|
fun KtModifierListOwner.visibilityModifierType(): KtModifierKeywordToken? =
|
||||||
= visibilityModifier()?.node?.elementType as KtModifierKeywordToken?
|
visibilityModifier()?.node?.elementType as KtModifierKeywordToken?
|
||||||
|
|
||||||
private val MODALITY_MODIFIERS = TokenSet.create(
|
private val MODALITY_MODIFIERS = TokenSet.create(
|
||||||
KtTokens.ABSTRACT_KEYWORD, KtTokens.FINAL_KEYWORD, KtTokens.SEALED_KEYWORD, KtTokens.OPEN_KEYWORD
|
KtTokens.ABSTRACT_KEYWORD, KtTokens.FINAL_KEYWORD, KtTokens.SEALED_KEYWORD, KtTokens.OPEN_KEYWORD
|
||||||
)
|
)
|
||||||
|
|
||||||
fun KtDeclaration.modalityModifier() = modifierFromTokenSet(MODALITY_MODIFIERS)
|
fun KtDeclaration.modalityModifier() = modifierFromTokenSet(MODALITY_MODIFIERS)
|
||||||
|
|
||||||
fun KtStringTemplateExpression.isPlain() = entries.all { it is KtLiteralStringTemplateEntry }
|
fun KtStringTemplateExpression.isPlain() = entries.all { it is KtLiteralStringTemplateEntry }
|
||||||
fun KtStringTemplateExpression.isPlainWithEscapes() = entries.all { it is KtLiteralStringTemplateEntry || it is KtEscapeStringTemplateEntry }
|
fun KtStringTemplateExpression.isPlainWithEscapes() =
|
||||||
|
entries.all { it is KtLiteralStringTemplateEntry || it is KtEscapeStringTemplateEntry }
|
||||||
|
|
||||||
// Correct for class members only (including constructors and nested classes)
|
// Correct for class members only (including constructors and nested classes)
|
||||||
// Returns null e.g. for member function parameters, member function locals, property accessors
|
// Returns null e.g. for member function parameters, member function locals, property accessors
|
||||||
val KtDeclaration.containingClassOrObject: KtClassOrObject?
|
val KtDeclaration.containingClassOrObject: KtClassOrObject?
|
||||||
get() = parent.let {
|
get() = parent.let {
|
||||||
when (it) {
|
when (it) {
|
||||||
is KtClassBody -> it.parent as? KtClassOrObject
|
is KtClassBody -> it.parent as? KtClassOrObject
|
||||||
is KtClassOrObject -> it
|
is KtClassOrObject -> it
|
||||||
is KtParameterList -> (it.parent as? KtPrimaryConstructor)?.getContainingClassOrObject()
|
is KtParameterList -> (it.parent as? KtPrimaryConstructor)?.getContainingClassOrObject()
|
||||||
else -> null
|
else -> null
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fun KtExpression.getOutermostParenthesizerOrThis(): KtExpression {
|
fun KtExpression.getOutermostParenthesizerOrThis(): KtExpression {
|
||||||
return (parentsWithSelf.zip(parents)).firstOrNull {
|
return (parentsWithSelf.zip(parents)).firstOrNull {
|
||||||
@@ -506,7 +505,7 @@ fun KtElement.containingClass(): KtClass? = getStrictParentOfType()
|
|||||||
|
|
||||||
fun KtClassOrObject.findPropertyByName(name: String): KtNamedDeclaration? {
|
fun KtClassOrObject.findPropertyByName(name: String): KtNamedDeclaration? {
|
||||||
return declarations.firstOrNull { it is KtProperty && it.name == name } as KtNamedDeclaration?
|
return declarations.firstOrNull { it is KtProperty && it.name == name } as KtNamedDeclaration?
|
||||||
?: primaryConstructorParameters.firstOrNull { it.hasValOrVar() && it.name == name }
|
?: primaryConstructorParameters.firstOrNull { it.hasValOrVar() && it.name == name }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isTypeConstructorReference(e: PsiElement): Boolean {
|
fun isTypeConstructorReference(e: PsiElement): Boolean {
|
||||||
@@ -516,7 +515,8 @@ fun isTypeConstructorReference(e: PsiElement): Boolean {
|
|||||||
|
|
||||||
fun KtParameter.isPropertyParameter() = ownerFunction is KtPrimaryConstructor && hasValOrVar()
|
fun KtParameter.isPropertyParameter() = ownerFunction is KtPrimaryConstructor && hasValOrVar()
|
||||||
|
|
||||||
fun isDoubleColonReceiver(expression: KtExpression) = expression.getParentOfTypeAndBranch<KtDoubleColonExpression> { this.receiverExpression } != null
|
fun isDoubleColonReceiver(expression: KtExpression) =
|
||||||
|
expression.getParentOfTypeAndBranch<KtDoubleColonExpression> { this.receiverExpression } != null
|
||||||
|
|
||||||
fun KtFunctionLiteral.getOrCreateParameterList(): KtParameterList {
|
fun KtFunctionLiteral.getOrCreateParameterList(): KtParameterList {
|
||||||
valueParameterList?.let { return it }
|
valueParameterList?.let { return it }
|
||||||
@@ -535,15 +535,16 @@ fun KtFunctionLiteral.getOrCreateParameterList(): KtParameterList {
|
|||||||
|
|
||||||
fun KtCallExpression.getOrCreateValueArgumentList(): KtValueArgumentList {
|
fun KtCallExpression.getOrCreateValueArgumentList(): KtValueArgumentList {
|
||||||
valueArgumentList?.let { return it }
|
valueArgumentList?.let { return it }
|
||||||
return addAfter(KtPsiFactory(this).createCallArguments("()"),
|
return addAfter(
|
||||||
typeArgumentList ?: calleeExpression) as KtValueArgumentList
|
KtPsiFactory(this).createCallArguments("()"),
|
||||||
|
typeArgumentList ?: calleeExpression
|
||||||
|
) as KtValueArgumentList
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KtCallExpression.addTypeArgument(typeArgument: KtTypeProjection) {
|
fun KtCallExpression.addTypeArgument(typeArgument: KtTypeProjection) {
|
||||||
if (typeArgumentList != null) {
|
if (typeArgumentList != null) {
|
||||||
typeArgumentList?.addArgument(typeArgument)
|
typeArgumentList?.addArgument(typeArgument)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
addAfter(KtPsiFactory(this).createTypeArguments("<${typeArgument.text}>"), calleeExpression)
|
addAfter(KtPsiFactory(this).createTypeArguments("<${typeArgument.text}>"), calleeExpression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -556,7 +557,7 @@ fun KtDeclaration.hasBody() = when (this) {
|
|||||||
|
|
||||||
|
|
||||||
fun KtExpression.referenceExpression(): KtReferenceExpression? =
|
fun KtExpression.referenceExpression(): KtReferenceExpression? =
|
||||||
(if (this is KtCallExpression) calleeExpression else this) as? KtReferenceExpression
|
(if (this is KtCallExpression) calleeExpression else this) as? KtReferenceExpression
|
||||||
|
|
||||||
fun KtExpression.getLabeledParent(labelName: String): KtLabeledExpression? {
|
fun KtExpression.getLabeledParent(labelName: String): KtLabeledExpression? {
|
||||||
parents.forEach {
|
parents.forEach {
|
||||||
|
|||||||
@@ -68,11 +68,9 @@ val PsiElement.parentsWithSelf: Sequence<PsiElement>
|
|||||||
val PsiElement.parents: Sequence<PsiElement>
|
val PsiElement.parents: Sequence<PsiElement>
|
||||||
get() = parentsWithSelf.drop(1)
|
get() = parentsWithSelf.drop(1)
|
||||||
|
|
||||||
fun PsiElement.prevLeaf(skipEmptyElements: Boolean = false): PsiElement?
|
fun PsiElement.prevLeaf(skipEmptyElements: Boolean = false): PsiElement? = PsiTreeUtil.prevLeaf(this, skipEmptyElements)
|
||||||
= PsiTreeUtil.prevLeaf(this, skipEmptyElements)
|
|
||||||
|
|
||||||
fun PsiElement.nextLeaf(skipEmptyElements: Boolean = false): PsiElement?
|
fun PsiElement.nextLeaf(skipEmptyElements: Boolean = false): PsiElement? = PsiTreeUtil.nextLeaf(this, skipEmptyElements)
|
||||||
= PsiTreeUtil.nextLeaf(this, skipEmptyElements)
|
|
||||||
|
|
||||||
val PsiElement.prevLeafs: Sequence<PsiElement>
|
val PsiElement.prevLeafs: Sequence<PsiElement>
|
||||||
get() = generateSequence({ prevLeaf() }, { it.prevLeaf() })
|
get() = generateSequence({ prevLeaf() }, { it.prevLeaf() })
|
||||||
@@ -97,7 +95,7 @@ fun PsiElement.nextLeaf(filter: (PsiElement) -> Boolean): PsiElement? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <T : PsiElement> PsiElement.getParentOfTypesAndPredicate(
|
fun <T : PsiElement> PsiElement.getParentOfTypesAndPredicate(
|
||||||
strict: Boolean = false, vararg parentClasses: Class<T>, predicate: (T) -> Boolean
|
strict: Boolean = false, vararg parentClasses: Class<T>, predicate: (T) -> Boolean
|
||||||
): T? {
|
): T? {
|
||||||
var element = if (strict) parent else this
|
var element = if (strict) parent else this
|
||||||
while (element != null) {
|
while (element != null) {
|
||||||
@@ -175,7 +173,10 @@ inline fun <reified T : PsiElement> PsiElement.getParentOfTypeAndBranch(strict:
|
|||||||
return getParentOfType<T>(strict)?.getIfChildIsInBranch(this, branch)
|
return getParentOfType<T>(strict)?.getIfChildIsInBranch(this, branch)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : PsiElement> PsiElement.getParentOfTypeAndBranches(strict: Boolean = false, noinline branches: T.() -> Iterable<PsiElement?>): T? {
|
inline fun <reified T : PsiElement> PsiElement.getParentOfTypeAndBranches(
|
||||||
|
strict: Boolean = false,
|
||||||
|
noinline branches: T.() -> Iterable<PsiElement?>
|
||||||
|
): T? {
|
||||||
return getParentOfType<T>(strict)?.getIfChildIsInBranches(this, branches)
|
return getParentOfType<T>(strict)?.getIfChildIsInBranches(this, branches)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,7 +189,9 @@ fun PsiElement.isInsideOf(elements: Iterable<PsiElement>): Boolean = elements.an
|
|||||||
|
|
||||||
fun PsiChildRange.trimWhiteSpaces(): PsiChildRange {
|
fun PsiChildRange.trimWhiteSpaces(): PsiChildRange {
|
||||||
if (first == null) return this
|
if (first == null) return this
|
||||||
return PsiChildRange(first.siblings().firstOrNull { it !is PsiWhiteSpace }, last!!.siblings(forward = false).firstOrNull { it !is PsiWhiteSpace })
|
return PsiChildRange(
|
||||||
|
first.siblings().firstOrNull { it !is PsiWhiteSpace },
|
||||||
|
last!!.siblings(forward = false).firstOrNull { it !is PsiWhiteSpace })
|
||||||
}
|
}
|
||||||
|
|
||||||
// -------------------- Recursive tree visiting --------------------------------------------------------------------------------------------
|
// -------------------- Recursive tree visiting --------------------------------------------------------------------------------------------
|
||||||
@@ -197,7 +200,10 @@ inline fun <reified T : PsiElement> PsiElement.forEachDescendantOfType(noinline
|
|||||||
forEachDescendantOfType({ true }, action)
|
forEachDescendantOfType({ true }, action)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : PsiElement> PsiElement.forEachDescendantOfType(crossinline canGoInside: (PsiElement) -> Boolean, noinline action: (T) -> Unit) {
|
inline fun <reified T : PsiElement> PsiElement.forEachDescendantOfType(
|
||||||
|
crossinline canGoInside: (PsiElement) -> Boolean,
|
||||||
|
noinline action: (T) -> Unit
|
||||||
|
) {
|
||||||
this.accept(object : PsiRecursiveElementVisitor() {
|
this.accept(object : PsiRecursiveElementVisitor() {
|
||||||
override fun visitElement(element: PsiElement) {
|
override fun visitElement(element: PsiElement) {
|
||||||
if (canGoInside(element)) {
|
if (canGoInside(element)) {
|
||||||
@@ -215,7 +221,10 @@ inline fun <reified T : PsiElement> PsiElement.anyDescendantOfType(noinline pred
|
|||||||
return findDescendantOfType(predicate) != null
|
return findDescendantOfType(predicate) != null
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : PsiElement> PsiElement.anyDescendantOfType(crossinline canGoInside: (PsiElement) -> Boolean, noinline predicate: (T) -> Boolean = { true }): Boolean {
|
inline fun <reified T : PsiElement> PsiElement.anyDescendantOfType(
|
||||||
|
crossinline canGoInside: (PsiElement) -> Boolean,
|
||||||
|
noinline predicate: (T) -> Boolean = { true }
|
||||||
|
): Boolean {
|
||||||
return findDescendantOfType(canGoInside, predicate) != null
|
return findDescendantOfType(canGoInside, predicate) != null
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,7 +232,10 @@ inline fun <reified T : PsiElement> PsiElement.findDescendantOfType(noinline pre
|
|||||||
return findDescendantOfType({ true }, predicate)
|
return findDescendantOfType({ true }, predicate)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : PsiElement> PsiElement.findDescendantOfType(crossinline canGoInside: (PsiElement) -> Boolean, noinline predicate: (T) -> Boolean = { true }): T? {
|
inline fun <reified T : PsiElement> PsiElement.findDescendantOfType(
|
||||||
|
crossinline canGoInside: (PsiElement) -> Boolean,
|
||||||
|
noinline predicate: (T) -> Boolean = { true }
|
||||||
|
): T? {
|
||||||
var result: T? = null
|
var result: T? = null
|
||||||
this.accept(object : PsiRecursiveElementWalkingVisitor() {
|
this.accept(object : PsiRecursiveElementWalkingVisitor() {
|
||||||
override fun visitElement(element: PsiElement) {
|
override fun visitElement(element: PsiElement) {
|
||||||
@@ -245,7 +257,10 @@ inline fun <reified T : PsiElement> PsiElement.collectDescendantsOfType(noinline
|
|||||||
return collectDescendantsOfType({ true }, predicate)
|
return collectDescendantsOfType({ true }, predicate)
|
||||||
}
|
}
|
||||||
|
|
||||||
inline fun <reified T : PsiElement> PsiElement.collectDescendantsOfType(crossinline canGoInside: (PsiElement) -> Boolean, noinline predicate: (T) -> Boolean = { true }): List<T> {
|
inline fun <reified T : PsiElement> PsiElement.collectDescendantsOfType(
|
||||||
|
crossinline canGoInside: (PsiElement) -> Boolean,
|
||||||
|
noinline predicate: (T) -> Boolean = { true }
|
||||||
|
): List<T> {
|
||||||
val result = ArrayList<T>()
|
val result = ArrayList<T>()
|
||||||
forEachDescendantOfType<T>(canGoInside) {
|
forEachDescendantOfType<T>(canGoInside) {
|
||||||
if (predicate(it)) {
|
if (predicate(it)) {
|
||||||
@@ -294,11 +309,11 @@ fun PsiFile.elementsInRange(range: TextRange): List<PsiElement> {
|
|||||||
val leaf = findFirstLeafWhollyInRange(this, currentRange) ?: break
|
val leaf = findFirstLeafWhollyInRange(this, currentRange) ?: break
|
||||||
|
|
||||||
val element = leaf
|
val element = leaf
|
||||||
.parentsWithSelf
|
.parentsWithSelf
|
||||||
.first {
|
.first {
|
||||||
val parent = it.parent
|
val parent = it.parent
|
||||||
it is PsiFile || parent.textRange !in currentRange
|
it is PsiFile || parent.textRange !in currentRange
|
||||||
}
|
}
|
||||||
result.add(element)
|
result.add(element)
|
||||||
|
|
||||||
offset = element.endOffset
|
offset = element.endOffset
|
||||||
@@ -333,8 +348,8 @@ fun PsiElement.getElementTextWithContext(): String {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find parent for element among file children
|
// Find parent for element among file children
|
||||||
val topLevelElement = PsiTreeUtil.findFirstParent(this, { it.parent is PsiFile }) ?:
|
val topLevelElement = PsiTreeUtil.findFirstParent(this, { it.parent is PsiFile })
|
||||||
throw AssertionError("For non-file element we should always be able to find parent in file children")
|
?: throw AssertionError("For non-file element we should always be able to find parent in file children")
|
||||||
|
|
||||||
val startContextOffset = topLevelElement.startOffset
|
val startContextOffset = topLevelElement.startOffset
|
||||||
val elementContextOffset = textRange.startOffset
|
val elementContextOffset = textRange.startOffset
|
||||||
@@ -344,9 +359,9 @@ fun PsiElement.getElementTextWithContext(): String {
|
|||||||
|
|
||||||
val isInjected = containingFile is VirtualFileWindow
|
val isInjected = containingFile is VirtualFileWindow
|
||||||
return StringBuilder(topLevelElement.text)
|
return StringBuilder(topLevelElement.text)
|
||||||
.insert(inFileParentOffset, "<caret>")
|
.insert(inFileParentOffset, "<caret>")
|
||||||
.insert(0, "File name: ${containingFile.name} Physical: ${containingFile.isPhysical} Injected: $isInjected\n")
|
.insert(0, "File name: ${containingFile.name} Physical: ${containingFile.isPhysical} Injected: $isInjected\n")
|
||||||
.toString()
|
.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun PsiElement.getTextWithLocation(): String = "'${this.text}' at ${DiagnosticUtils.atLocation(this)}"
|
fun PsiElement.getTextWithLocation(): String = "'${this.text}' at ${DiagnosticUtils.atLocation(this)}"
|
||||||
@@ -356,7 +371,7 @@ fun replaceFileAnnotationList(file: KtFile, annotationList: KtFileAnnotationList
|
|||||||
return file.fileAnnotationList!!.replace(annotationList) as KtFileAnnotationList
|
return file.fileAnnotationList!!.replace(annotationList) as KtFileAnnotationList
|
||||||
}
|
}
|
||||||
|
|
||||||
val beforeAnchor : PsiElement? = when {
|
val beforeAnchor: PsiElement? = when {
|
||||||
file.packageDirective?.packageKeyword != null -> file.packageDirective!!
|
file.packageDirective?.packageKeyword != null -> file.packageDirective!!
|
||||||
file.importList != null -> file.importList!!
|
file.importList != null -> file.importList!!
|
||||||
file.declarations.firstOrNull() != null -> file.declarations.first()
|
file.declarations.firstOrNull() != null -> file.declarations.first()
|
||||||
@@ -379,7 +394,7 @@ fun replaceFileAnnotationList(file: KtFile, annotationList: KtFileAnnotationList
|
|||||||
operator fun SearchScope.contains(element: PsiElement): Boolean = PsiSearchScopeUtil.isInScope(this, element)
|
operator fun SearchScope.contains(element: PsiElement): Boolean = PsiSearchScopeUtil.isInScope(this, element)
|
||||||
|
|
||||||
fun <E : PsiElement> E.createSmartPointer(): SmartPsiElementPointer<E> =
|
fun <E : PsiElement> E.createSmartPointer(): SmartPsiElementPointer<E> =
|
||||||
SmartPointerManager.getInstance(project).createSmartPsiElementPointer(this)
|
SmartPointerManager.getInstance(project).createSmartPsiElementPointer(this)
|
||||||
|
|
||||||
fun PsiElement.before(element: PsiElement) = textRange.endOffset <= element.textRange.startOffset
|
fun PsiElement.before(element: PsiElement) = textRange.endOffset <= element.textRange.startOffset
|
||||||
|
|
||||||
|
|||||||
@@ -113,7 +113,7 @@ interface KotlinPropertyStub : KotlinCallableStubBase<KtProperty> {
|
|||||||
fun hasReturnTypeRef(): Boolean
|
fun hasReturnTypeRef(): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface KotlinCallableStubBase<TDeclaration: KtCallableDeclaration> : KotlinStubWithFqName<TDeclaration> {
|
interface KotlinCallableStubBase<TDeclaration : KtCallableDeclaration> : KotlinStubWithFqName<TDeclaration> {
|
||||||
fun isTopLevel(): Boolean
|
fun isTopLevel(): Boolean
|
||||||
fun isExtension(): Boolean
|
fun isExtension(): Boolean
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -25,9 +25,10 @@ import org.jetbrains.kotlin.psi.KtAnnotationUseSiteTarget
|
|||||||
import org.jetbrains.kotlin.psi.stubs.KotlinAnnotationUseSiteTargetStub
|
import org.jetbrains.kotlin.psi.stubs.KotlinAnnotationUseSiteTargetStub
|
||||||
import org.jetbrains.kotlin.psi.stubs.impl.KotlinAnnotationUseSiteTargetStubImpl
|
import org.jetbrains.kotlin.psi.stubs.impl.KotlinAnnotationUseSiteTargetStubImpl
|
||||||
|
|
||||||
class KtAnnotationUseSiteTargetElementType(debugName: String) : KtStubElementType<KotlinAnnotationUseSiteTargetStub, KtAnnotationUseSiteTarget>(
|
class KtAnnotationUseSiteTargetElementType(debugName: String) :
|
||||||
|
KtStubElementType<KotlinAnnotationUseSiteTargetStub, KtAnnotationUseSiteTarget>(
|
||||||
debugName, KtAnnotationUseSiteTarget::class.java, KotlinAnnotationUseSiteTargetStub::class.java
|
debugName, KtAnnotationUseSiteTarget::class.java, KotlinAnnotationUseSiteTargetStub::class.java
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override fun createStub(psi: KtAnnotationUseSiteTarget, parentStub: StubElement<PsiElement>): KotlinAnnotationUseSiteTargetStub {
|
override fun createStub(psi: KtAnnotationUseSiteTarget, parentStub: StubElement<PsiElement>): KotlinAnnotationUseSiteTargetStub {
|
||||||
val useSiteTarget = psi.getAnnotationUseSiteTarget().name
|
val useSiteTarget = psi.getAnnotationUseSiteTarget().name
|
||||||
|
|||||||
+6
-3
@@ -25,14 +25,17 @@ import org.jetbrains.kotlin.psi.KtEnumEntrySuperclassReferenceExpression
|
|||||||
import org.jetbrains.kotlin.psi.stubs.KotlinEnumEntrySuperclassReferenceExpressionStub
|
import org.jetbrains.kotlin.psi.stubs.KotlinEnumEntrySuperclassReferenceExpressionStub
|
||||||
import org.jetbrains.kotlin.psi.stubs.impl.KotlinEnumEntrySuperclassReferenceExpressionStubImpl
|
import org.jetbrains.kotlin.psi.stubs.impl.KotlinEnumEntrySuperclassReferenceExpressionStubImpl
|
||||||
|
|
||||||
class KtEnumEntrySuperClassReferenceExpressionElementType(@NonNls debugName: String)
|
class KtEnumEntrySuperClassReferenceExpressionElementType(@NonNls debugName: String) :
|
||||||
: KtStubElementType<KotlinEnumEntrySuperclassReferenceExpressionStub, KtEnumEntrySuperclassReferenceExpression>(
|
KtStubElementType<KotlinEnumEntrySuperclassReferenceExpressionStub, KtEnumEntrySuperclassReferenceExpression>(
|
||||||
debugName,
|
debugName,
|
||||||
KtEnumEntrySuperclassReferenceExpression::class.java,
|
KtEnumEntrySuperclassReferenceExpression::class.java,
|
||||||
KotlinEnumEntrySuperclassReferenceExpressionStub::class.java
|
KotlinEnumEntrySuperclassReferenceExpressionStub::class.java
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override fun createStub(psi: KtEnumEntrySuperclassReferenceExpression, parentStub: StubElement<*>): KotlinEnumEntrySuperclassReferenceExpressionStub {
|
override fun createStub(
|
||||||
|
psi: KtEnumEntrySuperclassReferenceExpression,
|
||||||
|
parentStub: StubElement<*>
|
||||||
|
): KotlinEnumEntrySuperclassReferenceExpressionStub {
|
||||||
return KotlinEnumEntrySuperclassReferenceExpressionStubImpl(parentStub, StringRef.fromString(psi.getReferencedName())!!)
|
return KotlinEnumEntrySuperclassReferenceExpressionStubImpl(parentStub, StringRef.fromString(psi.getReferencedName())!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.psi.stubs.KotlinImportAliasStub
|
|||||||
import org.jetbrains.kotlin.psi.stubs.impl.KotlinImportAliasStubImpl
|
import org.jetbrains.kotlin.psi.stubs.impl.KotlinImportAliasStubImpl
|
||||||
|
|
||||||
class KtImportAliasElementType(debugName: String) :
|
class KtImportAliasElementType(debugName: String) :
|
||||||
KtStubElementType<KotlinImportAliasStub, KtImportAlias>(debugName, KtImportAlias::class.java, KotlinImportAliasStub::class.java) {
|
KtStubElementType<KotlinImportAliasStub, KtImportAlias>(debugName, KtImportAlias::class.java, KotlinImportAliasStub::class.java) {
|
||||||
override fun createStub(psi: KtImportAlias, parentStub: StubElement<PsiElement>?): KotlinImportAliasStub {
|
override fun createStub(psi: KtImportAlias, parentStub: StubElement<PsiElement>?): KotlinImportAliasStub {
|
||||||
return KotlinImportAliasStubImpl(parentStub, StringRef.fromString(psi.name))
|
return KotlinImportAliasStubImpl(parentStub, StringRef.fromString(psi.name))
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -24,9 +24,9 @@ import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
|||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
|
||||||
class KotlinAnnotationEntryStubImpl(
|
class KotlinAnnotationEntryStubImpl(
|
||||||
parent: StubElement<out PsiElement>?,
|
parent: StubElement<out PsiElement>?,
|
||||||
private val shortName: StringRef,
|
private val shortName: StringRef,
|
||||||
private val hasValueArguments: Boolean
|
private val hasValueArguments: Boolean
|
||||||
) : KotlinStubBaseImpl<KtAnnotationEntry>(parent, KtStubElementTypes.ANNOTATION_ENTRY), KotlinAnnotationEntryStub {
|
) : KotlinStubBaseImpl<KtAnnotationEntry>(parent, KtStubElementTypes.ANNOTATION_ENTRY), KotlinAnnotationEntryStub {
|
||||||
|
|
||||||
override fun getShortName() = shortName.string
|
override fun getShortName() = shortName.string
|
||||||
|
|||||||
+2
-2
@@ -24,8 +24,8 @@ import org.jetbrains.kotlin.psi.stubs.KotlinAnnotationUseSiteTargetStub
|
|||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||||
|
|
||||||
class KotlinAnnotationUseSiteTargetStubImpl(
|
class KotlinAnnotationUseSiteTargetStubImpl(
|
||||||
parent: StubElement<out PsiElement>?,
|
parent: StubElement<out PsiElement>?,
|
||||||
private val target: StringRef
|
private val target: StringRef
|
||||||
) : KotlinStubBaseImpl<KtAnnotationUseSiteTarget>(parent, KtStubElementTypes.ANNOTATION_TARGET), KotlinAnnotationUseSiteTargetStub {
|
) : KotlinStubBaseImpl<KtAnnotationUseSiteTarget>(parent, KtStubElementTypes.ANNOTATION_TARGET), KotlinAnnotationUseSiteTargetStub {
|
||||||
|
|
||||||
override fun getUseSiteTarget() = target.string
|
override fun getUseSiteTarget() = target.string
|
||||||
|
|||||||
@@ -25,20 +25,21 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
|
||||||
class KotlinFunctionStubImpl(
|
class KotlinFunctionStubImpl(
|
||||||
parent: StubElement<out PsiElement>?,
|
parent: StubElement<out PsiElement>?,
|
||||||
private val nameRef: StringRef?,
|
private val nameRef: StringRef?,
|
||||||
private val isTopLevel: Boolean,
|
private val isTopLevel: Boolean,
|
||||||
private val fqName: FqName?,
|
private val fqName: FqName?,
|
||||||
private val isExtension: Boolean,
|
private val isExtension: Boolean,
|
||||||
private val hasBlockBody: Boolean,
|
private val hasBlockBody: Boolean,
|
||||||
private val hasBody: Boolean,
|
private val hasBody: Boolean,
|
||||||
private val hasTypeParameterListBeforeFunctionName: Boolean
|
private val hasTypeParameterListBeforeFunctionName: Boolean
|
||||||
) : KotlinStubBaseImpl<KtNamedFunction>(parent, KtStubElementTypes.FUNCTION), KotlinFunctionStub {
|
) : KotlinStubBaseImpl<KtNamedFunction>(parent, KtStubElementTypes.FUNCTION), KotlinFunctionStub {
|
||||||
init {
|
init {
|
||||||
if (isTopLevel && fqName == null) {
|
if (isTopLevel && fqName == null) {
|
||||||
throw IllegalArgumentException("fqName shouldn't be null for top level functions")
|
throw IllegalArgumentException("fqName shouldn't be null for top level functions")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getFqName() = fqName
|
override fun getFqName() = fqName
|
||||||
|
|
||||||
override fun getName() = StringRef.toString(nameRef)
|
override fun getName() = StringRef.toString(nameRef)
|
||||||
|
|||||||
+6
-6
@@ -25,12 +25,12 @@ import org.jetbrains.kotlin.name.FqName
|
|||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
|
||||||
class KotlinParameterStubImpl(
|
class KotlinParameterStubImpl(
|
||||||
parent: StubElement<out PsiElement>?,
|
parent: StubElement<out PsiElement>?,
|
||||||
private val fqName: StringRef?,
|
private val fqName: StringRef?,
|
||||||
private val name: StringRef?,
|
private val name: StringRef?,
|
||||||
private val isMutable: Boolean,
|
private val isMutable: Boolean,
|
||||||
private val hasValOrVar: Boolean,
|
private val hasValOrVar: Boolean,
|
||||||
private val hasDefaultValue: Boolean
|
private val hasDefaultValue: Boolean
|
||||||
) : KotlinStubBaseImpl<KtParameter>(parent, KtStubElementTypes.VALUE_PARAMETER), KotlinParameterStub {
|
) : KotlinStubBaseImpl<KtParameter>(parent, KtStubElementTypes.VALUE_PARAMETER), KotlinParameterStub {
|
||||||
override fun getName(): String? {
|
override fun getName(): String? {
|
||||||
return StringRef.toString(name)
|
return StringRef.toString(name)
|
||||||
|
|||||||
@@ -30,7 +30,8 @@ import java.util.ArrayList
|
|||||||
|
|
||||||
val STUB_TO_STRING_PREFIX = "KotlinStub$"
|
val STUB_TO_STRING_PREFIX = "KotlinStub$"
|
||||||
|
|
||||||
open class KotlinStubBaseImpl<T : KtElementImplStub<*>>(parent: StubElement<*>?, elementType: IStubElementType<*, *>) : StubBase<T>(parent, elementType) {
|
open class KotlinStubBaseImpl<T : KtElementImplStub<*>>(parent: StubElement<*>?, elementType: IStubElementType<*, *>) :
|
||||||
|
StubBase<T>(parent, elementType) {
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
val stubInterface = this::class.java.interfaces.single { it.name.contains("Stub") }
|
val stubInterface = this::class.java.interfaces.single { it.name.contains("Stub") }
|
||||||
@@ -62,8 +63,7 @@ open class KotlinStubBaseImpl<T : KtElementImplStub<*>>(parent: StubElement<*>?,
|
|||||||
val value = property.invoke(this)
|
val value = property.invoke(this)
|
||||||
val name = getPropertyName(property)
|
val name = getPropertyName(property)
|
||||||
"$name=$value"
|
"$name=$value"
|
||||||
}
|
} catch (e: Exception) {
|
||||||
catch (e: Exception) {
|
|
||||||
LOGGER.error(e)
|
LOGGER.error(e)
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
@@ -80,6 +80,11 @@ open class KotlinStubBaseImpl<T : KtElementImplStub<*>>(parent: StubElement<*>?,
|
|||||||
companion object {
|
companion object {
|
||||||
private val LOGGER: Logger = Logger.getInstance(KotlinStubBaseImpl::class.java)
|
private val LOGGER: Logger = Logger.getInstance(KotlinStubBaseImpl::class.java)
|
||||||
|
|
||||||
private val BASE_STUB_INTERFACES = listOf(KotlinStubWithFqName::class.java, KotlinClassOrObjectStub::class.java, NamedStub::class.java, KotlinCallableStubBase::class.java)
|
private val BASE_STUB_INTERFACES = listOf(
|
||||||
|
KotlinStubWithFqName::class.java,
|
||||||
|
KotlinClassOrObjectStub::class.java,
|
||||||
|
NamedStub::class.java,
|
||||||
|
KotlinCallableStubBase::class.java
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,5 +23,5 @@ import org.jetbrains.kotlin.psi.stubs.KotlinUserTypeStub
|
|||||||
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
|
||||||
|
|
||||||
class KotlinUserTypeStubImpl(
|
class KotlinUserTypeStubImpl(
|
||||||
parent: StubElement<out PsiElement>?
|
parent: StubElement<out PsiElement>?
|
||||||
) : KotlinStubBaseImpl<KtUserType>(parent, KtStubElementTypes.USER_TYPE), KotlinUserTypeStub
|
) : KotlinStubBaseImpl<KtUserType>(parent, KtStubElementTypes.USER_TYPE), KotlinUserTypeStub
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.psi.stubs.impl
|
|||||||
import com.intellij.util.io.StringRef
|
import com.intellij.util.io.StringRef
|
||||||
|
|
||||||
object Utils {
|
object Utils {
|
||||||
fun wrapStrings(names : List<String>) : Array<StringRef> {
|
fun wrapStrings(names: List<String>): Array<StringRef> {
|
||||||
return Array(names.size) { i -> StringRef.fromString(names[i])!! }
|
return Array(names.size) { i -> StringRef.fromString(names[i])!! }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-20
@@ -45,25 +45,27 @@ import org.jetbrains.kotlin.types.TypeConstructor
|
|||||||
* This class has its own synthetic declaration inside.
|
* This class has its own synthetic declaration inside.
|
||||||
*/
|
*/
|
||||||
class SyntheticClassOrObjectDescriptor(
|
class SyntheticClassOrObjectDescriptor(
|
||||||
c: LazyClassContext,
|
c: LazyClassContext,
|
||||||
parentClassOrObject: KtPureClassOrObject,
|
parentClassOrObject: KtPureClassOrObject,
|
||||||
containingDeclaration: DeclarationDescriptor,
|
containingDeclaration: DeclarationDescriptor,
|
||||||
name: Name,
|
name: Name,
|
||||||
source: SourceElement,
|
source: SourceElement,
|
||||||
outerScope: LexicalScope,
|
outerScope: LexicalScope,
|
||||||
private val modality: Modality,
|
private val modality: Modality,
|
||||||
private val visibility: Visibility,
|
private val visibility: Visibility,
|
||||||
constructorVisibility: Visibility,
|
constructorVisibility: Visibility,
|
||||||
private val kind: ClassKind,
|
private val kind: ClassKind,
|
||||||
private val isCompanionObject: Boolean
|
private val isCompanionObject: Boolean
|
||||||
) : ClassDescriptorBase(c.storageManager, containingDeclaration, name, source, false), ClassDescriptorWithResolutionScopes {
|
) : ClassDescriptorBase(c.storageManager, containingDeclaration, name, source, false), ClassDescriptorWithResolutionScopes {
|
||||||
val syntheticDeclaration: KtPureClassOrObject = SyntheticDeclaration(parentClassOrObject, name.asString())
|
val syntheticDeclaration: KtPureClassOrObject = SyntheticDeclaration(parentClassOrObject, name.asString())
|
||||||
|
|
||||||
private val thisDescriptor: SyntheticClassOrObjectDescriptor get() = this // code readability
|
private val thisDescriptor: SyntheticClassOrObjectDescriptor get() = this // code readability
|
||||||
private val typeConstructor = SyntheticTypeConstructor(c.storageManager)
|
private val typeConstructor = SyntheticTypeConstructor(c.storageManager)
|
||||||
private val resolutionScopesSupport = ClassResolutionScopesSupport(thisDescriptor, c.storageManager, { outerScope })
|
private val resolutionScopesSupport = ClassResolutionScopesSupport(thisDescriptor, c.storageManager, { outerScope })
|
||||||
private val syntheticSupertypes = mutableListOf<KotlinType>().apply { c.syntheticResolveExtension.addSyntheticSupertypes(thisDescriptor, this) }
|
private val syntheticSupertypes =
|
||||||
private val unsubstitutedMemberScope = LazyClassMemberScope(c, SyntheticClassMemberDeclarationProvider(syntheticDeclaration), this, c.trace)
|
mutableListOf<KotlinType>().apply { c.syntheticResolveExtension.addSyntheticSupertypes(thisDescriptor, this) }
|
||||||
|
private val unsubstitutedMemberScope =
|
||||||
|
LazyClassMemberScope(c, SyntheticClassMemberDeclarationProvider(syntheticDeclaration), this, c.trace)
|
||||||
private val unsubstitutedPrimaryConstructor = createUnsubstitutedPrimaryConstructor(constructorVisibility)
|
private val unsubstitutedPrimaryConstructor = createUnsubstitutedPrimaryConstructor(constructorVisibility)
|
||||||
|
|
||||||
override val annotations: Annotations get() = Annotations.EMPTY
|
override val annotations: Annotations get() = Annotations.EMPTY
|
||||||
@@ -97,11 +99,15 @@ class SyntheticClassOrObjectDescriptor(
|
|||||||
|
|
||||||
override fun getScopeForClassHeaderResolution(): LexicalScope = resolutionScopesSupport.scopeForClassHeaderResolution()
|
override fun getScopeForClassHeaderResolution(): LexicalScope = resolutionScopesSupport.scopeForClassHeaderResolution()
|
||||||
override fun getScopeForConstructorHeaderResolution(): LexicalScope = resolutionScopesSupport.scopeForConstructorHeaderResolution()
|
override fun getScopeForConstructorHeaderResolution(): LexicalScope = resolutionScopesSupport.scopeForConstructorHeaderResolution()
|
||||||
override fun getScopeForCompanionObjectHeaderResolution(): LexicalScope = resolutionScopesSupport.scopeForCompanionObjectHeaderResolution()
|
override fun getScopeForCompanionObjectHeaderResolution(): LexicalScope =
|
||||||
override fun getScopeForMemberDeclarationResolution(): LexicalScope = resolutionScopesSupport.scopeForMemberDeclarationResolution()
|
resolutionScopesSupport.scopeForCompanionObjectHeaderResolution()
|
||||||
override fun getScopeForStaticMemberDeclarationResolution(): LexicalScope = resolutionScopesSupport.scopeForStaticMemberDeclarationResolution()
|
|
||||||
|
|
||||||
override fun getScopeForInitializerResolution(): LexicalScope = throw UnsupportedOperationException("Not supported for synthetic class or object")
|
override fun getScopeForMemberDeclarationResolution(): LexicalScope = resolutionScopesSupport.scopeForMemberDeclarationResolution()
|
||||||
|
override fun getScopeForStaticMemberDeclarationResolution(): LexicalScope =
|
||||||
|
resolutionScopesSupport.scopeForStaticMemberDeclarationResolution()
|
||||||
|
|
||||||
|
override fun getScopeForInitializerResolution(): LexicalScope =
|
||||||
|
throw UnsupportedOperationException("Not supported for synthetic class or object")
|
||||||
|
|
||||||
override fun toString(): String = "synthetic class " + name.toString() + " in " + containingDeclaration
|
override fun toString(): String = "synthetic class " + name.toString() + " in " + containingDeclaration
|
||||||
|
|
||||||
@@ -121,7 +127,7 @@ class SyntheticClassOrObjectDescriptor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class SyntheticClassMemberDeclarationProvider(
|
private class SyntheticClassMemberDeclarationProvider(
|
||||||
override val correspondingClassOrObject: KtPureClassOrObject
|
override val correspondingClassOrObject: KtPureClassOrObject
|
||||||
) : ClassMemberDeclarationProvider {
|
) : ClassMemberDeclarationProvider {
|
||||||
override val ownerInfo: KtClassLikeInfo? = null
|
override val ownerInfo: KtClassLikeInfo? = null
|
||||||
override fun getDeclarations(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): List<KtDeclaration> = emptyList()
|
override fun getDeclarations(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): List<KtDeclaration> = emptyList()
|
||||||
@@ -134,8 +140,8 @@ class SyntheticClassOrObjectDescriptor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal inner class SyntheticDeclaration(
|
internal inner class SyntheticDeclaration(
|
||||||
private val _parent: KtPureElement,
|
private val _parent: KtPureElement,
|
||||||
private val _name: String
|
private val _name: String
|
||||||
) : KtPureClassOrObject {
|
) : KtPureClassOrObject {
|
||||||
fun descriptor() = thisDescriptor
|
fun descriptor() = thisDescriptor
|
||||||
|
|
||||||
|
|||||||
@@ -28,14 +28,13 @@ import org.jetbrains.kotlin.utils.Printer
|
|||||||
import org.jetbrains.kotlin.utils.addToStdlib.flatMapToNullable
|
import org.jetbrains.kotlin.utils.addToStdlib.flatMapToNullable
|
||||||
|
|
||||||
class AllUnderImportScope(
|
class AllUnderImportScope(
|
||||||
descriptor: DeclarationDescriptor,
|
descriptor: DeclarationDescriptor,
|
||||||
excludedImportNames: Collection<FqName>
|
excludedImportNames: Collection<FqName>
|
||||||
) : BaseImportingScope(null) {
|
) : BaseImportingScope(null) {
|
||||||
|
|
||||||
private val scopes: List<MemberScope> = if (descriptor is ClassDescriptor) {
|
private val scopes: List<MemberScope> = if (descriptor is ClassDescriptor) {
|
||||||
listOf(descriptor.staticScope, descriptor.unsubstitutedInnerClassesScope)
|
listOf(descriptor.staticScope, descriptor.unsubstitutedInnerClassesScope)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
assert(descriptor is PackageViewDescriptor) {
|
assert(descriptor is PackageViewDescriptor) {
|
||||||
"Must be class or package view descriptor: $descriptor"
|
"Must be class or package view descriptor: $descriptor"
|
||||||
}
|
}
|
||||||
@@ -44,8 +43,7 @@ class AllUnderImportScope(
|
|||||||
|
|
||||||
private val excludedNames: Set<Name> = if (excludedImportNames.isEmpty()) { // optimization
|
private val excludedNames: Set<Name> = if (excludedImportNames.isEmpty()) { // optimization
|
||||||
emptySet<Name>()
|
emptySet<Name>()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val fqName = DescriptorUtils.getFqNameSafe(descriptor)
|
val fqName = DescriptorUtils.getFqNameSafe(descriptor)
|
||||||
// toSet() is used here instead mapNotNullTo(hashSetOf()) because it results in not keeping empty sets as separate instances
|
// toSet() is used here instead mapNotNullTo(hashSetOf()) because it results in not keeping empty sets as separate instances
|
||||||
excludedImportNames.mapNotNull { if (it.parent() == fqName) it.shortName() else null }.toSet()
|
excludedImportNames.mapNotNull { if (it.parent() == fqName) it.shortName() else null }.toSet()
|
||||||
@@ -54,21 +52,20 @@ class AllUnderImportScope(
|
|||||||
override fun computeImportedNames(): Set<Name>? = scopes.flatMapToNullable(hashSetOf(), MemberScope::computeAllNames)
|
override fun computeImportedNames(): Set<Name>? = scopes.flatMapToNullable(hashSetOf(), MemberScope::computeAllNames)
|
||||||
|
|
||||||
override fun getContributedDescriptors(
|
override fun getContributedDescriptors(
|
||||||
kindFilter: DescriptorKindFilter,
|
kindFilter: DescriptorKindFilter,
|
||||||
nameFilter: (Name) -> Boolean,
|
nameFilter: (Name) -> Boolean,
|
||||||
changeNamesForAliased: Boolean
|
changeNamesForAliased: Boolean
|
||||||
): Collection<DeclarationDescriptor> {
|
): Collection<DeclarationDescriptor> {
|
||||||
val nameFilterToUse = if (excludedNames.isEmpty()) { // optimization
|
val nameFilterToUse = if (excludedNames.isEmpty()) { // optimization
|
||||||
nameFilter
|
nameFilter
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
{ it !in excludedNames && nameFilter(it) }
|
{ it !in excludedNames && nameFilter(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
val noPackagesKindFilter = kindFilter.withoutKinds(DescriptorKindFilter.PACKAGES_MASK)
|
val noPackagesKindFilter = kindFilter.withoutKinds(DescriptorKindFilter.PACKAGES_MASK)
|
||||||
return scopes
|
return scopes
|
||||||
.flatMap { it.getContributedDescriptors(noPackagesKindFilter, nameFilterToUse) }
|
.flatMap { it.getContributedDescriptors(noPackagesKindFilter, nameFilterToUse) }
|
||||||
.filter { it !is PackageViewDescriptor } // subpackages are not imported
|
.filter { it !is PackageViewDescriptor } // subpackages are not imported
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? {
|
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? {
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.types.KotlinType
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class CompositeBindingContext private constructor(
|
class CompositeBindingContext private constructor(
|
||||||
private val delegates: LinkedHashSet<BindingContext>
|
private val delegates: LinkedHashSet<BindingContext>
|
||||||
) : BindingContext {
|
) : BindingContext {
|
||||||
override fun getType(expression: KtExpression): KotlinType? {
|
override fun getType(expression: KtExpression): KotlinType? {
|
||||||
return delegates.asSequence().map { it.getType(expression) }.firstOrNull { it != null }
|
return delegates.asSequence().map { it.getType(expression) }.firstOrNull { it != null }
|
||||||
@@ -67,7 +67,7 @@ class CompositeBindingContext private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class CompositeDiagnostics(
|
private class CompositeDiagnostics(
|
||||||
private val delegates: List<Diagnostics>
|
private val delegates: List<Diagnostics>
|
||||||
) : Diagnostics {
|
) : Diagnostics {
|
||||||
|
|
||||||
override fun iterator(): Iterator<Diagnostic> {
|
override fun iterator(): Iterator<Diagnostic> {
|
||||||
|
|||||||
@@ -34,22 +34,18 @@ object DataClassDescriptorResolver {
|
|||||||
|
|
||||||
private val COMPONENT_FUNCTION_NAME_PREFIX = "component"
|
private val COMPONENT_FUNCTION_NAME_PREFIX = "component"
|
||||||
|
|
||||||
fun createComponentName(index: Int): Name
|
fun createComponentName(index: Int): Name = Name.identifier(COMPONENT_FUNCTION_NAME_PREFIX + index)
|
||||||
= Name.identifier(COMPONENT_FUNCTION_NAME_PREFIX + index)
|
|
||||||
|
|
||||||
fun getComponentIndex(componentName: String): Int
|
fun getComponentIndex(componentName: String): Int = componentName.substring(COMPONENT_FUNCTION_NAME_PREFIX.length).toInt()
|
||||||
= componentName.substring(COMPONENT_FUNCTION_NAME_PREFIX.length).toInt()
|
|
||||||
|
|
||||||
fun isComponentLike(name: Name): Boolean
|
fun isComponentLike(name: Name): Boolean = isComponentLike(name.asString())
|
||||||
= isComponentLike(name.asString())
|
|
||||||
|
|
||||||
private fun isComponentLike(name: String): Boolean {
|
private fun isComponentLike(name: String): Boolean {
|
||||||
if (!name.startsWith(COMPONENT_FUNCTION_NAME_PREFIX)) return false
|
if (!name.startsWith(COMPONENT_FUNCTION_NAME_PREFIX)) return false
|
||||||
|
|
||||||
try {
|
try {
|
||||||
getComponentIndex(name)
|
getComponentIndex(name)
|
||||||
}
|
} catch (e: NumberFormatException) {
|
||||||
catch (e: NumberFormatException) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,58 +53,58 @@ object DataClassDescriptorResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createEqualsFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor =
|
fun createEqualsFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor =
|
||||||
doCreateFunctionFromAny(classDescriptor, EQUALS_METHOD_NAME)
|
doCreateFunctionFromAny(classDescriptor, EQUALS_METHOD_NAME)
|
||||||
|
|
||||||
fun createHashCodeFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor =
|
fun createHashCodeFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor =
|
||||||
doCreateFunctionFromAny(classDescriptor, HASH_CODE_METHOD_NAME)
|
doCreateFunctionFromAny(classDescriptor, HASH_CODE_METHOD_NAME)
|
||||||
|
|
||||||
fun createToStringFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor =
|
fun createToStringFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor =
|
||||||
doCreateFunctionFromAny(classDescriptor, TO_STRING_METHOD_NAME)
|
doCreateFunctionFromAny(classDescriptor, TO_STRING_METHOD_NAME)
|
||||||
|
|
||||||
private fun doCreateFunctionFromAny(classDescriptor: ClassDescriptor, name: Name): SimpleFunctionDescriptor {
|
private fun doCreateFunctionFromAny(classDescriptor: ClassDescriptor, name: Name): SimpleFunctionDescriptor {
|
||||||
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
|
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||||
classDescriptor, Annotations.EMPTY, name, CallableMemberDescriptor.Kind.SYNTHESIZED, classDescriptor.source
|
classDescriptor, Annotations.EMPTY, name, CallableMemberDescriptor.Kind.SYNTHESIZED, classDescriptor.source
|
||||||
)
|
)
|
||||||
|
|
||||||
val functionFromAny = classDescriptor.builtIns.any.getMemberScope(emptyList())
|
val functionFromAny = classDescriptor.builtIns.any.getMemberScope(emptyList())
|
||||||
.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS).single()
|
.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS).single()
|
||||||
|
|
||||||
functionDescriptor.initialize(
|
functionDescriptor.initialize(
|
||||||
null,
|
null,
|
||||||
classDescriptor.thisAsReceiverParameter,
|
classDescriptor.thisAsReceiverParameter,
|
||||||
functionFromAny.typeParameters,
|
functionFromAny.typeParameters,
|
||||||
functionFromAny.valueParameters.map { it.copy(functionDescriptor, it.name, it.index) },
|
functionFromAny.valueParameters.map { it.copy(functionDescriptor, it.name, it.index) },
|
||||||
functionFromAny.returnType,
|
functionFromAny.returnType,
|
||||||
Modality.OPEN,
|
Modality.OPEN,
|
||||||
Visibilities.PUBLIC
|
Visibilities.PUBLIC
|
||||||
)
|
)
|
||||||
|
|
||||||
return functionDescriptor
|
return functionDescriptor
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createComponentFunctionDescriptor(
|
fun createComponentFunctionDescriptor(
|
||||||
parameterIndex: Int,
|
parameterIndex: Int,
|
||||||
property: PropertyDescriptor,
|
property: PropertyDescriptor,
|
||||||
parameter: ValueParameterDescriptor,
|
parameter: ValueParameterDescriptor,
|
||||||
classDescriptor: ClassDescriptor,
|
classDescriptor: ClassDescriptor,
|
||||||
trace: BindingTrace
|
trace: BindingTrace
|
||||||
): SimpleFunctionDescriptor {
|
): SimpleFunctionDescriptor {
|
||||||
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
|
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||||
classDescriptor,
|
classDescriptor,
|
||||||
Annotations.EMPTY,
|
Annotations.EMPTY,
|
||||||
createComponentName(parameterIndex),
|
createComponentName(parameterIndex),
|
||||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||||
parameter.source
|
parameter.source
|
||||||
)
|
)
|
||||||
|
|
||||||
functionDescriptor.initialize(
|
functionDescriptor.initialize(
|
||||||
null,
|
null,
|
||||||
classDescriptor.thisAsReceiverParameter,
|
classDescriptor.thisAsReceiverParameter,
|
||||||
emptyList<TypeParameterDescriptor>(),
|
emptyList<TypeParameterDescriptor>(),
|
||||||
emptyList<ValueParameterDescriptor>(),
|
emptyList<ValueParameterDescriptor>(),
|
||||||
property.type,
|
property.type,
|
||||||
Modality.FINAL,
|
Modality.FINAL,
|
||||||
property.visibility
|
property.visibility
|
||||||
)
|
)
|
||||||
functionDescriptor.isOperator = true
|
functionDescriptor.isOperator = true
|
||||||
|
|
||||||
@@ -117,16 +113,16 @@ object DataClassDescriptorResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createCopyFunctionDescriptor(
|
fun createCopyFunctionDescriptor(
|
||||||
constructorParameters: Collection<ValueParameterDescriptor>,
|
constructorParameters: Collection<ValueParameterDescriptor>,
|
||||||
classDescriptor: ClassDescriptor,
|
classDescriptor: ClassDescriptor,
|
||||||
trace: BindingTrace
|
trace: BindingTrace
|
||||||
): SimpleFunctionDescriptor {
|
): SimpleFunctionDescriptor {
|
||||||
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
|
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||||
classDescriptor,
|
classDescriptor,
|
||||||
Annotations.EMPTY,
|
Annotations.EMPTY,
|
||||||
COPY_METHOD_NAME,
|
COPY_METHOD_NAME,
|
||||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||||
classDescriptor.source
|
classDescriptor.source
|
||||||
)
|
)
|
||||||
|
|
||||||
val parameterDescriptors = arrayListOf<ValueParameterDescriptor>()
|
val parameterDescriptors = arrayListOf<ValueParameterDescriptor>()
|
||||||
@@ -136,8 +132,8 @@ object DataClassDescriptorResolver {
|
|||||||
// If a parameter doesn't have the corresponding property, it must not have a default value in the 'copy' function
|
// If a parameter doesn't have the corresponding property, it must not have a default value in the 'copy' function
|
||||||
val declaresDefaultValue = propertyDescriptor != null
|
val declaresDefaultValue = propertyDescriptor != null
|
||||||
val parameterDescriptor = ValueParameterDescriptorImpl(
|
val parameterDescriptor = ValueParameterDescriptorImpl(
|
||||||
functionDescriptor, null, parameter.index, parameter.annotations, parameter.name, parameter.type, declaresDefaultValue,
|
functionDescriptor, null, parameter.index, parameter.annotations, parameter.name, parameter.type, declaresDefaultValue,
|
||||||
parameter.isCrossinline, parameter.isNoinline, parameter.varargElementType, parameter.source
|
parameter.isCrossinline, parameter.isNoinline, parameter.varargElementType, parameter.source
|
||||||
)
|
)
|
||||||
parameterDescriptors.add(parameterDescriptor)
|
parameterDescriptors.add(parameterDescriptor)
|
||||||
if (declaresDefaultValue) {
|
if (declaresDefaultValue) {
|
||||||
@@ -146,13 +142,13 @@ object DataClassDescriptorResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
functionDescriptor.initialize(
|
functionDescriptor.initialize(
|
||||||
null,
|
null,
|
||||||
classDescriptor.thisAsReceiverParameter,
|
classDescriptor.thisAsReceiverParameter,
|
||||||
emptyList<TypeParameterDescriptor>(),
|
emptyList<TypeParameterDescriptor>(),
|
||||||
parameterDescriptors,
|
parameterDescriptors,
|
||||||
classDescriptor.defaultType,
|
classDescriptor.defaultType,
|
||||||
Modality.FINAL,
|
Modality.FINAL,
|
||||||
Visibilities.PUBLIC
|
Visibilities.PUBLIC
|
||||||
)
|
)
|
||||||
|
|
||||||
trace.record(BindingContext.DATA_CLASS_COPY_FUNCTION, classDescriptor, functionDescriptor)
|
trace.record(BindingContext.DATA_CLASS_COPY_FUNCTION, classDescriptor, functionDescriptor)
|
||||||
|
|||||||
@@ -38,8 +38,8 @@ import org.jetbrains.kotlin.utils.keysToMap
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class DeclarationResolver(
|
class DeclarationResolver(
|
||||||
private val annotationResolver: AnnotationResolver,
|
private val annotationResolver: AnnotationResolver,
|
||||||
private val trace: BindingTrace
|
private val trace: BindingTrace
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun resolveAnnotationsOnFiles(c: TopDownAnalysisContext, scopeProvider: FileScopeProvider) {
|
fun resolveAnnotationsOnFiles(c: TopDownAnalysisContext, scopeProvider: FileScopeProvider) {
|
||||||
@@ -74,14 +74,17 @@ class DeclarationResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkRedeclarationsInPackages(topLevelDescriptorProvider: TopLevelDescriptorProvider, topLevelFqNames: Multimap<FqName, KtElement>) {
|
fun checkRedeclarationsInPackages(
|
||||||
|
topLevelDescriptorProvider: TopLevelDescriptorProvider,
|
||||||
|
topLevelFqNames: Multimap<FqName, KtElement>
|
||||||
|
) {
|
||||||
for ((fqName, declarationsOrPackageDirectives) in topLevelFqNames.asMap()) {
|
for ((fqName, declarationsOrPackageDirectives) in topLevelFqNames.asMap()) {
|
||||||
if (fqName.isRoot) continue
|
if (fqName.isRoot) continue
|
||||||
|
|
||||||
// TODO: report error on expected class and actual val, or vice versa
|
// TODO: report error on expected class and actual val, or vice versa
|
||||||
val (expected, actual) =
|
val (expected, actual) =
|
||||||
getTopLevelDescriptorsByFqName(topLevelDescriptorProvider, fqName, NoLookupLocation.WHEN_CHECK_DECLARATION_CONFLICTS)
|
getTopLevelDescriptorsByFqName(topLevelDescriptorProvider, fqName, NoLookupLocation.WHEN_CHECK_DECLARATION_CONFLICTS)
|
||||||
.partition { it is MemberDescriptor && it.isExpect }
|
.partition { it is MemberDescriptor && it.isExpect }
|
||||||
|
|
||||||
for (descriptors in listOf(expected, actual)) {
|
for (descriptors in listOf(expected, actual)) {
|
||||||
if (descriptors.size > 1) {
|
if (descriptors.size > 1) {
|
||||||
@@ -94,7 +97,11 @@ class DeclarationResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getTopLevelDescriptorsByFqName(topLevelDescriptorProvider: TopLevelDescriptorProvider, fqName: FqName, location: LookupLocation): Set<DeclarationDescriptor> {
|
private fun getTopLevelDescriptorsByFqName(
|
||||||
|
topLevelDescriptorProvider: TopLevelDescriptorProvider,
|
||||||
|
fqName: FqName,
|
||||||
|
location: LookupLocation
|
||||||
|
): Set<DeclarationDescriptor> {
|
||||||
val descriptors = HashSet<DeclarationDescriptor>()
|
val descriptors = HashSet<DeclarationDescriptor>()
|
||||||
|
|
||||||
descriptors.addIfNotNull(topLevelDescriptorProvider.getPackageFragment(fqName))
|
descriptors.addIfNotNull(topLevelDescriptorProvider.getPackageFragment(fqName))
|
||||||
|
|||||||
@@ -45,29 +45,29 @@ import org.jetbrains.kotlin.types.typeUtil.*
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
internal class DeclarationsCheckerBuilder(
|
internal class DeclarationsCheckerBuilder(
|
||||||
private val descriptorResolver: DescriptorResolver,
|
private val descriptorResolver: DescriptorResolver,
|
||||||
private val originalModifiersChecker: ModifiersChecker,
|
private val originalModifiersChecker: ModifiersChecker,
|
||||||
private val annotationChecker: AnnotationChecker,
|
private val annotationChecker: AnnotationChecker,
|
||||||
private val identifierChecker: IdentifierChecker,
|
private val identifierChecker: IdentifierChecker,
|
||||||
private val languageVersionSettings: LanguageVersionSettings,
|
private val languageVersionSettings: LanguageVersionSettings,
|
||||||
private val typeSpecificityComparator: TypeSpecificityComparator,
|
private val typeSpecificityComparator: TypeSpecificityComparator,
|
||||||
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
|
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
|
||||||
) {
|
) {
|
||||||
fun withTrace(trace: BindingTrace) = DeclarationsChecker(
|
fun withTrace(trace: BindingTrace) = DeclarationsChecker(
|
||||||
descriptorResolver, originalModifiersChecker, annotationChecker, identifierChecker, trace, languageVersionSettings,
|
descriptorResolver, originalModifiersChecker, annotationChecker, identifierChecker, trace, languageVersionSettings,
|
||||||
typeSpecificityComparator, diagnosticSuppressor
|
typeSpecificityComparator, diagnosticSuppressor
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
class DeclarationsChecker(
|
class DeclarationsChecker(
|
||||||
private val descriptorResolver: DescriptorResolver,
|
private val descriptorResolver: DescriptorResolver,
|
||||||
modifiersChecker: ModifiersChecker,
|
modifiersChecker: ModifiersChecker,
|
||||||
private val annotationChecker: AnnotationChecker,
|
private val annotationChecker: AnnotationChecker,
|
||||||
private val identifierChecker: IdentifierChecker,
|
private val identifierChecker: IdentifierChecker,
|
||||||
private val trace: BindingTrace,
|
private val trace: BindingTrace,
|
||||||
private val languageVersionSettings: LanguageVersionSettings,
|
private val languageVersionSettings: LanguageVersionSettings,
|
||||||
typeSpecificityComparator: TypeSpecificityComparator,
|
typeSpecificityComparator: TypeSpecificityComparator,
|
||||||
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
|
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val modifiersChecker = modifiersChecker.withTrace(trace)
|
private val modifiersChecker = modifiersChecker.withTrace(trace)
|
||||||
@@ -102,9 +102,9 @@ class DeclarationsChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val destructuringDeclarations = bodiesResolveContext.destructuringDeclarationEntries.entries
|
val destructuringDeclarations = bodiesResolveContext.destructuringDeclarationEntries.entries
|
||||||
.map { (entry, _) -> entry.parent }
|
.map { (entry, _) -> entry.parent }
|
||||||
.filterIsInstance<KtDestructuringDeclaration>()
|
.filterIsInstance<KtDestructuringDeclaration>()
|
||||||
.distinct()
|
.distinct()
|
||||||
|
|
||||||
for (multiDeclaration in destructuringDeclarations) {
|
for (multiDeclaration in destructuringDeclarations) {
|
||||||
modifiersChecker.checkModifiersForDestructuringDeclaration(multiDeclaration)
|
modifiersChecker.checkModifiersForDestructuringDeclaration(multiDeclaration)
|
||||||
@@ -143,7 +143,7 @@ class DeclarationsChecker(
|
|||||||
trace.report(TYPEALIAS_SHOULD_EXPAND_TO_CLASS.on(typeReference, expandedType))
|
trace.report(TYPEALIAS_SHOULD_EXPAND_TO_CLASS.on(typeReference, expandedType))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (TypeUtils.contains(expandedType) { it.isArrayOfNothing()} ) {
|
if (TypeUtils.contains(expandedType) { it.isArrayOfNothing() }) {
|
||||||
trace.report(TYPEALIAS_EXPANDED_TO_MALFORMED_TYPE.on(typeReference, expandedType, "Array<Nothing> is illegal"))
|
trace.report(TYPEALIAS_EXPANDED_TO_MALFORMED_TYPE.on(typeReference, expandedType, "Array<Nothing> is illegal"))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,7 +151,7 @@ class DeclarationsChecker(
|
|||||||
for (typeParameter in typeAliasDescriptor.declaredTypeParameters) {
|
for (typeParameter in typeAliasDescriptor.declaredTypeParameters) {
|
||||||
if (typeParameter !in usedTypeAliasParameters) {
|
if (typeParameter !in usedTypeAliasParameters) {
|
||||||
val source = DescriptorToSourceUtils.descriptorToDeclaration(typeParameter) as? KtTypeParameter
|
val source = DescriptorToSourceUtils.descriptorToDeclaration(typeParameter) as? KtTypeParameter
|
||||||
?: throw AssertionError("No source element for type parameter $typeParameter of $typeAliasDescriptor")
|
?: throw AssertionError("No source element for type parameter $typeParameter of $typeAliasDescriptor")
|
||||||
trace.report(UNUSED_TYPEALIAS_PARAMETER.on(source, typeParameter, expandedType))
|
trace.report(UNUSED_TYPEALIAS_PARAMETER.on(source, typeParameter, expandedType))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,31 +180,35 @@ class DeclarationsChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rhs.arguments.map { it.type.constructor.declarationDescriptor as? TypeParameterDescriptor } !=
|
if (rhs.arguments.map { it.type.constructor.declarationDescriptor as? TypeParameterDescriptor } !=
|
||||||
typeAliasDescriptor.declaredTypeParameters) {
|
typeAliasDescriptor.declaredTypeParameters) {
|
||||||
trace.report(ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION.on(declaration))
|
trace.report(ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION.on(declaration))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getUsedTypeAliasParameters(type: KotlinType, typeAlias: TypeAliasDescriptor): Set<TypeParameterDescriptor> =
|
private fun getUsedTypeAliasParameters(type: KotlinType, typeAlias: TypeAliasDescriptor): Set<TypeParameterDescriptor> =
|
||||||
type.constituentTypes().mapNotNullTo(HashSet()) {
|
type.constituentTypes().mapNotNullTo(HashSet()) {
|
||||||
val descriptor = it.constructor.declarationDescriptor as? TypeParameterDescriptor
|
val descriptor = it.constructor.declarationDescriptor as? TypeParameterDescriptor
|
||||||
descriptor?.takeIf { it.containingDeclaration == typeAlias }
|
descriptor?.takeIf { it.containingDeclaration == typeAlias }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TypeAliasDeclarationCheckingReportStrategy(
|
private class TypeAliasDeclarationCheckingReportStrategy(
|
||||||
private val trace: BindingTrace,
|
private val trace: BindingTrace,
|
||||||
typeAliasDescriptor: TypeAliasDescriptor,
|
typeAliasDescriptor: TypeAliasDescriptor,
|
||||||
declaration: KtTypeAlias
|
declaration: KtTypeAlias
|
||||||
) : TypeAliasExpansionReportStrategy {
|
) : TypeAliasExpansionReportStrategy {
|
||||||
private val typeReference = declaration.getTypeReference()
|
private val typeReference = declaration.getTypeReference()
|
||||||
?: throw AssertionError("Incorrect type alias declaration for $typeAliasDescriptor")
|
?: throw AssertionError("Incorrect type alias declaration for $typeAliasDescriptor")
|
||||||
|
|
||||||
override fun wrongNumberOfTypeArguments(typeAlias: TypeAliasDescriptor, numberOfParameters: Int) {
|
override fun wrongNumberOfTypeArguments(typeAlias: TypeAliasDescriptor, numberOfParameters: Int) {
|
||||||
// Do nothing: this should've been reported during type resolution.
|
// Do nothing: this should've been reported during type resolution.
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, substitutedArgument: KotlinType) {
|
override fun conflictingProjection(
|
||||||
|
typeAlias: TypeAliasDescriptor,
|
||||||
|
typeParameter: TypeParameterDescriptor?,
|
||||||
|
substitutedArgument: KotlinType
|
||||||
|
) {
|
||||||
trace.report(CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION.on(typeReference, substitutedArgument))
|
trace.report(CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION.on(typeReference, substitutedArgument))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,7 +216,12 @@ class DeclarationsChecker(
|
|||||||
trace.report(RECURSIVE_TYPEALIAS_EXPANSION.on(typeReference, typeAlias))
|
trace.report(RECURSIVE_TYPEALIAS_EXPANSION.on(typeReference, typeAlias))
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun boundsViolationInSubstitution(bound: KotlinType, unsubstitutedArgument: KotlinType, argument: KotlinType, typeParameter: TypeParameterDescriptor) {
|
override fun boundsViolationInSubstitution(
|
||||||
|
bound: KotlinType,
|
||||||
|
unsubstitutedArgument: KotlinType,
|
||||||
|
argument: KotlinType,
|
||||||
|
typeParameter: TypeParameterDescriptor
|
||||||
|
) {
|
||||||
// TODO more precise diagnostics
|
// TODO more precise diagnostics
|
||||||
if (!argument.containsTypeAliasParameters() && !bound.containsTypeAliasParameters()) {
|
if (!argument.containsTypeAliasParameters() && !bound.containsTypeAliasParameters()) {
|
||||||
trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(typeReference, bound, argument, typeParameter))
|
trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(typeReference, bound, argument, typeParameter))
|
||||||
@@ -272,8 +281,7 @@ class DeclarationsChecker(
|
|||||||
val classDescriptor = constructorDescriptor.containingDeclaration
|
val classDescriptor = constructorDescriptor.containingDeclaration
|
||||||
if (classDescriptor.kind == ClassKind.ENUM_CLASS) {
|
if (classDescriptor.kind == ClassKind.ENUM_CLASS) {
|
||||||
trace.report(NON_PRIVATE_CONSTRUCTOR_IN_ENUM.on(visibilityModifier))
|
trace.report(NON_PRIVATE_CONSTRUCTOR_IN_ENUM.on(visibilityModifier))
|
||||||
}
|
} else if (classDescriptor.modality == Modality.SEALED) {
|
||||||
else if (classDescriptor.modality == Modality.SEALED) {
|
|
||||||
trace.report(NON_PRIVATE_CONSTRUCTOR_IN_SEALED.on(visibilityModifier))
|
trace.report(NON_PRIVATE_CONSTRUCTOR_IN_SEALED.on(visibilityModifier))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -301,7 +309,8 @@ class DeclarationsChecker(
|
|||||||
is KtClass -> {
|
is KtClass -> {
|
||||||
checkClassButNotObject(classOrObject, classDescriptor)
|
checkClassButNotObject(classOrObject, classDescriptor)
|
||||||
descriptorResolver.checkNamesInConstraints(
|
descriptorResolver.checkNamesInConstraints(
|
||||||
classOrObject, classDescriptor, classDescriptor.scopeForClassHeaderResolution, trace)
|
classOrObject, classDescriptor, classDescriptor.scopeForClassHeaderResolution, trace
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is KtObjectDeclaration -> {
|
is KtObjectDeclaration -> {
|
||||||
checkObject(classOrObject, classDescriptor)
|
checkObject(classOrObject, classDescriptor)
|
||||||
@@ -346,32 +355,31 @@ class DeclarationsChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkOnlyOneTypeParameterBound(
|
private fun checkOnlyOneTypeParameterBound(
|
||||||
descriptor: TypeParameterDescriptor, declaration: KtTypeParameter, owner: KtTypeParameterListOwner
|
descriptor: TypeParameterDescriptor, declaration: KtTypeParameter, owner: KtTypeParameterListOwner
|
||||||
) {
|
) {
|
||||||
val upperBounds = descriptor.upperBounds
|
val upperBounds = descriptor.upperBounds
|
||||||
val (boundsWhichAreTypeParameters, otherBounds) = upperBounds
|
val (boundsWhichAreTypeParameters, otherBounds) = upperBounds
|
||||||
.map(KotlinType::constructor)
|
.map(KotlinType::constructor)
|
||||||
.partition { constructor -> constructor.declarationDescriptor is TypeParameterDescriptor }
|
.partition { constructor -> constructor.declarationDescriptor is TypeParameterDescriptor }
|
||||||
.let { pair -> pair.first.toSet() to pair.second.toSet() }
|
.let { pair -> pair.first.toSet() to pair.second.toSet() }
|
||||||
if (boundsWhichAreTypeParameters.size > 1 || (boundsWhichAreTypeParameters.size == 1 && otherBounds.isNotEmpty())) {
|
if (boundsWhichAreTypeParameters.size > 1 || (boundsWhichAreTypeParameters.size == 1 && otherBounds.isNotEmpty())) {
|
||||||
val reportOn = if (boundsWhichAreTypeParameters.size + otherBounds.size == 2) {
|
val reportOn = if (boundsWhichAreTypeParameters.size + otherBounds.size == 2) {
|
||||||
// If there's only one problematic bound (either 2 type parameter bounds, or 1 type parameter bound + 1 other bound),
|
// If there's only one problematic bound (either 2 type parameter bounds, or 1 type parameter bound + 1 other bound),
|
||||||
// report the diagnostic on that bound
|
// report the diagnostic on that bound
|
||||||
|
|
||||||
val allBounds: List<Pair<KtTypeReference, KotlinType?>> =
|
val allBounds: List<Pair<KtTypeReference, KotlinType?>> =
|
||||||
owner.typeConstraints
|
owner.typeConstraints
|
||||||
.filter { constraint ->
|
.filter { constraint ->
|
||||||
constraint.subjectTypeParameterName?.getReferencedNameAsName() == declaration.nameAsName
|
constraint.subjectTypeParameterName?.getReferencedNameAsName() == declaration.nameAsName
|
||||||
}
|
}
|
||||||
.mapNotNull { constraint -> constraint.boundTypeReference }
|
.mapNotNull { constraint -> constraint.boundTypeReference }
|
||||||
.map { typeReference -> typeReference to trace.bindingContext.get(TYPE, typeReference) }
|
.map { typeReference -> typeReference to trace.bindingContext.get(TYPE, typeReference) }
|
||||||
|
|
||||||
val problematicBound =
|
val problematicBound =
|
||||||
allBounds.firstOrNull { bound -> bound.second?.constructor != boundsWhichAreTypeParameters.first() }
|
allBounds.firstOrNull { bound -> bound.second?.constructor != boundsWhichAreTypeParameters.first() }
|
||||||
|
|
||||||
problematicBound?.first ?: declaration
|
problematicBound?.first ?: declaration
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Otherwise report the diagnostic on the type parameter declaration
|
// Otherwise report the diagnostic on the type parameter declaration
|
||||||
declaration
|
declaration
|
||||||
}
|
}
|
||||||
@@ -400,17 +408,20 @@ class DeclarationsChecker(
|
|||||||
if (conflictingTypes.size <= 1) continue
|
if (conflictingTypes.size <= 1) continue
|
||||||
|
|
||||||
val containingDeclaration = typeParameterDescriptor.containingDeclaration as? ClassDescriptor
|
val containingDeclaration = typeParameterDescriptor.containingDeclaration as? ClassDescriptor
|
||||||
?: throw AssertionError("Not a class descriptor: " + typeParameterDescriptor.containingDeclaration)
|
?: throw AssertionError("Not a class descriptor: " + typeParameterDescriptor.containingDeclaration)
|
||||||
if (sourceElement is KtClassOrObject) {
|
if (sourceElement is KtClassOrObject) {
|
||||||
val delegationSpecifierList = sourceElement.getSuperTypeList() ?: continue
|
val delegationSpecifierList = sourceElement.getSuperTypeList() ?: continue
|
||||||
trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES.on(
|
trace.report(
|
||||||
|
INCONSISTENT_TYPE_PARAMETER_VALUES.on(
|
||||||
delegationSpecifierList, typeParameterDescriptor, containingDeclaration, conflictingTypes
|
delegationSpecifierList, typeParameterDescriptor, containingDeclaration, conflictingTypes
|
||||||
))
|
)
|
||||||
}
|
)
|
||||||
else if (sourceElement is KtTypeParameter) {
|
} else if (sourceElement is KtTypeParameter) {
|
||||||
trace.report(INCONSISTENT_TYPE_PARAMETER_BOUNDS.on(
|
trace.report(
|
||||||
|
INCONSISTENT_TYPE_PARAMETER_BOUNDS.on(
|
||||||
sourceElement, typeParameterDescriptor, containingDeclaration, conflictingTypes
|
sourceElement, typeParameterDescriptor, containingDeclaration, conflictingTypes
|
||||||
))
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -521,8 +532,7 @@ class DeclarationsChecker(
|
|||||||
for (parameter in aClass.primaryConstructorParameters) {
|
for (parameter in aClass.primaryConstructorParameters) {
|
||||||
if (!parameter.hasValOrVar()) {
|
if (!parameter.hasValOrVar()) {
|
||||||
trace.report(MISSING_VAL_ON_ANNOTATION_PARAMETER.on(parameter))
|
trace.report(MISSING_VAL_ON_ANNOTATION_PARAMETER.on(parameter))
|
||||||
}
|
} else if (parameter.isMutable) {
|
||||||
else if (parameter.isMutable) {
|
|
||||||
trace.report(VAR_ANNOTATION_PARAMETER.on(parameter))
|
trace.report(VAR_ANNOTATION_PARAMETER.on(parameter))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -537,8 +547,7 @@ class DeclarationsChecker(
|
|||||||
if (member != null && member.hasModifier(KtTokens.OPEN_KEYWORD)) {
|
if (member != null && member.hasModifier(KtTokens.OPEN_KEYWORD)) {
|
||||||
if (classDescriptor.kind == ClassKind.OBJECT) {
|
if (classDescriptor.kind == ClassKind.OBJECT) {
|
||||||
trace.report(NON_FINAL_MEMBER_IN_OBJECT.on(member))
|
trace.report(NON_FINAL_MEMBER_IN_OBJECT.on(member))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
trace.report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member))
|
trace.report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -594,9 +603,9 @@ class DeclarationsChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkMemberProperty(
|
private fun checkMemberProperty(
|
||||||
property: KtProperty,
|
property: KtProperty,
|
||||||
propertyDescriptor: PropertyDescriptor,
|
propertyDescriptor: PropertyDescriptor,
|
||||||
classDescriptor: ClassDescriptor
|
classDescriptor: ClassDescriptor
|
||||||
) {
|
) {
|
||||||
val modifierList = property.modifierList
|
val modifierList = property.modifierList
|
||||||
|
|
||||||
@@ -607,8 +616,7 @@ class DeclarationsChecker(
|
|||||||
trace.report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, property.name ?: "", classDescriptor))
|
trace.report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, property.name ?: "", classDescriptor))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
} else if (classDescriptor.kind == ClassKind.INTERFACE &&
|
||||||
else if (classDescriptor.kind == ClassKind.INTERFACE &&
|
|
||||||
modifierList.hasModifier(KtTokens.OPEN_KEYWORD) &&
|
modifierList.hasModifier(KtTokens.OPEN_KEYWORD) &&
|
||||||
propertyDescriptor.modality == Modality.ABSTRACT) {
|
propertyDescriptor.modality == Modality.ABSTRACT) {
|
||||||
trace.report(REDUNDANT_OPEN_IN_INTERFACE.on(property))
|
trace.report(REDUNDANT_OPEN_IN_INTERFACE.on(property))
|
||||||
@@ -659,35 +667,33 @@ class DeclarationsChecker(
|
|||||||
!backingFieldRequired -> trace.report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer))
|
!backingFieldRequired -> trace.report(PROPERTY_INITIALIZER_NO_BACKING_FIELD.on(initializer))
|
||||||
property.receiverTypeReference != null -> trace.report(EXTENSION_PROPERTY_WITH_BACKING_FIELD.on(initializer))
|
property.receiverTypeReference != null -> trace.report(EXTENSION_PROPERTY_WITH_BACKING_FIELD.on(initializer))
|
||||||
}
|
}
|
||||||
}
|
} else if (delegate != null) {
|
||||||
else if (delegate != null) {
|
|
||||||
if (inInterface) {
|
if (inInterface) {
|
||||||
trace.report(DELEGATED_PROPERTY_IN_INTERFACE.on(delegate))
|
trace.report(DELEGATED_PROPERTY_IN_INTERFACE.on(delegate))
|
||||||
}
|
} else if (isExpect) {
|
||||||
else if (isExpect) {
|
|
||||||
trace.report(EXPECTED_DELEGATED_PROPERTY.on(delegate))
|
trace.report(EXPECTED_DELEGATED_PROPERTY.on(delegate))
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val isUninitialized = trace.bindingContext.get(BindingContext.IS_UNINITIALIZED, propertyDescriptor) ?: false
|
val isUninitialized = trace.bindingContext.get(BindingContext.IS_UNINITIALIZED, propertyDescriptor) ?: false
|
||||||
val isExternal = propertyDescriptor.isEffectivelyExternal()
|
val isExternal = propertyDescriptor.isEffectivelyExternal()
|
||||||
if (backingFieldRequired && !inInterface && !propertyDescriptor.isLateInit && !isExpect && isUninitialized && !isExternal) {
|
if (backingFieldRequired && !inInterface && !propertyDescriptor.isLateInit && !isExpect && isUninitialized && !isExternal) {
|
||||||
if (propertyDescriptor.extensionReceiverParameter != null && !hasAccessorImplementation) {
|
if (propertyDescriptor.extensionReceiverParameter != null && !hasAccessorImplementation) {
|
||||||
trace.report(EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT.on(property))
|
trace.report(EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT.on(property))
|
||||||
}
|
} else if (diagnosticSuppressor.shouldReportNoBody(propertyDescriptor)) {
|
||||||
else if (diagnosticSuppressor.shouldReportNoBody(propertyDescriptor)) {
|
|
||||||
if (containingDeclaration !is ClassDescriptor || hasAccessorImplementation) {
|
if (containingDeclaration !is ClassDescriptor || hasAccessorImplementation) {
|
||||||
trace.report(MUST_BE_INITIALIZED.on(property))
|
trace.report(MUST_BE_INITIALIZED.on(property))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property))
|
trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (property.typeReference == null && !languageVersionSettings.supportsFeature(LanguageFeature.ShortSyntaxForPropertyGetters)) {
|
||||||
else if (property.typeReference == null && !languageVersionSettings.supportsFeature(LanguageFeature.ShortSyntaxForPropertyGetters)) {
|
trace.report(
|
||||||
trace.report(Errors.UNSUPPORTED_FEATURE.on(property, LanguageFeature.ShortSyntaxForPropertyGetters to languageVersionSettings))
|
Errors.UNSUPPORTED_FEATURE.on(
|
||||||
}
|
property,
|
||||||
else if (noExplicitTypeOrGetterType(property)) {
|
LanguageFeature.ShortSyntaxForPropertyGetters to languageVersionSettings
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else if (noExplicitTypeOrGetterType(property)) {
|
||||||
trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property))
|
trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -703,7 +709,7 @@ class DeclarationsChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun noExplicitTypeOrGetterType(property: KtProperty) =
|
private fun noExplicitTypeOrGetterType(property: KtProperty) =
|
||||||
property.typeReference == null
|
property.typeReference == null
|
||||||
&& (property.getter == null || (property.getter!!.hasBlockBody() && property.getter!!.returnTypeReference == null))
|
&& (property.getter == null || (property.getter!!.hasBlockBody() && property.getter!!.returnTypeReference == null))
|
||||||
|
|
||||||
fun checkFunction(function: KtNamedFunction, functionDescriptor: SimpleFunctionDescriptor) {
|
fun checkFunction(function: KtNamedFunction, functionDescriptor: SimpleFunctionDescriptor) {
|
||||||
@@ -744,8 +750,7 @@ class DeclarationsChecker(
|
|||||||
diagnosticSuppressor.shouldReportNoBody(functionDescriptor)) {
|
diagnosticSuppressor.shouldReportNoBody(functionDescriptor)) {
|
||||||
trace.report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor))
|
trace.report(NON_ABSTRACT_FUNCTION_WITH_NO_BODY.on(function, functionDescriptor))
|
||||||
}
|
}
|
||||||
}
|
} else /* top-level only */ {
|
||||||
else /* top-level only */ {
|
|
||||||
if (!function.hasBody() && !hasAbstractModifier && !hasExternalModifier && !functionDescriptor.isExpect &&
|
if (!function.hasBody() && !hasAbstractModifier && !hasExternalModifier && !functionDescriptor.isExpect &&
|
||||||
diagnosticSuppressor.shouldReportNoBody(functionDescriptor)) {
|
diagnosticSuppressor.shouldReportNoBody(functionDescriptor)) {
|
||||||
trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor))
|
trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor))
|
||||||
@@ -779,16 +784,15 @@ class DeclarationsChecker(
|
|||||||
if (declaration.typeReference == null) {
|
if (declaration.typeReference == null) {
|
||||||
if (it.isNothing() && !declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) {
|
if (it.isNothing() && !declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) {
|
||||||
trace.report(
|
trace.report(
|
||||||
(if (declaration is KtProperty) IMPLICIT_NOTHING_PROPERTY_TYPE else IMPLICIT_NOTHING_RETURN_TYPE).on(target)
|
(if (declaration is KtProperty) IMPLICIT_NOTHING_PROPERTY_TYPE else IMPLICIT_NOTHING_RETURN_TYPE).on(target)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (it.contains { type -> type.constructor is IntersectionTypeConstructor }) {
|
if (it.contains { type -> type.constructor is IntersectionTypeConstructor }) {
|
||||||
trace.report(IMPLICIT_INTERSECTION_TYPE.on(target, it))
|
trace.report(IMPLICIT_INTERSECTION_TYPE.on(target, it))
|
||||||
}
|
}
|
||||||
}
|
} else if (it.isNothing() && it is AbbreviatedType) {
|
||||||
else if (it.isNothing() && it is AbbreviatedType) {
|
|
||||||
trace.report(
|
trace.report(
|
||||||
(if (declaration is KtProperty) ABBREVIATED_NOTHING_PROPERTY_TYPE else ABBREVIATED_NOTHING_RETURN_TYPE).on(target)
|
(if (declaration is KtProperty) ABBREVIATED_NOTHING_PROPERTY_TYPE else ABBREVIATED_NOTHING_RETURN_TYPE).on(target)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -800,8 +804,7 @@ class DeclarationsChecker(
|
|||||||
if (accessor != null) {
|
if (accessor != null) {
|
||||||
modifiersChecker.checkModifiersForDeclaration(accessor, accessorDescriptor)
|
modifiersChecker.checkModifiersForDeclaration(accessor, accessorDescriptor)
|
||||||
identifierChecker.checkDeclaration(accessor, trace)
|
identifierChecker.checkDeclaration(accessor, trace)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
modifiersChecker.runDeclarationCheckers(property, accessorDescriptor)
|
modifiersChecker.runDeclarationCheckers(property, accessorDescriptor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -816,9 +819,9 @@ class DeclarationsChecker(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkAccessor(
|
private fun checkAccessor(
|
||||||
propertyDescriptor: PropertyDescriptor,
|
propertyDescriptor: PropertyDescriptor,
|
||||||
accessor: KtPropertyAccessor?,
|
accessor: KtPropertyAccessor?,
|
||||||
accessorDescriptor: PropertyAccessorDescriptor?
|
accessorDescriptor: PropertyAccessorDescriptor?
|
||||||
) {
|
) {
|
||||||
if (accessor == null || accessorDescriptor == null) return
|
if (accessor == null || accessorDescriptor == null) return
|
||||||
if (propertyDescriptor.isExpect && accessor.hasBody()) {
|
if (propertyDescriptor.isExpect && accessor.hasBody()) {
|
||||||
@@ -827,29 +830,25 @@ class DeclarationsChecker(
|
|||||||
|
|
||||||
val accessorModifierList = accessor.modifierList ?: return
|
val accessorModifierList = accessor.modifierList ?: return
|
||||||
val tokens = modifiersChecker.getTokensCorrespondingToModifiers(
|
val tokens = modifiersChecker.getTokensCorrespondingToModifiers(
|
||||||
accessorModifierList,
|
accessorModifierList,
|
||||||
setOf(KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.PRIVATE_KEYWORD, KtTokens.INTERNAL_KEYWORD)
|
setOf(KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.PRIVATE_KEYWORD, KtTokens.INTERNAL_KEYWORD)
|
||||||
)
|
)
|
||||||
if (accessor.isGetter) {
|
if (accessor.isGetter) {
|
||||||
if (accessorDescriptor.visibility != propertyDescriptor.visibility) {
|
if (accessorDescriptor.visibility != propertyDescriptor.visibility) {
|
||||||
reportVisibilityModifierDiagnostics(tokens.values, Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY)
|
reportVisibilityModifierDiagnostics(tokens.values, Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
reportVisibilityModifierDiagnostics(tokens.values, Errors.REDUNDANT_MODIFIER_IN_GETTER)
|
reportVisibilityModifierDiagnostics(tokens.values, Errors.REDUNDANT_MODIFIER_IN_GETTER)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (propertyDescriptor.isOverridable
|
if (propertyDescriptor.isOverridable
|
||||||
&& accessorDescriptor.visibility == Visibilities.PRIVATE
|
&& accessorDescriptor.visibility == Visibilities.PRIVATE
|
||||||
&& propertyDescriptor.visibility != Visibilities.PRIVATE) {
|
&& propertyDescriptor.visibility != Visibilities.PRIVATE) {
|
||||||
if (propertyDescriptor.modality == Modality.ABSTRACT) {
|
if (propertyDescriptor.modality == Modality.ABSTRACT) {
|
||||||
reportVisibilityModifierDiagnostics(tokens.values, Errors.PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY)
|
reportVisibilityModifierDiagnostics(tokens.values, Errors.PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
reportVisibilityModifierDiagnostics(tokens.values, Errors.PRIVATE_SETTER_FOR_OPEN_PROPERTY)
|
reportVisibilityModifierDiagnostics(tokens.values, Errors.PRIVATE_SETTER_FOR_OPEN_PROPERTY)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val compare = Visibilities.compare(accessorDescriptor.visibility, propertyDescriptor.visibility)
|
val compare = Visibilities.compare(accessorDescriptor.visibility, propertyDescriptor.visibility)
|
||||||
if (compare == null || compare > 0) {
|
if (compare == null || compare > 0) {
|
||||||
reportVisibilityModifierDiagnostics(tokens.values, Errors.SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY)
|
reportVisibilityModifierDiagnostics(tokens.values, Errors.SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY)
|
||||||
@@ -866,8 +865,7 @@ class DeclarationsChecker(
|
|||||||
trace.report(EXPECTED_ENUM_ENTRY_WITH_BODY.on(enumEntry))
|
trace.report(EXPECTED_ENUM_ENTRY_WITH_BODY.on(enumEntry))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
assert(DescriptorUtils.isInterface(enumClass)) { "Enum entry should be declared in enum class: " + enumEntryClass }
|
assert(DescriptorUtils.isInterface(enumClass)) { "Enum entry should be declared in enum class: " + enumEntryClass }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -922,7 +920,10 @@ class DeclarationsChecker(
|
|||||||
return isImplementingMethodOfAnyInternal(member, HashSet<ClassDescriptor>())
|
return isImplementingMethodOfAnyInternal(member, HashSet<ClassDescriptor>())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isImplementingMethodOfAnyInternal(member: CallableMemberDescriptor, visitedClasses: MutableSet<ClassDescriptor>): Boolean {
|
private fun isImplementingMethodOfAnyInternal(
|
||||||
|
member: CallableMemberDescriptor,
|
||||||
|
visitedClasses: MutableSet<ClassDescriptor>
|
||||||
|
): Boolean {
|
||||||
for (overridden in member.overriddenDescriptors) {
|
for (overridden in member.overriddenDescriptors) {
|
||||||
val containingDeclaration = overridden.containingDeclaration
|
val containingDeclaration = overridden.containingDeclaration
|
||||||
if (containingDeclaration !is ClassDescriptor) continue
|
if (containingDeclaration !is ClassDescriptor) continue
|
||||||
|
|||||||
@@ -33,14 +33,14 @@ import org.jetbrains.kotlin.types.isError
|
|||||||
import org.jetbrains.kotlin.utils.keysToMapExceptNulls
|
import org.jetbrains.kotlin.utils.keysToMapExceptNulls
|
||||||
|
|
||||||
class DelegationResolver<T : CallableMemberDescriptor> private constructor(
|
class DelegationResolver<T : CallableMemberDescriptor> private constructor(
|
||||||
private val classOrObject: KtPureClassOrObject,
|
private val classOrObject: KtPureClassOrObject,
|
||||||
private val ownerDescriptor: ClassDescriptor,
|
private val ownerDescriptor: ClassDescriptor,
|
||||||
private val existingMembers: Collection<CallableDescriptor>,
|
private val existingMembers: Collection<CallableDescriptor>,
|
||||||
private val trace: BindingTrace,
|
private val trace: BindingTrace,
|
||||||
private val memberExtractor: MemberExtractor<T>,
|
private val memberExtractor: MemberExtractor<T>,
|
||||||
private val typeResolver: TypeResolver,
|
private val typeResolver: TypeResolver,
|
||||||
private val delegationFilter: DelegationFilter,
|
private val delegationFilter: DelegationFilter,
|
||||||
private val languageVersionSettings: LanguageVersionSettings
|
private val languageVersionSettings: LanguageVersionSettings
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private fun generateDelegatedMembers(): Collection<T> {
|
private fun generateDelegatedMembers(): Collection<T> {
|
||||||
@@ -61,24 +61,24 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateDelegatesForInterface(existingDelegates: Collection<T>, delegatedInterfaceType: KotlinType): Collection<T> =
|
private fun generateDelegatesForInterface(existingDelegates: Collection<T>, delegatedInterfaceType: KotlinType): Collection<T> =
|
||||||
generateDelegationCandidates(delegatedInterfaceType).filter { candidate ->
|
generateDelegationCandidates(delegatedInterfaceType).filter { candidate ->
|
||||||
!isOverridingAnyOf(candidate, existingMembers) &&
|
!isOverridingAnyOf(candidate, existingMembers) &&
|
||||||
!checkClashWithOtherDelegatedMember(candidate, existingDelegates)
|
!checkClashWithOtherDelegatedMember(candidate, existingDelegates)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun generateDelegationCandidates(delegatedInterfaceType: KotlinType): Collection<T> =
|
private fun generateDelegationCandidates(delegatedInterfaceType: KotlinType): Collection<T> =
|
||||||
getDelegatableMembers(delegatedInterfaceType).map { memberDescriptor ->
|
getDelegatableMembers(delegatedInterfaceType).map { memberDescriptor ->
|
||||||
val newModality = if (memberDescriptor.modality == Modality.ABSTRACT) Modality.OPEN else memberDescriptor.modality
|
val newModality = if (memberDescriptor.modality == Modality.ABSTRACT) Modality.OPEN else memberDescriptor.modality
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
memberDescriptor.newCopyBuilder()
|
memberDescriptor.newCopyBuilder()
|
||||||
.setOwner(ownerDescriptor)
|
.setOwner(ownerDescriptor)
|
||||||
.setDispatchReceiverParameter(ownerDescriptor.thisAsReceiverParameter)
|
.setDispatchReceiverParameter(ownerDescriptor.thisAsReceiverParameter)
|
||||||
.setModality(newModality)
|
.setModality(newModality)
|
||||||
.setVisibility(Visibilities.INHERITED)
|
.setVisibility(Visibilities.INHERITED)
|
||||||
.setKind(DELEGATION)
|
.setKind(DELEGATION)
|
||||||
.setCopyOverrides(false)
|
.setCopyOverrides(false)
|
||||||
.build() as T
|
.build() as T
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkClashWithOtherDelegatedMember(candidate: T, delegatedMembers: Collection<T>): Boolean {
|
private fun checkClashWithOtherDelegatedMember(candidate: T, delegatedMembers: Collection<T>): Boolean {
|
||||||
val alreadyDelegated = delegatedMembers.firstOrNull { isOverridableBy(it, candidate) }
|
val alreadyDelegated = delegatedMembers.firstOrNull { isOverridableBy(it, candidate) }
|
||||||
@@ -92,16 +92,16 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
|
|||||||
|
|
||||||
|
|
||||||
private fun getDelegatableMembers(interfaceType: KotlinType): Collection<T> =
|
private fun getDelegatableMembers(interfaceType: KotlinType): Collection<T> =
|
||||||
memberExtractor.getMembersByType(interfaceType).filter { descriptor ->
|
memberExtractor.getMembersByType(interfaceType).filter { descriptor ->
|
||||||
descriptor.isOverridable &&
|
descriptor.isOverridable &&
|
||||||
(descriptor.kind.isReal || !descriptor.overridesClassMembersOnly()) &&
|
(descriptor.kind.isReal || !descriptor.overridesClassMembersOnly()) &&
|
||||||
delegationFilter.filter(descriptor, languageVersionSettings)
|
delegationFilter.filter(descriptor, languageVersionSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun T.overridesClassMembersOnly() =
|
private fun T.overridesClassMembersOnly() =
|
||||||
DescriptorUtils.getAllOverriddenDeclarations(this).all {
|
DescriptorUtils.getAllOverriddenDeclarations(this).all {
|
||||||
DescriptorUtils.isClass(it.containingDeclaration)
|
DescriptorUtils.isClass(it.containingDeclaration)
|
||||||
}
|
}
|
||||||
|
|
||||||
interface MemberExtractor<out T : CallableMemberDescriptor> {
|
interface MemberExtractor<out T : CallableMemberDescriptor> {
|
||||||
fun getMembersByType(type: KotlinType): Collection<T>
|
fun getMembersByType(type: KotlinType): Collection<T>
|
||||||
@@ -113,26 +113,35 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun <T : CallableMemberDescriptor> generateDelegatedMembers(
|
fun <T : CallableMemberDescriptor> generateDelegatedMembers(
|
||||||
classOrObject: KtPureClassOrObject,
|
classOrObject: KtPureClassOrObject,
|
||||||
ownerDescriptor: ClassDescriptor,
|
ownerDescriptor: ClassDescriptor,
|
||||||
existingMembers: Collection<CallableDescriptor>,
|
existingMembers: Collection<CallableDescriptor>,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
memberExtractor: MemberExtractor<T>,
|
memberExtractor: MemberExtractor<T>,
|
||||||
typeResolver: TypeResolver,
|
typeResolver: TypeResolver,
|
||||||
delegationFilter: DelegationFilter,
|
delegationFilter: DelegationFilter,
|
||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
): Collection<T> =
|
): Collection<T> =
|
||||||
DelegationResolver(classOrObject, ownerDescriptor, existingMembers, trace, memberExtractor, typeResolver, delegationFilter, languageVersionSettings)
|
DelegationResolver(
|
||||||
.generateDelegatedMembers()
|
classOrObject,
|
||||||
|
ownerDescriptor,
|
||||||
|
existingMembers,
|
||||||
|
trace,
|
||||||
|
memberExtractor,
|
||||||
|
typeResolver,
|
||||||
|
delegationFilter,
|
||||||
|
languageVersionSettings
|
||||||
|
)
|
||||||
|
.generateDelegatedMembers()
|
||||||
|
|
||||||
private fun isOverridingAnyOf(
|
private fun isOverridingAnyOf(
|
||||||
candidate: CallableMemberDescriptor,
|
candidate: CallableMemberDescriptor,
|
||||||
possiblyOverriddenBy: Collection<CallableDescriptor>
|
possiblyOverriddenBy: Collection<CallableDescriptor>
|
||||||
): Boolean =
|
): Boolean =
|
||||||
possiblyOverriddenBy.any { isOverridableBy(it, candidate) }
|
possiblyOverriddenBy.any { isOverridableBy(it, candidate) }
|
||||||
|
|
||||||
private fun isOverridableBy(memberOne: CallableDescriptor, memberTwo: CallableDescriptor): Boolean =
|
private fun isOverridableBy(memberOne: CallableDescriptor, memberTwo: CallableDescriptor): Boolean =
|
||||||
OverridingUtil.DEFAULT.isOverridableBy(memberOne, memberTwo, null).result == OVERRIDABLE
|
OverridingUtil.DEFAULT.isOverridableBy(memberOne, memberTwo, null).result == OVERRIDABLE
|
||||||
|
|
||||||
// class Foo : Bar by baz
|
// class Foo : Bar by baz
|
||||||
// descriptor = Foo
|
// descriptor = Foo
|
||||||
@@ -140,34 +149,34 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
|
|||||||
// delegateExpressionType = typeof(baz)
|
// delegateExpressionType = typeof(baz)
|
||||||
// return Map<member of Foo, corresponding member of typeOf(baz)>
|
// return Map<member of Foo, corresponding member of typeOf(baz)>
|
||||||
fun getDelegates(
|
fun getDelegates(
|
||||||
descriptor: ClassDescriptor,
|
descriptor: ClassDescriptor,
|
||||||
toInterface: ClassDescriptor,
|
toInterface: ClassDescriptor,
|
||||||
delegateExpressionType: KotlinType? = null
|
delegateExpressionType: KotlinType? = null
|
||||||
): Map<CallableMemberDescriptor, CallableMemberDescriptor> {
|
): Map<CallableMemberDescriptor, CallableMemberDescriptor> {
|
||||||
if (delegateExpressionType?.isDynamic() ?: false) return emptyMap()
|
if (delegateExpressionType?.isDynamic() ?: false) return emptyMap()
|
||||||
|
|
||||||
val delegatedMembers = descriptor.defaultType.memberScope.getContributedDescriptors().asSequence()
|
val delegatedMembers = descriptor.defaultType.memberScope.getContributedDescriptors().asSequence()
|
||||||
.filterIsInstance<CallableMemberDescriptor>()
|
.filterIsInstance<CallableMemberDescriptor>()
|
||||||
.filter { it.kind == CallableMemberDescriptor.Kind.DELEGATION }
|
.filter { it.kind == CallableMemberDescriptor.Kind.DELEGATION }
|
||||||
.asIterable()
|
.asIterable()
|
||||||
.sortedWith(MemberComparator.INSTANCE)
|
.sortedWith(MemberComparator.INSTANCE)
|
||||||
|
|
||||||
return delegatedMembers
|
return delegatedMembers
|
||||||
.keysToMapExceptNulls { delegatingMember ->
|
.keysToMapExceptNulls { delegatingMember ->
|
||||||
val actualDelegates = DescriptorUtils.getAllOverriddenDescriptors(delegatingMember)
|
val actualDelegates = DescriptorUtils.getAllOverriddenDescriptors(delegatingMember)
|
||||||
.filter { it.containingDeclaration == toInterface }
|
.filter { it.containingDeclaration == toInterface }
|
||||||
.map { overriddenDescriptor ->
|
.map { overriddenDescriptor ->
|
||||||
val scope = (delegateExpressionType ?: toInterface.defaultType).memberScope
|
val scope = (delegateExpressionType ?: toInterface.defaultType).memberScope
|
||||||
val name = overriddenDescriptor.name
|
val name = overriddenDescriptor.name
|
||||||
|
|
||||||
// this is the actual member of delegateExpressionType that we are delegating to
|
// this is the actual member of delegateExpressionType that we are delegating to
|
||||||
(scope.getContributedFunctions(name, NoLookupLocation.WHEN_CHECK_OVERRIDES) +
|
(scope.getContributedFunctions(name, NoLookupLocation.WHEN_CHECK_OVERRIDES) +
|
||||||
scope.getContributedVariables(name, NoLookupLocation.WHEN_CHECK_OVERRIDES))
|
scope.getContributedVariables(name, NoLookupLocation.WHEN_CHECK_OVERRIDES))
|
||||||
.firstOrNull { it == overriddenDescriptor || OverridingUtil.overrides(it, overriddenDescriptor) }
|
.firstOrNull { it == overriddenDescriptor || OverridingUtil.overrides(it, overriddenDescriptor) }
|
||||||
}
|
}
|
||||||
|
|
||||||
actualDelegates.firstOrNull()
|
actualDelegates.firstOrNull()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,14 +47,16 @@ object DescriptorToSourceUtils {
|
|||||||
result.add(descriptor)
|
result.add(descriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun getEffectiveReferencedDescriptors(descriptor: DeclarationDescriptor): Collection<DeclarationDescriptor> {
|
@JvmStatic
|
||||||
|
fun getEffectiveReferencedDescriptors(descriptor: DeclarationDescriptor): Collection<DeclarationDescriptor> {
|
||||||
val result = ArrayList<DeclarationDescriptor>()
|
val result = ArrayList<DeclarationDescriptor>()
|
||||||
collectEffectiveReferencedDescriptors(result, descriptor.original)
|
collectEffectiveReferencedDescriptors(result, descriptor.original)
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Fix in descriptor
|
// TODO Fix in descriptor
|
||||||
@JvmStatic private fun getSourceForExtensionReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor): PsiElement? {
|
@JvmStatic
|
||||||
|
private fun getSourceForExtensionReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor): PsiElement? {
|
||||||
// Only for extension receivers
|
// Only for extension receivers
|
||||||
if (descriptor.source != SourceElement.NO_SOURCE || descriptor.value !is ExtensionReceiver) return null
|
if (descriptor.source != SourceElement.NO_SOURCE || descriptor.value !is ExtensionReceiver) return null
|
||||||
val containingDeclaration = descriptor.containingDeclaration as? CallableDescriptor ?: return null
|
val containingDeclaration = descriptor.containingDeclaration as? CallableDescriptor ?: return null
|
||||||
@@ -62,7 +64,8 @@ object DescriptorToSourceUtils {
|
|||||||
return psi.receiverTypeReference
|
return psi.receiverTypeReference
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun getSourceFromDescriptor(descriptor: DeclarationDescriptor): PsiElement? {
|
@JvmStatic
|
||||||
|
fun getSourceFromDescriptor(descriptor: DeclarationDescriptor): PsiElement? {
|
||||||
if (descriptor is ReceiverParameterDescriptor) {
|
if (descriptor is ReceiverParameterDescriptor) {
|
||||||
getSourceForExtensionReceiverParameterDescriptor(descriptor)?.let { return it }
|
getSourceForExtensionReceiverParameterDescriptor(descriptor)?.let { return it }
|
||||||
}
|
}
|
||||||
@@ -70,7 +73,8 @@ object DescriptorToSourceUtils {
|
|||||||
return (descriptor as? DeclarationDescriptorWithSource)?.source?.getPsi()
|
return (descriptor as? DeclarationDescriptorWithSource)?.source?.getPsi()
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun getSourceFromAnnotation(descriptor: AnnotationDescriptor): KtAnnotationEntry? {
|
@JvmStatic
|
||||||
|
fun getSourceFromAnnotation(descriptor: AnnotationDescriptor): KtAnnotationEntry? {
|
||||||
return descriptor.source.getPsi() as? KtAnnotationEntry
|
return descriptor.source.getPsi() as? KtAnnotationEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -78,12 +82,14 @@ object DescriptorToSourceUtils {
|
|||||||
// Returns PSI element for descriptor. If there are many relevant elements (e.g. it is fake override
|
// Returns PSI element for descriptor. If there are many relevant elements (e.g. it is fake override
|
||||||
// with multiple declarations), returns null. It can't find declarations in builtins or decompiled code.
|
// with multiple declarations), returns null. It can't find declarations in builtins or decompiled code.
|
||||||
// In IDE, use DescriptorToSourceUtilsIde instead.
|
// In IDE, use DescriptorToSourceUtilsIde instead.
|
||||||
@JvmStatic fun descriptorToDeclaration(descriptor: DeclarationDescriptor): PsiElement? {
|
@JvmStatic
|
||||||
|
fun descriptorToDeclaration(descriptor: DeclarationDescriptor): PsiElement? {
|
||||||
val effectiveReferencedDescriptors = getEffectiveReferencedDescriptors(descriptor)
|
val effectiveReferencedDescriptors = getEffectiveReferencedDescriptors(descriptor)
|
||||||
return if (effectiveReferencedDescriptors.size == 1) getSourceFromDescriptor(effectiveReferencedDescriptors.firstOrNull()!!) else null
|
return if (effectiveReferencedDescriptors.size == 1) getSourceFromDescriptor(effectiveReferencedDescriptors.firstOrNull()!!) else null
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic fun getContainingFile(declarationDescriptor: DeclarationDescriptor): KtFile? {
|
@JvmStatic
|
||||||
|
fun getContainingFile(declarationDescriptor: DeclarationDescriptor): KtFile? {
|
||||||
// declarationDescriptor may describe a synthesized element which doesn't have PSI
|
// declarationDescriptor may describe a synthesized element which doesn't have PSI
|
||||||
// To workaround that, we find a top-level parent (which is inside a PackageFragmentDescriptor), which is guaranteed to have PSI
|
// To workaround that, we find a top-level parent (which is inside a PackageFragmentDescriptor), which is guaranteed to have PSI
|
||||||
val descriptor = findTopLevelParent(declarationDescriptor) ?: return null
|
val descriptor = findTopLevelParent(declarationDescriptor) ?: return null
|
||||||
|
|||||||
@@ -38,16 +38,17 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
|
|||||||
return result and checkFunction(constructor, constructorDescriptor)
|
return result and checkFunction(constructor, constructorDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkDeclarationWithVisibility(modifierListOwner: KtModifierListOwner,
|
fun checkDeclarationWithVisibility(
|
||||||
descriptor: DeclarationDescriptorWithVisibility,
|
modifierListOwner: KtModifierListOwner,
|
||||||
visibility: Visibility
|
descriptor: DeclarationDescriptorWithVisibility,
|
||||||
) : Boolean {
|
visibility: Visibility
|
||||||
|
): Boolean {
|
||||||
return when {
|
return when {
|
||||||
modifierListOwner is KtFunction &&
|
modifierListOwner is KtFunction &&
|
||||||
descriptor is FunctionDescriptor -> checkFunction(modifierListOwner, descriptor, visibility)
|
descriptor is FunctionDescriptor -> checkFunction(modifierListOwner, descriptor, visibility)
|
||||||
|
|
||||||
modifierListOwner is KtProperty &&
|
modifierListOwner is KtProperty &&
|
||||||
descriptor is PropertyDescriptor -> checkProperty(modifierListOwner, descriptor, visibility)
|
descriptor is PropertyDescriptor -> checkProperty(modifierListOwner, descriptor, visibility)
|
||||||
|
|
||||||
else -> true
|
else -> true
|
||||||
}
|
}
|
||||||
@@ -60,48 +61,66 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
|
|||||||
val typeAliasVisibility = typeAliasDescriptor.effectiveVisibility()
|
val typeAliasVisibility = typeAliasDescriptor.effectiveVisibility()
|
||||||
val restricting = expandedType.leastPermissiveDescriptor(typeAliasVisibility)
|
val restricting = expandedType.leastPermissiveDescriptor(typeAliasVisibility)
|
||||||
if (restricting != null) {
|
if (restricting != null) {
|
||||||
trace.report(Errors.EXPOSED_TYPEALIAS_EXPANDED_TYPE.on(typeAlias.nameIdentifier ?: typeAlias,
|
trace.report(
|
||||||
typeAliasVisibility, restricting, restricting.effectiveVisibility()))
|
Errors.EXPOSED_TYPEALIAS_EXPANDED_TYPE.on(
|
||||||
|
typeAlias.nameIdentifier ?: typeAlias,
|
||||||
|
typeAliasVisibility, restricting, restricting.effectiveVisibility()
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkFunction(function: KtFunction,
|
fun checkFunction(
|
||||||
functionDescriptor: FunctionDescriptor,
|
function: KtFunction,
|
||||||
// for checking situation with modified basic visibility
|
functionDescriptor: FunctionDescriptor,
|
||||||
visibility: Visibility = functionDescriptor.visibility
|
// for checking situation with modified basic visibility
|
||||||
|
visibility: Visibility = functionDescriptor.visibility
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val functionVisibility = functionDescriptor.effectiveVisibility(visibility)
|
val functionVisibility = functionDescriptor.effectiveVisibility(visibility)
|
||||||
var result = true
|
var result = true
|
||||||
if (function !is KtConstructor<*>) {
|
if (function !is KtConstructor<*>) {
|
||||||
val restricting = functionDescriptor.returnType?.leastPermissiveDescriptor(functionVisibility)
|
val restricting = functionDescriptor.returnType?.leastPermissiveDescriptor(functionVisibility)
|
||||||
if (restricting != null) {
|
if (restricting != null) {
|
||||||
trace.report(Errors.EXPOSED_FUNCTION_RETURN_TYPE.on(function.nameIdentifier ?: function, functionVisibility,
|
trace.report(
|
||||||
restricting, restricting.effectiveVisibility()))
|
Errors.EXPOSED_FUNCTION_RETURN_TYPE.on(
|
||||||
|
function.nameIdentifier ?: function, functionVisibility,
|
||||||
|
restricting, restricting.effectiveVisibility()
|
||||||
|
)
|
||||||
|
)
|
||||||
result = false
|
result = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
functionDescriptor.valueParameters.forEachIndexed { i, parameterDescriptor ->
|
functionDescriptor.valueParameters.forEachIndexed { i, parameterDescriptor ->
|
||||||
val restricting = parameterDescriptor.type.leastPermissiveDescriptor(functionVisibility)
|
val restricting = parameterDescriptor.type.leastPermissiveDescriptor(functionVisibility)
|
||||||
if (restricting != null && i < function.valueParameters.size) {
|
if (restricting != null && i < function.valueParameters.size) {
|
||||||
trace.report(Errors.EXPOSED_PARAMETER_TYPE.on(function.valueParameters[i], functionVisibility,
|
trace.report(
|
||||||
restricting, restricting.effectiveVisibility()))
|
Errors.EXPOSED_PARAMETER_TYPE.on(
|
||||||
|
function.valueParameters[i], functionVisibility,
|
||||||
|
restricting, restricting.effectiveVisibility()
|
||||||
|
)
|
||||||
|
)
|
||||||
result = false
|
result = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return result and checkMemberReceiver(function.receiverTypeReference, functionDescriptor)
|
return result and checkMemberReceiver(function.receiverTypeReference, functionDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkProperty(property: KtProperty,
|
fun checkProperty(
|
||||||
propertyDescriptor: PropertyDescriptor,
|
property: KtProperty,
|
||||||
// for checking situation with modified basic visibility
|
propertyDescriptor: PropertyDescriptor,
|
||||||
visibility: Visibility = propertyDescriptor.visibility
|
// for checking situation with modified basic visibility
|
||||||
|
visibility: Visibility = propertyDescriptor.visibility
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val propertyVisibility = propertyDescriptor.effectiveVisibility(visibility)
|
val propertyVisibility = propertyDescriptor.effectiveVisibility(visibility)
|
||||||
val restricting = propertyDescriptor.type.leastPermissiveDescriptor(propertyVisibility)
|
val restricting = propertyDescriptor.type.leastPermissiveDescriptor(propertyVisibility)
|
||||||
var result = true
|
var result = true
|
||||||
if (restricting != null) {
|
if (restricting != null) {
|
||||||
trace.report(Errors.EXPOSED_PROPERTY_TYPE.on(property.nameIdentifier ?: property, propertyVisibility,
|
trace.report(
|
||||||
restricting, restricting.effectiveVisibility()))
|
Errors.EXPOSED_PROPERTY_TYPE.on(
|
||||||
|
property.nameIdentifier ?: property, propertyVisibility,
|
||||||
|
restricting, restricting.effectiveVisibility()
|
||||||
|
)
|
||||||
|
)
|
||||||
result = false
|
result = false
|
||||||
}
|
}
|
||||||
return result and checkMemberReceiver(property.receiverTypeReference, propertyDescriptor)
|
return result and checkMemberReceiver(property.receiverTypeReference, propertyDescriptor)
|
||||||
@@ -113,8 +132,12 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
|
|||||||
val memberVisibility = memberDescriptor.effectiveVisibility()
|
val memberVisibility = memberDescriptor.effectiveVisibility()
|
||||||
val restricting = receiverParameterDescriptor.type.leastPermissiveDescriptor(memberVisibility)
|
val restricting = receiverParameterDescriptor.type.leastPermissiveDescriptor(memberVisibility)
|
||||||
if (restricting != null) {
|
if (restricting != null) {
|
||||||
trace.report(Errors.EXPOSED_RECEIVER_TYPE.on(typeReference, memberVisibility,
|
trace.report(
|
||||||
restricting, restricting.effectiveVisibility()))
|
Errors.EXPOSED_RECEIVER_TYPE.on(
|
||||||
|
typeReference, memberVisibility,
|
||||||
|
restricting, restricting.effectiveVisibility()
|
||||||
|
)
|
||||||
|
)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
@@ -135,12 +158,19 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
|
|||||||
val restricting = superType.leastPermissiveDescriptor(classVisibility)
|
val restricting = superType.leastPermissiveDescriptor(classVisibility)
|
||||||
if (restricting != null) {
|
if (restricting != null) {
|
||||||
if (isInterface) {
|
if (isInterface) {
|
||||||
trace.report(Errors.EXPOSED_SUPER_INTERFACE.on(delegationList[i], classVisibility,
|
trace.report(
|
||||||
restricting, restricting.effectiveVisibility()))
|
Errors.EXPOSED_SUPER_INTERFACE.on(
|
||||||
}
|
delegationList[i], classVisibility,
|
||||||
else {
|
restricting, restricting.effectiveVisibility()
|
||||||
trace.report(Errors.EXPOSED_SUPER_CLASS.on(delegationList[i], classVisibility,
|
)
|
||||||
restricting, restricting.effectiveVisibility()))
|
)
|
||||||
|
} else {
|
||||||
|
trace.report(
|
||||||
|
Errors.EXPOSED_SUPER_CLASS.on(
|
||||||
|
delegationList[i], classVisibility,
|
||||||
|
restricting, restricting.effectiveVisibility()
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
result = false
|
result = false
|
||||||
}
|
}
|
||||||
@@ -157,8 +187,12 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
|
|||||||
for (upperBound in typeParameterDescriptor.upperBounds) {
|
for (upperBound in typeParameterDescriptor.upperBounds) {
|
||||||
val restricting = upperBound.leastPermissiveDescriptor(classVisibility)
|
val restricting = upperBound.leastPermissiveDescriptor(classVisibility)
|
||||||
if (restricting != null) {
|
if (restricting != null) {
|
||||||
trace.report(Errors.EXPOSED_TYPE_PARAMETER_BOUND.on(typeParameterList[i], classVisibility,
|
trace.report(
|
||||||
restricting, restricting.effectiveVisibility()))
|
Errors.EXPOSED_TYPE_PARAMETER_BOUND.on(
|
||||||
|
typeParameterList[i], classVisibility,
|
||||||
|
restricting, restricting.effectiveVisibility()
|
||||||
|
)
|
||||||
|
)
|
||||||
result = false
|
result = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,27 +34,27 @@ import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class LazyTopDownAnalyzer(
|
class LazyTopDownAnalyzer(
|
||||||
private val trace: BindingTrace,
|
private val trace: BindingTrace,
|
||||||
private val declarationResolver: DeclarationResolver,
|
private val declarationResolver: DeclarationResolver,
|
||||||
private val overrideResolver: OverrideResolver,
|
private val overrideResolver: OverrideResolver,
|
||||||
private val overloadResolver: OverloadResolver,
|
private val overloadResolver: OverloadResolver,
|
||||||
private val varianceChecker: VarianceChecker,
|
private val varianceChecker: VarianceChecker,
|
||||||
private val moduleDescriptor: ModuleDescriptor,
|
private val moduleDescriptor: ModuleDescriptor,
|
||||||
private val lazyDeclarationResolver: LazyDeclarationResolver,
|
private val lazyDeclarationResolver: LazyDeclarationResolver,
|
||||||
private val bodyResolver: BodyResolver,
|
private val bodyResolver: BodyResolver,
|
||||||
private val topLevelDescriptorProvider: TopLevelDescriptorProvider,
|
private val topLevelDescriptorProvider: TopLevelDescriptorProvider,
|
||||||
private val fileScopeProvider: FileScopeProvider,
|
private val fileScopeProvider: FileScopeProvider,
|
||||||
private val declarationScopeProvider: DeclarationScopeProvider,
|
private val declarationScopeProvider: DeclarationScopeProvider,
|
||||||
private val qualifiedExpressionResolver: QualifiedExpressionResolver,
|
private val qualifiedExpressionResolver: QualifiedExpressionResolver,
|
||||||
private val identifierChecker: IdentifierChecker,
|
private val identifierChecker: IdentifierChecker,
|
||||||
private val languageVersionSettings: LanguageVersionSettings,
|
private val languageVersionSettings: LanguageVersionSettings,
|
||||||
private val deprecationResolver: DeprecationResolver,
|
private val deprecationResolver: DeprecationResolver,
|
||||||
private val classifierUsageCheckers: Iterable<ClassifierUsageChecker>
|
private val classifierUsageCheckers: Iterable<ClassifierUsageChecker>
|
||||||
) {
|
) {
|
||||||
fun analyzeDeclarations(
|
fun analyzeDeclarations(
|
||||||
topDownAnalysisMode: TopDownAnalysisMode,
|
topDownAnalysisMode: TopDownAnalysisMode,
|
||||||
declarations: Collection<PsiElement>,
|
declarations: Collection<PsiElement>,
|
||||||
outerDataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY
|
outerDataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY
|
||||||
): TopDownAnalysisContext {
|
): TopDownAnalysisContext {
|
||||||
val c = TopDownAnalysisContext(topDownAnalysisMode, outerDataFlowInfo, declarationScopeProvider)
|
val c = TopDownAnalysisContext(topDownAnalysisMode, outerDataFlowInfo, declarationScopeProvider)
|
||||||
|
|
||||||
@@ -82,8 +82,8 @@ class LazyTopDownAnalyzer(
|
|||||||
|
|
||||||
override fun visitScript(script: KtScript) {
|
override fun visitScript(script: KtScript) {
|
||||||
c.scripts.put(
|
c.scripts.put(
|
||||||
script,
|
script,
|
||||||
lazyDeclarationResolver.getScriptDescriptor(script, KotlinLookupLocation(script)) as LazyScriptDescriptor
|
lazyDeclarationResolver.getScriptDescriptor(script, KotlinLookupLocation(script)) as LazyScriptDescriptor
|
||||||
)
|
)
|
||||||
registerDeclarations(script.declarations)
|
registerDeclarations(script.declarations)
|
||||||
}
|
}
|
||||||
@@ -109,8 +109,10 @@ class LazyTopDownAnalyzer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
|
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
|
||||||
val location = if (classOrObject.isTopLevel()) KotlinLookupLocation(classOrObject) else NoLookupLocation.WHEN_RESOLVE_DECLARATION
|
val location =
|
||||||
val descriptor = lazyDeclarationResolver.getClassDescriptor(classOrObject, location) as ClassDescriptorWithResolutionScopes
|
if (classOrObject.isTopLevel()) KotlinLookupLocation(classOrObject) else NoLookupLocation.WHEN_RESOLVE_DECLARATION
|
||||||
|
val descriptor =
|
||||||
|
lazyDeclarationResolver.getClassDescriptor(classOrObject, location) as ClassDescriptorWithResolutionScopes
|
||||||
|
|
||||||
c.declaredClasses.put(classOrObject, descriptor)
|
c.declaredClasses.put(classOrObject, descriptor)
|
||||||
registerDeclarations(classOrObject.declarations)
|
registerDeclarations(classOrObject.declarations)
|
||||||
@@ -127,12 +129,10 @@ class LazyTopDownAnalyzer(
|
|||||||
trace.report(MANY_COMPANION_OBJECTS.on(jetDeclaration))
|
trace.report(MANY_COMPANION_OBJECTS.on(jetDeclaration))
|
||||||
}
|
}
|
||||||
companionObjectAlreadyFound = true
|
companionObjectAlreadyFound = true
|
||||||
}
|
} else if (jetDeclaration is KtSecondaryConstructor) {
|
||||||
else if (jetDeclaration is KtSecondaryConstructor) {
|
|
||||||
if (DescriptorUtils.isSingletonOrAnonymousObject(classDescriptor)) {
|
if (DescriptorUtils.isSingletonOrAnonymousObject(classDescriptor)) {
|
||||||
trace.report(CONSTRUCTOR_IN_OBJECT.on(jetDeclaration))
|
trace.report(CONSTRUCTOR_IN_OBJECT.on(jetDeclaration))
|
||||||
}
|
} else if (classDescriptor.kind == ClassKind.INTERFACE) {
|
||||||
else if (classDescriptor.kind == ClassKind.INTERFACE) {
|
|
||||||
trace.report(CONSTRUCTOR_IN_INTERFACE.on(jetDeclaration))
|
trace.report(CONSTRUCTOR_IN_INTERFACE.on(jetDeclaration))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -147,13 +147,19 @@ class LazyTopDownAnalyzer(
|
|||||||
private fun registerPrimaryConstructorParameters(klass: KtClass) {
|
private fun registerPrimaryConstructorParameters(klass: KtClass) {
|
||||||
for (jetParameter in klass.primaryConstructorParameters) {
|
for (jetParameter in klass.primaryConstructorParameters) {
|
||||||
if (jetParameter.hasValOrVar()) {
|
if (jetParameter.hasValOrVar()) {
|
||||||
c.primaryConstructorParameterProperties.put(jetParameter, lazyDeclarationResolver.resolveToDescriptor(jetParameter) as PropertyDescriptor)
|
c.primaryConstructorParameterProperties.put(
|
||||||
|
jetParameter,
|
||||||
|
lazyDeclarationResolver.resolveToDescriptor(jetParameter) as PropertyDescriptor
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSecondaryConstructor(constructor: KtSecondaryConstructor) {
|
override fun visitSecondaryConstructor(constructor: KtSecondaryConstructor) {
|
||||||
c.secondaryConstructors.put(constructor, lazyDeclarationResolver.resolveToDescriptor(constructor) as ClassConstructorDescriptor)
|
c.secondaryConstructors.put(
|
||||||
|
constructor,
|
||||||
|
lazyDeclarationResolver.resolveToDescriptor(constructor) as ClassConstructorDescriptor
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitEnumEntry(enumEntry: KtEnumEntry) {
|
override fun visitEnumEntry(enumEntry: KtEnumEntry) {
|
||||||
@@ -165,7 +171,8 @@ class LazyTopDownAnalyzer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun visitAnonymousInitializer(initializer: KtAnonymousInitializer) {
|
override fun visitAnonymousInitializer(initializer: KtAnonymousInitializer) {
|
||||||
val containerDescriptor = lazyDeclarationResolver.resolveToDescriptor(initializer.containingDeclaration) as ClassDescriptorWithResolutionScopes
|
val containerDescriptor =
|
||||||
|
lazyDeclarationResolver.resolveToDescriptor(initializer.containingDeclaration) as ClassDescriptorWithResolutionScopes
|
||||||
c.anonymousInitializers.put(initializer, containerDescriptor)
|
c.anonymousInitializers.put(initializer, containerDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +244,11 @@ class LazyTopDownAnalyzer(
|
|||||||
fileScopeProvider.getImportResolver(file).forceResolveAllImports()
|
fileScopeProvider.getImportResolver(file).forceResolveAllImports()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createTypeAliasDescriptors(c: TopDownAnalysisContext, topLevelFqNames: Multimap<FqName, KtElement>, typeAliases: List<KtTypeAlias>) {
|
private fun createTypeAliasDescriptors(
|
||||||
|
c: TopDownAnalysisContext,
|
||||||
|
topLevelFqNames: Multimap<FqName, KtElement>,
|
||||||
|
typeAliases: List<KtTypeAlias>
|
||||||
|
) {
|
||||||
for (typeAlias in typeAliases) {
|
for (typeAlias in typeAliases) {
|
||||||
val descriptor = lazyDeclarationResolver.resolveToDescriptor(typeAlias) as TypeAliasDescriptor
|
val descriptor = lazyDeclarationResolver.resolveToDescriptor(typeAlias) as TypeAliasDescriptor
|
||||||
|
|
||||||
@@ -247,7 +258,11 @@ class LazyTopDownAnalyzer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createPropertyDescriptors(c: TopDownAnalysisContext, topLevelFqNames: Multimap<FqName, KtElement>, properties: List<KtProperty>) {
|
private fun createPropertyDescriptors(
|
||||||
|
c: TopDownAnalysisContext,
|
||||||
|
topLevelFqNames: Multimap<FqName, KtElement>,
|
||||||
|
properties: List<KtProperty>
|
||||||
|
) {
|
||||||
for (property in properties) {
|
for (property in properties) {
|
||||||
val descriptor = lazyDeclarationResolver.resolveToDescriptor(property) as PropertyDescriptor
|
val descriptor = lazyDeclarationResolver.resolveToDescriptor(property) as PropertyDescriptor
|
||||||
|
|
||||||
@@ -269,9 +284,10 @@ class LazyTopDownAnalyzer(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createPropertiesFromDestructuringDeclarations(
|
private fun createPropertiesFromDestructuringDeclarations(
|
||||||
c: TopDownAnalysisContext,
|
c: TopDownAnalysisContext,
|
||||||
topLevelFqNames: Multimap<FqName, KtElement>,
|
topLevelFqNames: Multimap<FqName, KtElement>,
|
||||||
destructuringDeclarations: List<KtDestructuringDeclaration>) {
|
destructuringDeclarations: List<KtDestructuringDeclaration>
|
||||||
|
) {
|
||||||
for (destructuringDeclaration in destructuringDeclarations) {
|
for (destructuringDeclaration in destructuringDeclarations) {
|
||||||
for (entry in destructuringDeclaration.entries) {
|
for (entry in destructuringDeclaration.entries) {
|
||||||
val descriptor = lazyDeclarationResolver.resolveToDescriptor(entry) as PropertyDescriptor
|
val descriptor = lazyDeclarationResolver.resolveToDescriptor(entry) as PropertyDescriptor
|
||||||
@@ -283,7 +299,11 @@ class LazyTopDownAnalyzer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerTopLevelFqName(topLevelFqNames: Multimap<FqName, KtElement>, declaration: KtNamedDeclaration, descriptor: DeclarationDescriptor) {
|
private fun registerTopLevelFqName(
|
||||||
|
topLevelFqNames: Multimap<FqName, KtElement>,
|
||||||
|
declaration: KtNamedDeclaration,
|
||||||
|
descriptor: DeclarationDescriptor
|
||||||
|
) {
|
||||||
if (DescriptorUtils.isTopLevelDeclaration(descriptor)) {
|
if (DescriptorUtils.isTopLevelDeclaration(descriptor)) {
|
||||||
val fqName = declaration.fqName
|
val fqName = declaration.fqName
|
||||||
if (fqName != null) {
|
if (fqName != null) {
|
||||||
|
|||||||
@@ -52,93 +52,123 @@ object ModifierCheckerCore {
|
|||||||
COMPATIBLE_FOR_CLASSES_ONLY
|
COMPATIBLE_FOR_CLASSES_ONLY
|
||||||
}
|
}
|
||||||
|
|
||||||
private val defaultVisibilityTargets = EnumSet.of(CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
|
private val defaultVisibilityTargets = EnumSet.of(
|
||||||
MEMBER_FUNCTION, TOP_LEVEL_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER,
|
CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
|
||||||
MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, CONSTRUCTOR, TYPEALIAS)
|
MEMBER_FUNCTION, TOP_LEVEL_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER,
|
||||||
|
MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, CONSTRUCTOR, TYPEALIAS
|
||||||
|
)
|
||||||
|
|
||||||
val possibleTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>(
|
val possibleTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>(
|
||||||
ENUM_KEYWORD to EnumSet.of(ENUM_CLASS),
|
ENUM_KEYWORD to EnumSet.of(ENUM_CLASS),
|
||||||
ABSTRACT_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
ABSTRACT_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||||
OPEN_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
OPEN_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, INTERFACE, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||||
FINAL_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS, OBJECT, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
FINAL_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS, OBJECT, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||||
SEALED_KEYWORD to EnumSet.of(CLASS_ONLY),
|
SEALED_KEYWORD to EnumSet.of(CLASS_ONLY),
|
||||||
INNER_KEYWORD to EnumSet.of(CLASS_ONLY),
|
INNER_KEYWORD to EnumSet.of(CLASS_ONLY),
|
||||||
OVERRIDE_KEYWORD to EnumSet.of(MEMBER_PROPERTY, MEMBER_FUNCTION),
|
OVERRIDE_KEYWORD to EnumSet.of(MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||||
PRIVATE_KEYWORD to defaultVisibilityTargets,
|
PRIVATE_KEYWORD to defaultVisibilityTargets,
|
||||||
PUBLIC_KEYWORD to defaultVisibilityTargets,
|
PUBLIC_KEYWORD to defaultVisibilityTargets,
|
||||||
INTERNAL_KEYWORD to defaultVisibilityTargets,
|
INTERNAL_KEYWORD to defaultVisibilityTargets,
|
||||||
PROTECTED_KEYWORD to EnumSet.of(CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
|
PROTECTED_KEYWORD to EnumSet.of(
|
||||||
MEMBER_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, MEMBER_PROPERTY, CONSTRUCTOR, TYPEALIAS),
|
CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
|
||||||
IN_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
|
MEMBER_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, MEMBER_PROPERTY, CONSTRUCTOR, TYPEALIAS
|
||||||
OUT_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
|
),
|
||||||
REIFIED_KEYWORD to EnumSet.of(TYPE_PARAMETER),
|
IN_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
|
||||||
VARARG_KEYWORD to EnumSet.of(VALUE_PARAMETER, PROPERTY_PARAMETER),
|
OUT_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
|
||||||
COMPANION_KEYWORD to EnumSet.of(OBJECT),
|
REIFIED_KEYWORD to EnumSet.of(TYPE_PARAMETER),
|
||||||
LATEINIT_KEYWORD to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, LOCAL_VARIABLE),
|
VARARG_KEYWORD to EnumSet.of(VALUE_PARAMETER, PROPERTY_PARAMETER),
|
||||||
DATA_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS),
|
COMPANION_KEYWORD to EnumSet.of(OBJECT),
|
||||||
INLINE_KEYWORD to EnumSet.of(FUNCTION, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER),
|
LATEINIT_KEYWORD to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, LOCAL_VARIABLE),
|
||||||
NOINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
|
DATA_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS),
|
||||||
TAILREC_KEYWORD to EnumSet.of(FUNCTION),
|
INLINE_KEYWORD to EnumSet.of(FUNCTION, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER),
|
||||||
SUSPEND_KEYWORD to EnumSet.of(MEMBER_FUNCTION, TOP_LEVEL_FUNCTION),
|
NOINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
|
||||||
EXTERNAL_KEYWORD to EnumSet.of(FUNCTION, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER, CLASS),
|
TAILREC_KEYWORD to EnumSet.of(FUNCTION),
|
||||||
ANNOTATION_KEYWORD to EnumSet.of(ANNOTATION_CLASS),
|
SUSPEND_KEYWORD to EnumSet.of(MEMBER_FUNCTION, TOP_LEVEL_FUNCTION),
|
||||||
CROSSINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
|
EXTERNAL_KEYWORD to EnumSet.of(FUNCTION, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER, CLASS),
|
||||||
CONST_KEYWORD to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY),
|
ANNOTATION_KEYWORD to EnumSet.of(ANNOTATION_CLASS),
|
||||||
OPERATOR_KEYWORD to EnumSet.of(FUNCTION),
|
CROSSINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
|
||||||
INFIX_KEYWORD to EnumSet.of(FUNCTION),
|
CONST_KEYWORD to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY),
|
||||||
HEADER_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
|
OPERATOR_KEYWORD to EnumSet.of(FUNCTION),
|
||||||
IMPL_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, MEMBER_FUNCTION, TOP_LEVEL_PROPERTY, MEMBER_PROPERTY, CONSTRUCTOR, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS, TYPEALIAS),
|
INFIX_KEYWORD to EnumSet.of(FUNCTION),
|
||||||
EXPECT_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
|
HEADER_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
|
||||||
ACTUAL_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, MEMBER_FUNCTION, TOP_LEVEL_PROPERTY, MEMBER_PROPERTY, CONSTRUCTOR, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS, TYPEALIAS)
|
IMPL_KEYWORD to EnumSet.of(
|
||||||
|
TOP_LEVEL_FUNCTION,
|
||||||
|
MEMBER_FUNCTION,
|
||||||
|
TOP_LEVEL_PROPERTY,
|
||||||
|
MEMBER_PROPERTY,
|
||||||
|
CONSTRUCTOR,
|
||||||
|
CLASS_ONLY,
|
||||||
|
OBJECT,
|
||||||
|
INTERFACE,
|
||||||
|
ENUM_CLASS,
|
||||||
|
ANNOTATION_CLASS,
|
||||||
|
TYPEALIAS
|
||||||
|
),
|
||||||
|
EXPECT_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
|
||||||
|
ACTUAL_KEYWORD to EnumSet.of(
|
||||||
|
TOP_LEVEL_FUNCTION,
|
||||||
|
MEMBER_FUNCTION,
|
||||||
|
TOP_LEVEL_PROPERTY,
|
||||||
|
MEMBER_PROPERTY,
|
||||||
|
CONSTRUCTOR,
|
||||||
|
CLASS_ONLY,
|
||||||
|
OBJECT,
|
||||||
|
INTERFACE,
|
||||||
|
ENUM_CLASS,
|
||||||
|
ANNOTATION_CLASS,
|
||||||
|
TYPEALIAS
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
private val featureDependencies = mapOf(
|
private val featureDependencies = mapOf(
|
||||||
SUSPEND_KEYWORD to listOf(LanguageFeature.Coroutines),
|
SUSPEND_KEYWORD to listOf(LanguageFeature.Coroutines),
|
||||||
INLINE_KEYWORD to listOf(LanguageFeature.InlineProperties),
|
INLINE_KEYWORD to listOf(LanguageFeature.InlineProperties),
|
||||||
HEADER_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
HEADER_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
||||||
IMPL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
IMPL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
||||||
EXPECT_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
EXPECT_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
||||||
ACTUAL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
ACTUAL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
||||||
LATEINIT_KEYWORD to listOf(LanguageFeature.LateinitTopLevelProperties, LanguageFeature.LateinitLocalVariables)
|
LATEINIT_KEYWORD to listOf(LanguageFeature.LateinitTopLevelProperties, LanguageFeature.LateinitLocalVariables)
|
||||||
)
|
)
|
||||||
|
|
||||||
private val featureDependenciesTargets = mapOf(
|
private val featureDependenciesTargets = mapOf(
|
||||||
LanguageFeature.InlineProperties to setOf(PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER),
|
LanguageFeature.InlineProperties to setOf(PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER),
|
||||||
LanguageFeature.LateinitLocalVariables to setOf(LOCAL_VARIABLE),
|
LanguageFeature.LateinitLocalVariables to setOf(LOCAL_VARIABLE),
|
||||||
LanguageFeature.LateinitTopLevelProperties to setOf(TOP_LEVEL_PROPERTY)
|
LanguageFeature.LateinitTopLevelProperties to setOf(TOP_LEVEL_PROPERTY)
|
||||||
)
|
)
|
||||||
|
|
||||||
// NOTE: deprecated targets must be possible!
|
// NOTE: deprecated targets must be possible!
|
||||||
private val deprecatedTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>()
|
private val deprecatedTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>()
|
||||||
|
|
||||||
private val deprecatedModifierMap = mapOf(
|
private val deprecatedModifierMap = mapOf(
|
||||||
HEADER_KEYWORD to EXPECT_KEYWORD,
|
HEADER_KEYWORD to EXPECT_KEYWORD,
|
||||||
IMPL_KEYWORD to ACTUAL_KEYWORD
|
IMPL_KEYWORD to ACTUAL_KEYWORD
|
||||||
)
|
)
|
||||||
|
|
||||||
// NOTE: redundant targets must be possible!
|
// NOTE: redundant targets must be possible!
|
||||||
private val redundantTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>(
|
private val redundantTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>(
|
||||||
OPEN_KEYWORD to EnumSet.of(INTERFACE)
|
OPEN_KEYWORD to EnumSet.of(INTERFACE)
|
||||||
)
|
)
|
||||||
|
|
||||||
private val possibleParentTargetPredicateMap = mapOf<KtModifierKeywordToken, TargetAllowedPredicate>(
|
private val possibleParentTargetPredicateMap = mapOf<KtModifierKeywordToken, TargetAllowedPredicate>(
|
||||||
INNER_KEYWORD to or(always(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS),
|
INNER_KEYWORD to or(
|
||||||
ifSupported(LanguageFeature.InnerClassInEnumEntryClass, ENUM_ENTRY)),
|
always(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS),
|
||||||
OVERRIDE_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, INTERFACE, ENUM_CLASS, ENUM_ENTRY),
|
ifSupported(LanguageFeature.InnerClassInEnumEntryClass, ENUM_ENTRY)
|
||||||
PROTECTED_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS, COMPANION_OBJECT),
|
),
|
||||||
INTERNAL_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, ENUM_CLASS, ENUM_ENTRY, FILE),
|
OVERRIDE_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, INTERFACE, ENUM_CLASS, ENUM_ENTRY),
|
||||||
PRIVATE_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, INTERFACE, ENUM_CLASS, ENUM_ENTRY, FILE),
|
PROTECTED_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS, COMPANION_OBJECT),
|
||||||
COMPANION_KEYWORD to always(CLASS_ONLY, ENUM_CLASS, INTERFACE),
|
INTERNAL_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, ENUM_CLASS, ENUM_ENTRY, FILE),
|
||||||
FINAL_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, ENUM_CLASS, ENUM_ENTRY, ANNOTATION_CLASS, FILE),
|
PRIVATE_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, INTERFACE, ENUM_CLASS, ENUM_ENTRY, FILE),
|
||||||
VARARG_KEYWORD to always(CONSTRUCTOR, FUNCTION, CLASS)
|
COMPANION_KEYWORD to always(CLASS_ONLY, ENUM_CLASS, INTERFACE),
|
||||||
|
FINAL_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, ENUM_CLASS, ENUM_ENTRY, ANNOTATION_CLASS, FILE),
|
||||||
|
VARARG_KEYWORD to always(CONSTRUCTOR, FUNCTION, CLASS)
|
||||||
)
|
)
|
||||||
|
|
||||||
private val deprecatedParentTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>()
|
private val deprecatedParentTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>()
|
||||||
|
|
||||||
fun isPossibleParentTarget(
|
fun isPossibleParentTarget(
|
||||||
modifier: KtModifierKeywordToken,
|
modifier: KtModifierKeywordToken,
|
||||||
parentTarget: KotlinTarget,
|
parentTarget: KotlinTarget,
|
||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
): Boolean {
|
): Boolean {
|
||||||
deprecatedParentTargetMap[modifier]?.let {
|
deprecatedParentTargetMap[modifier]?.let {
|
||||||
if (parentTarget in it) return false
|
if (parentTarget in it) return false
|
||||||
@@ -198,15 +228,17 @@ object ModifierCheckerCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun redundantRegister(
|
private fun redundantRegister(
|
||||||
sufficient: KtModifierKeywordToken,
|
sufficient: KtModifierKeywordToken,
|
||||||
redundant: KtModifierKeywordToken
|
redundant: KtModifierKeywordToken
|
||||||
): Map<Pair<KtModifierKeywordToken, KtModifierKeywordToken>, Compatibility> {
|
): Map<Pair<KtModifierKeywordToken, KtModifierKeywordToken>, Compatibility> {
|
||||||
return mapOf(Pair(sufficient, redundant) to Compatibility.REDUNDANT,
|
return mapOf(
|
||||||
Pair(redundant, sufficient) to Compatibility.REVERSE_REDUNDANT)
|
Pair(sufficient, redundant) to Compatibility.REDUNDANT,
|
||||||
|
Pair(redundant, sufficient) to Compatibility.REVERSE_REDUNDANT
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun compatibilityRegister(
|
private fun compatibilityRegister(
|
||||||
compatibility: Compatibility, vararg list: KtModifierKeywordToken
|
compatibility: Compatibility, vararg list: KtModifierKeywordToken
|
||||||
): Map<Pair<KtModifierKeywordToken, KtModifierKeywordToken>, Compatibility> {
|
): Map<Pair<KtModifierKeywordToken, KtModifierKeywordToken>, Compatibility> {
|
||||||
val result = hashMapOf<Pair<KtModifierKeywordToken, KtModifierKeywordToken>, Compatibility>()
|
val result = hashMapOf<Pair<KtModifierKeywordToken, KtModifierKeywordToken>, Compatibility>()
|
||||||
for (first in list) {
|
for (first in list) {
|
||||||
@@ -220,7 +252,7 @@ object ModifierCheckerCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun compatibilityForClassesRegister(vararg list: KtModifierKeywordToken) =
|
private fun compatibilityForClassesRegister(vararg list: KtModifierKeywordToken) =
|
||||||
compatibilityRegister(Compatibility.COMPATIBLE_FOR_CLASSES_ONLY, *list)
|
compatibilityRegister(Compatibility.COMPATIBLE_FOR_CLASSES_ONLY, *list)
|
||||||
|
|
||||||
private fun incompatibilityRegister(vararg list: KtModifierKeywordToken) = compatibilityRegister(Compatibility.INCOMPATIBLE, *list)
|
private fun incompatibilityRegister(vararg list: KtModifierKeywordToken) = compatibilityRegister(Compatibility.INCOMPATIBLE, *list)
|
||||||
|
|
||||||
@@ -229,29 +261,31 @@ object ModifierCheckerCore {
|
|||||||
private fun compatibility(first: KtModifierKeywordToken, second: KtModifierKeywordToken): Compatibility {
|
private fun compatibility(first: KtModifierKeywordToken, second: KtModifierKeywordToken): Compatibility {
|
||||||
return if (first == second) {
|
return if (first == second) {
|
||||||
Compatibility.REPEATED
|
Compatibility.REPEATED
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
mutualCompatibility[Pair(first, second)] ?: Compatibility.COMPATIBLE
|
mutualCompatibility[Pair(first, second)] ?: Compatibility.COMPATIBLE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkCompatibility(trace: BindingTrace,
|
private fun checkCompatibility(
|
||||||
firstNode: ASTNode,
|
trace: BindingTrace,
|
||||||
secondNode: ASTNode,
|
firstNode: ASTNode,
|
||||||
owner: PsiElement,
|
secondNode: ASTNode,
|
||||||
incorrectNodes: MutableSet<ASTNode>) {
|
owner: PsiElement,
|
||||||
|
incorrectNodes: MutableSet<ASTNode>
|
||||||
|
) {
|
||||||
val first = firstNode.elementType as KtModifierKeywordToken
|
val first = firstNode.elementType as KtModifierKeywordToken
|
||||||
val second = secondNode.elementType as KtModifierKeywordToken
|
val second = secondNode.elementType as KtModifierKeywordToken
|
||||||
val compatibility = compatibility(first, second)
|
val compatibility = compatibility(first, second)
|
||||||
when (compatibility) {
|
when (compatibility) {
|
||||||
Compatibility.COMPATIBLE -> {}
|
Compatibility.COMPATIBLE -> {
|
||||||
|
}
|
||||||
Compatibility.REPEATED -> if (incorrectNodes.add(secondNode)) {
|
Compatibility.REPEATED -> if (incorrectNodes.add(secondNode)) {
|
||||||
trace.report(Errors.REPEATED_MODIFIER.on (secondNode.psi, first))
|
trace.report(Errors.REPEATED_MODIFIER.on(secondNode.psi, first))
|
||||||
}
|
}
|
||||||
Compatibility.REDUNDANT ->
|
Compatibility.REDUNDANT ->
|
||||||
trace.report(Errors.REDUNDANT_MODIFIER.on(secondNode.psi, second, first))
|
trace.report(Errors.REDUNDANT_MODIFIER.on(secondNode.psi, second, first))
|
||||||
Compatibility.REVERSE_REDUNDANT ->
|
Compatibility.REVERSE_REDUNDANT ->
|
||||||
trace.report(Errors.REDUNDANT_MODIFIER.on(firstNode.psi, first, second))
|
trace.report(Errors.REDUNDANT_MODIFIER.on(firstNode.psi, first, second))
|
||||||
Compatibility.DEPRECATED -> {
|
Compatibility.DEPRECATED -> {
|
||||||
trace.report(Errors.DEPRECATED_MODIFIER_PAIR.on(firstNode.psi, first, second))
|
trace.report(Errors.DEPRECATED_MODIFIER_PAIR.on(firstNode.psi, first, second))
|
||||||
trace.report(Errors.DEPRECATED_MODIFIER_PAIR.on(secondNode.psi, second, first))
|
trace.report(Errors.DEPRECATED_MODIFIER_PAIR.on(secondNode.psi, second, first))
|
||||||
@@ -285,18 +319,30 @@ object ModifierCheckerCore {
|
|||||||
deprecatedModifierReplacement != null ->
|
deprecatedModifierReplacement != null ->
|
||||||
trace.report(Errors.DEPRECATED_MODIFIER.on(node.psi, modifier, deprecatedModifierReplacement))
|
trace.report(Errors.DEPRECATED_MODIFIER.on(node.psi, modifier, deprecatedModifierReplacement))
|
||||||
actualTargets.any { it in deprecatedTargets } ->
|
actualTargets.any { it in deprecatedTargets } ->
|
||||||
trace.report(Errors.DEPRECATED_MODIFIER_FOR_TARGET.on(node.psi, modifier, actualTargets.firstOrNull()?.description ?: "this"))
|
trace.report(
|
||||||
|
Errors.DEPRECATED_MODIFIER_FOR_TARGET.on(
|
||||||
|
node.psi,
|
||||||
|
modifier,
|
||||||
|
actualTargets.firstOrNull()?.description ?: "this"
|
||||||
|
)
|
||||||
|
)
|
||||||
actualTargets.any { it in redundantTargets } ->
|
actualTargets.any { it in redundantTargets } ->
|
||||||
trace.report(Errors.REDUNDANT_MODIFIER_FOR_TARGET.on(node.psi, modifier, actualTargets.firstOrNull()?.description ?: "this"))
|
trace.report(
|
||||||
|
Errors.REDUNDANT_MODIFIER_FOR_TARGET.on(
|
||||||
|
node.psi,
|
||||||
|
modifier,
|
||||||
|
actualTargets.firstOrNull()?.description ?: "this"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkLanguageLevelSupport(
|
private fun checkLanguageLevelSupport(
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
node: ASTNode,
|
node: ASTNode,
|
||||||
languageVersionSettings: LanguageVersionSettings,
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
actualTargets: List<KotlinTarget>
|
actualTargets: List<KotlinTarget>
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val modifier = node.elementType as KtModifierKeywordToken
|
val modifier = node.elementType as KtModifierKeywordToken
|
||||||
|
|
||||||
@@ -313,8 +359,7 @@ object ModifierCheckerCore {
|
|||||||
|
|
||||||
if (featureSupport == LanguageFeature.State.DISABLED) {
|
if (featureSupport == LanguageFeature.State.DISABLED) {
|
||||||
trace.report(Errors.UNSUPPORTED_FEATURE.on(node.psi, diagnosticData))
|
trace.report(Errors.UNSUPPORTED_FEATURE.on(node.psi, diagnosticData))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
trace.report(Errors.EXPERIMENTAL_FEATURE_ERROR.on(node.psi, diagnosticData))
|
trace.report(Errors.EXPERIMENTAL_FEATURE_ERROR.on(node.psi, diagnosticData))
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
@@ -330,7 +375,12 @@ object ModifierCheckerCore {
|
|||||||
|
|
||||||
|
|
||||||
// Should return false if error is reported, true otherwise
|
// Should return false if error is reported, true otherwise
|
||||||
private fun checkParent(trace: BindingTrace, node: ASTNode, parentDescriptor: DeclarationDescriptor?, languageVersionSettings: LanguageVersionSettings): Boolean {
|
private fun checkParent(
|
||||||
|
trace: BindingTrace,
|
||||||
|
node: ASTNode,
|
||||||
|
parentDescriptor: DeclarationDescriptor?,
|
||||||
|
languageVersionSettings: LanguageVersionSettings
|
||||||
|
): Boolean {
|
||||||
val modifier = node.elementType as KtModifierKeywordToken
|
val modifier = node.elementType as KtModifierKeywordToken
|
||||||
val actualParents: List<KotlinTarget> = when (parentDescriptor) {
|
val actualParents: List<KotlinTarget> = when (parentDescriptor) {
|
||||||
is ClassDescriptor -> KotlinTarget.classActualTargets(parentDescriptor)
|
is ClassDescriptor -> KotlinTarget.classActualTargets(parentDescriptor)
|
||||||
@@ -341,23 +391,35 @@ object ModifierCheckerCore {
|
|||||||
}
|
}
|
||||||
val deprecatedParents = deprecatedParentTargetMap[modifier]
|
val deprecatedParents = deprecatedParentTargetMap[modifier]
|
||||||
if (deprecatedParents != null && actualParents.any { it in deprecatedParents }) {
|
if (deprecatedParents != null && actualParents.any { it in deprecatedParents }) {
|
||||||
trace.report(Errors.DEPRECATED_MODIFIER_CONTAINING_DECLARATION.on(node.psi, modifier, actualParents.firstOrNull()?.description ?: "this scope"))
|
trace.report(
|
||||||
|
Errors.DEPRECATED_MODIFIER_CONTAINING_DECLARATION.on(
|
||||||
|
node.psi,
|
||||||
|
modifier,
|
||||||
|
actualParents.firstOrNull()?.description ?: "this scope"
|
||||||
|
)
|
||||||
|
)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
val possibleParentPredicate = possibleParentTargetPredicateMap[modifier] ?: return true
|
val possibleParentPredicate = possibleParentTargetPredicateMap[modifier] ?: return true
|
||||||
if (actualParents.any { possibleParentPredicate.isAllowed(it, languageVersionSettings) }) return true
|
if (actualParents.any { possibleParentPredicate.isAllowed(it, languageVersionSettings) }) return true
|
||||||
trace.report(Errors.WRONG_MODIFIER_CONTAINING_DECLARATION.on(node.psi, modifier, actualParents.firstOrNull()?.description ?: "this scope"))
|
trace.report(
|
||||||
|
Errors.WRONG_MODIFIER_CONTAINING_DECLARATION.on(
|
||||||
|
node.psi,
|
||||||
|
modifier,
|
||||||
|
actualParents.firstOrNull()?.description ?: "this scope"
|
||||||
|
)
|
||||||
|
)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private val MODIFIER_KEYWORD_SET = TokenSet.orSet(KtTokens.SOFT_KEYWORDS, TokenSet.create(KtTokens.IN_KEYWORD))
|
private val MODIFIER_KEYWORD_SET = TokenSet.orSet(KtTokens.SOFT_KEYWORDS, TokenSet.create(KtTokens.IN_KEYWORD))
|
||||||
|
|
||||||
private fun checkModifierList(
|
private fun checkModifierList(
|
||||||
list: KtModifierList,
|
list: KtModifierList,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
parentDescriptor: DeclarationDescriptor?,
|
parentDescriptor: DeclarationDescriptor?,
|
||||||
actualTargets: List<KotlinTarget>,
|
actualTargets: List<KotlinTarget>,
|
||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
) {
|
) {
|
||||||
// It's a list of all nodes with error already reported
|
// It's a list of all nodes with error already reported
|
||||||
// General strategy: report no more than one error but any number of warnings
|
// General strategy: report no more than one error but any number of warnings
|
||||||
@@ -381,10 +443,10 @@ object ModifierCheckerCore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun check(
|
fun check(
|
||||||
listOwner: KtModifierListOwner,
|
listOwner: KtModifierListOwner,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
descriptor: DeclarationDescriptor?,
|
descriptor: DeclarationDescriptor?,
|
||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
) {
|
) {
|
||||||
if (listOwner is KtDeclarationWithBody) {
|
if (listOwner is KtDeclarationWithBody) {
|
||||||
// JetFunction or JetPropertyAccessor
|
// JetFunction or JetPropertyAccessor
|
||||||
@@ -410,18 +472,19 @@ private fun always(target: KotlinTarget, vararg targets: KotlinTarget) = object
|
|||||||
private val targetSet = EnumSet.of(target, *targets)
|
private val targetSet = EnumSet.of(target, *targets)
|
||||||
|
|
||||||
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
|
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
|
||||||
target in targetSet
|
target in targetSet
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun ifSupported(languageFeature: LanguageFeature, target: KotlinTarget, vararg targets: KotlinTarget) = object : TargetAllowedPredicate {
|
private fun ifSupported(languageFeature: LanguageFeature, target: KotlinTarget, vararg targets: KotlinTarget) =
|
||||||
private val targetSet = EnumSet.of(target, *targets)
|
object : TargetAllowedPredicate {
|
||||||
|
private val targetSet = EnumSet.of(target, *targets)
|
||||||
|
|
||||||
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
|
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
|
||||||
languageVersionSettings.supportsFeature(languageFeature) && target in targetSet
|
languageVersionSettings.supportsFeature(languageFeature) && target in targetSet
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun or(p1: TargetAllowedPredicate, p2: TargetAllowedPredicate) = object : TargetAllowedPredicate {
|
private fun or(p1: TargetAllowedPredicate, p2: TargetAllowedPredicate) = object : TargetAllowedPredicate {
|
||||||
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
|
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
|
||||||
p1.isAllowed(target, languageVersionSettings) ||
|
p1.isAllowed(target, languageVersionSettings) ||
|
||||||
p2.isAllowed(target, languageVersionSettings)
|
p2.isAllowed(target, languageVersionSettings)
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-8
@@ -31,9 +31,9 @@ import org.jetbrains.kotlin.utils.DFS
|
|||||||
object NonExpansiveInheritanceRestrictionChecker {
|
object NonExpansiveInheritanceRestrictionChecker {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun check(
|
fun check(
|
||||||
declaration: KtClass,
|
declaration: KtClass,
|
||||||
classDescriptor: ClassDescriptor,
|
classDescriptor: ClassDescriptor,
|
||||||
diagnosticHolder: DiagnosticSink
|
diagnosticHolder: DiagnosticSink
|
||||||
) {
|
) {
|
||||||
val typeConstructor = classDescriptor.typeConstructor
|
val typeConstructor = classDescriptor.typeConstructor
|
||||||
if (typeConstructor.parameters.isEmpty()) return
|
if (typeConstructor.parameters.isEmpty()) return
|
||||||
@@ -104,11 +104,14 @@ object NonExpansiveInheritanceRestrictionChecker {
|
|||||||
|
|
||||||
for (typeParameter in typeParameters) {
|
for (typeParameter in typeParameters) {
|
||||||
if (typeParameter.defaultType in constituents || typeParameter.defaultType.makeNullableAsSpecified(true) in constituents) {
|
if (typeParameter.defaultType in constituents || typeParameter.defaultType.makeNullableAsSpecified(true) in constituents) {
|
||||||
addEdge(typeParameter, constituentTypeConstructor.parameters[i], !TypeUtils.isTypeParameter(typeProjection.type))
|
addEdge(
|
||||||
|
typeParameter,
|
||||||
|
constituentTypeConstructor.parameters[i],
|
||||||
|
!TypeUtils.isTypeParameter(typeProjection.type)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// Furthermore, if T appears as a constituent type of an element of the B-closure of the set of lower and
|
// Furthermore, if T appears as a constituent type of an element of the B-closure of the set of lower and
|
||||||
// upper bounds of a skolem type variable Q in a skolemization of a projected generic type in ST, add an
|
// upper bounds of a skolem type variable Q in a skolemization of a projected generic type in ST, add an
|
||||||
// expanding edge from T to V, where V is the type parameter corresponding to Q.
|
// expanding edge from T to V, where V is the type parameter corresponding to Q.
|
||||||
@@ -116,7 +119,8 @@ object NonExpansiveInheritanceRestrictionChecker {
|
|||||||
val bounds = hashSetOf<KotlinType>()
|
val bounds = hashSetOf<KotlinType>()
|
||||||
|
|
||||||
val substitutor = TypeConstructorSubstitution.create(constituentType).buildSubstitutor()
|
val substitutor = TypeConstructorSubstitution.create(constituentType).buildSubstitutor()
|
||||||
val adaptedUpperBounds = originalTypeParameter.upperBounds.mapNotNull { substitutor.substitute(it, Variance.INVARIANT) }
|
val adaptedUpperBounds =
|
||||||
|
originalTypeParameter.upperBounds.mapNotNull { substitutor.substitute(it, Variance.INVARIANT) }
|
||||||
bounds.addAll(adaptedUpperBounds)
|
bounds.addAll(adaptedUpperBounds)
|
||||||
|
|
||||||
if (!typeProjection.isStarProjection) {
|
if (!typeProjection.isStarProjection) {
|
||||||
@@ -138,7 +142,7 @@ object NonExpansiveInheritanceRestrictionChecker {
|
|||||||
|
|
||||||
private data class ExpansiveEdge<out T>(val from: T, val to: T)
|
private data class ExpansiveEdge<out T>(val from: T, val to: T)
|
||||||
|
|
||||||
private interface Graph<T> {
|
private interface Graph<T> {
|
||||||
fun getNeighbors(node: T): Collection<T>
|
fun getNeighbors(node: T): Collection<T>
|
||||||
val expansiveEdges: Set<ExpansiveEdge<T>>
|
val expansiveEdges: Set<ExpansiveEdge<T>>
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ import org.jetbrains.kotlin.utils.addToStdlib.assertedCast
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class OverrideResolver(
|
class OverrideResolver(
|
||||||
private val trace: BindingTrace,
|
private val trace: BindingTrace,
|
||||||
private val overridesBackwardCompatibilityHelper: OverridesBackwardCompatibilityHelper,
|
private val overridesBackwardCompatibilityHelper: OverridesBackwardCompatibilityHelper,
|
||||||
private val languageVersionSettings: LanguageVersionSettings
|
private val languageVersionSettings: LanguageVersionSettings
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun check(c: TopDownAnalysisContext) {
|
fun check(c: TopDownAnalysisContext) {
|
||||||
@@ -106,14 +106,17 @@ class OverrideResolver(
|
|||||||
// don't care
|
// don't care
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun abstractMemberWithMoreSpecificType(abstractMember: CallableMemberDescriptor, concreteMember: CallableMemberDescriptor) {
|
override fun abstractMemberWithMoreSpecificType(
|
||||||
|
abstractMember: CallableMemberDescriptor,
|
||||||
|
concreteMember: CallableMemberDescriptor
|
||||||
|
) {
|
||||||
shouldImplement.add(abstractMember)
|
shouldImplement.add(abstractMember)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class CollectErrorInformationForInheritedMembersStrategy(
|
private inner class CollectErrorInformationForInheritedMembersStrategy(
|
||||||
private val klass: KtClassOrObject,
|
private val klass: KtClassOrObject,
|
||||||
private val classDescriptor: ClassDescriptor
|
private val classDescriptor: ClassDescriptor
|
||||||
) : CheckInheritedSignaturesReportStrategy, CheckOverrideReportStrategy {
|
) : CheckInheritedSignaturesReportStrategy, CheckOverrideReportStrategy {
|
||||||
|
|
||||||
private val abstractNoImpl = linkedSetOf<CallableMemberDescriptor>()
|
private val abstractNoImpl = linkedSetOf<CallableMemberDescriptor>()
|
||||||
@@ -147,24 +150,25 @@ class OverrideResolver(
|
|||||||
if (descriptor1 is PropertyDescriptor && descriptor2 is PropertyDescriptor) {
|
if (descriptor1 is PropertyDescriptor && descriptor2 is PropertyDescriptor) {
|
||||||
if (descriptor1.isVar || descriptor2.isVar) {
|
if (descriptor1.isVar || descriptor2.isVar) {
|
||||||
reportInheritanceConflictIfRequired(VAR_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2)
|
reportInheritanceConflictIfRequired(VAR_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
reportInheritanceConflictIfRequired(PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2)
|
reportInheritanceConflictIfRequired(PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
reportInheritanceConflictIfRequired(RETURN_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2)
|
reportInheritanceConflictIfRequired(RETURN_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun abstractMemberWithMoreSpecificType(abstractMember: CallableMemberDescriptor, concreteMember: CallableMemberDescriptor) {
|
override fun abstractMemberWithMoreSpecificType(
|
||||||
|
abstractMember: CallableMemberDescriptor,
|
||||||
|
concreteMember: CallableMemberDescriptor
|
||||||
|
) {
|
||||||
typeMismatchOnInheritance(abstractMember, concreteMember)
|
typeMismatchOnInheritance(abstractMember, concreteMember)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun reportInheritanceConflictIfRequired(
|
private fun reportInheritanceConflictIfRequired(
|
||||||
diagnosticFactory: DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor>,
|
diagnosticFactory: DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor>,
|
||||||
descriptor1: CallableMemberDescriptor,
|
descriptor1: CallableMemberDescriptor,
|
||||||
descriptor2: CallableMemberDescriptor
|
descriptor2: CallableMemberDescriptor
|
||||||
) {
|
) {
|
||||||
if (!onceErrorsReported.contains(diagnosticFactory)) {
|
if (!onceErrorsReported.contains(diagnosticFactory)) {
|
||||||
onceErrorsReported.add(diagnosticFactory)
|
onceErrorsReported.add(diagnosticFactory)
|
||||||
@@ -177,19 +181,21 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun returnTypeMismatchOnOverride(
|
override fun returnTypeMismatchOnOverride(
|
||||||
overriding: CallableMemberDescriptor,
|
overriding: CallableMemberDescriptor,
|
||||||
overridden: CallableMemberDescriptor
|
overridden: CallableMemberDescriptor
|
||||||
) {
|
) {
|
||||||
reportDelegationProblemIfRequired(
|
reportDelegationProblemIfRequired(
|
||||||
RETURN_TYPE_MISMATCH_BY_DELEGATION, RETURN_TYPE_MISMATCH_ON_INHERITANCE, overriding, overridden)
|
RETURN_TYPE_MISMATCH_BY_DELEGATION, RETURN_TYPE_MISMATCH_ON_INHERITANCE, overriding, overridden
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun propertyTypeMismatchOnOverride(
|
override fun propertyTypeMismatchOnOverride(
|
||||||
overriding: PropertyDescriptor,
|
overriding: PropertyDescriptor,
|
||||||
overridden: PropertyDescriptor
|
overridden: PropertyDescriptor
|
||||||
) {
|
) {
|
||||||
reportDelegationProblemIfRequired(
|
reportDelegationProblemIfRequired(
|
||||||
PROPERTY_TYPE_MISMATCH_BY_DELEGATION, PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, overriding, overridden)
|
PROPERTY_TYPE_MISMATCH_BY_DELEGATION, PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, overriding, overridden
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun varOverriddenByVal(overriding: CallableMemberDescriptor, overridden: CallableMemberDescriptor) {
|
override fun varOverriddenByVal(overriding: CallableMemberDescriptor, overridden: CallableMemberDescriptor) {
|
||||||
@@ -197,14 +203,16 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun reportDelegationProblemIfRequired(
|
private fun reportDelegationProblemIfRequired(
|
||||||
diagnosticFactory: DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor>,
|
diagnosticFactory: DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor>,
|
||||||
relevantDiagnosticFromInheritance: DiagnosticFactoryWithPsiElement<*, *>?,
|
relevantDiagnosticFromInheritance: DiagnosticFactoryWithPsiElement<*, *>?,
|
||||||
delegate: CallableMemberDescriptor,
|
delegate: CallableMemberDescriptor,
|
||||||
overridden: CallableMemberDescriptor
|
overridden: CallableMemberDescriptor
|
||||||
) {
|
) {
|
||||||
assert(delegate.kind == DELEGATION) { "Delegate expected, got " + delegate + " of kind " + delegate.kind }
|
assert(delegate.kind == DELEGATION) { "Delegate expected, got " + delegate + " of kind " + delegate.kind }
|
||||||
|
|
||||||
if (!onceErrorsReported.contains(diagnosticFactory) && (relevantDiagnosticFromInheritance == null || !onceErrorsReported.contains(relevantDiagnosticFromInheritance))) {
|
if (!onceErrorsReported.contains(diagnosticFactory) && (relevantDiagnosticFromInheritance == null || !onceErrorsReported.contains(
|
||||||
|
relevantDiagnosticFromInheritance
|
||||||
|
))) {
|
||||||
onceErrorsReported.add(diagnosticFactory)
|
onceErrorsReported.add(diagnosticFactory)
|
||||||
trace.report(diagnosticFactory.on(klass, delegate, overridden))
|
trace.report(diagnosticFactory.on(klass, delegate, overridden))
|
||||||
}
|
}
|
||||||
@@ -214,8 +222,7 @@ class OverrideResolver(
|
|||||||
val canHaveAbstractMembers = classCanHaveAbstractFakeOverride(classDescriptor)
|
val canHaveAbstractMembers = classCanHaveAbstractFakeOverride(classDescriptor)
|
||||||
if (abstractInBaseClassNoImpl.isNotEmpty() && !canHaveAbstractMembers) {
|
if (abstractInBaseClassNoImpl.isNotEmpty() && !canHaveAbstractMembers) {
|
||||||
trace.report(ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractInBaseClassNoImpl.first()))
|
trace.report(ABSTRACT_CLASS_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractInBaseClassNoImpl.first()))
|
||||||
}
|
} else if (abstractNoImpl.isNotEmpty() && !canHaveAbstractMembers) {
|
||||||
else if (abstractNoImpl.isNotEmpty() && !canHaveAbstractMembers) {
|
|
||||||
trace.report(ABSTRACT_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractNoImpl.first()))
|
trace.report(ABSTRACT_MEMBER_NOT_IMPLEMENTED.on(klass, klass, abstractNoImpl.first()))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -223,8 +230,7 @@ class OverrideResolver(
|
|||||||
multipleImplementations.removeAll(conflictingReturnTypes)
|
multipleImplementations.removeAll(conflictingReturnTypes)
|
||||||
if (!conflictingInterfaceMembers.isEmpty()) {
|
if (!conflictingInterfaceMembers.isEmpty()) {
|
||||||
trace.report(MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED.on(klass, klass, conflictingInterfaceMembers.iterator().next()))
|
trace.report(MANY_INTERFACES_MEMBER_NOT_IMPLEMENTED.on(klass, klass, conflictingInterfaceMembers.iterator().next()))
|
||||||
}
|
} else if (!multipleImplementations.isEmpty()) {
|
||||||
else if (!multipleImplementations.isEmpty()) {
|
|
||||||
trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(klass, klass, multipleImplementations.iterator().next()))
|
trace.report(MANY_IMPL_MEMBER_NOT_IMPLEMENTED.on(klass, klass, multipleImplementations.iterator().next()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,8 +252,7 @@ class OverrideResolver(
|
|||||||
if (declared.kind == CallableMemberDescriptor.Kind.SYNTHESIZED) {
|
if (declared.kind == CallableMemberDescriptor.Kind.SYNTHESIZED) {
|
||||||
if (DataClassDescriptorResolver.isComponentLike(declared.name)) {
|
if (DataClassDescriptorResolver.isComponentLike(declared.name)) {
|
||||||
checkOverrideForComponentFunction(declared)
|
checkOverrideForComponentFunction(declared)
|
||||||
}
|
} else if (declared.name == DataClassDescriptorResolver.COPY_METHOD_NAME) {
|
||||||
else if (declared.name == DataClassDescriptorResolver.COPY_METHOD_NAME) {
|
|
||||||
checkOverrideForCopyFunction(declared)
|
checkOverrideForCopyFunction(declared)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
@@ -257,7 +262,8 @@ class OverrideResolver(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val member = DescriptorToSourceUtils.descriptorToDeclaration(declared) as KtNamedDeclaration? ?: throw IllegalStateException("declared descriptor is not resolved to declaration: " + declared)
|
val member = DescriptorToSourceUtils.descriptorToDeclaration(declared) as KtNamedDeclaration?
|
||||||
|
?: throw IllegalStateException("declared descriptor is not resolved to declaration: " + declared)
|
||||||
|
|
||||||
val modifierList = member.modifierList
|
val modifierList = member.modifierList
|
||||||
val hasOverrideNode = modifierList != null && modifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD)
|
val hasOverrideNode = modifierList != null && modifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD)
|
||||||
@@ -288,8 +294,7 @@ class OverrideResolver(
|
|||||||
typeMismatchError = true
|
typeMismatchError = true
|
||||||
if (overridden.isVar) {
|
if (overridden.isVar) {
|
||||||
trace.report(VAR_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden))
|
trace.report(VAR_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
trace.report(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden))
|
trace.report(PROPERTY_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -302,7 +307,10 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun cannotOverrideInvisibleMember(overriding: CallableMemberDescriptor, invisibleOverridden: CallableMemberDescriptor) {
|
override fun cannotOverrideInvisibleMember(
|
||||||
|
overriding: CallableMemberDescriptor,
|
||||||
|
invisibleOverridden: CallableMemberDescriptor
|
||||||
|
) {
|
||||||
trace.report(CANNOT_OVERRIDE_INVISIBLE_MEMBER.on(member, declared, invisibleOverridden))
|
trace.report(CANNOT_OVERRIDE_INVISIBLE_MEMBER.on(member, declared, invisibleOverridden))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -310,8 +318,7 @@ class OverrideResolver(
|
|||||||
trace.report(NOTHING_TO_OVERRIDE.on(member, declared))
|
trace.report(NOTHING_TO_OVERRIDE.on(member, declared))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
} else if (!overriddenDescriptors.isEmpty() && !overridesBackwardCompatibilityHelper.overrideCanBeOmitted(declared)) {
|
||||||
else if (!overriddenDescriptors.isEmpty() && !overridesBackwardCompatibilityHelper.overrideCanBeOmitted(declared)) {
|
|
||||||
val overridden = overriddenDescriptors.iterator().next()
|
val overridden = overriddenDescriptors.iterator().next()
|
||||||
trace.report(VIRTUAL_MEMBER_HIDDEN.on(member, declared, overridden, overridden.containingDeclaration))
|
trace.report(VIRTUAL_MEMBER_HIDDEN.on(member, declared, overridden, overridden.containingDeclaration))
|
||||||
}
|
}
|
||||||
@@ -354,8 +361,7 @@ class OverrideResolver(
|
|||||||
val dataModifier = findDataModifierForDataClass(copyFunction.containingDeclaration)
|
val dataModifier = findDataModifierForDataClass(copyFunction.containingDeclaration)
|
||||||
if (languageVersionSettings.supportsFeature(LanguageFeature.ProhibitDataClassesOverridingCopy)) {
|
if (languageVersionSettings.supportsFeature(LanguageFeature.ProhibitDataClassesOverridingCopy)) {
|
||||||
trace.report(DATA_CLASS_OVERRIDE_DEFAULT_VALUES_ERROR.on(dataModifier, copyFunction, baseClassifier))
|
trace.report(DATA_CLASS_OVERRIDE_DEFAULT_VALUES_ERROR.on(dataModifier, copyFunction, baseClassifier))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
trace.report(DATA_CLASS_OVERRIDE_DEFAULT_VALUES_WARNING.on(dataModifier, copyFunction, baseClassifier))
|
trace.report(DATA_CLASS_OVERRIDE_DEFAULT_VALUES_WARNING.on(dataModifier, copyFunction, baseClassifier))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -397,15 +403,15 @@ class OverrideResolver(
|
|||||||
|
|
||||||
if (isDeclaration) {
|
if (isDeclaration) {
|
||||||
checkNameAndDefaultForDeclaredParameter(parameterFromSubclass, multipleDefaultsInSuper)
|
checkNameAndDefaultForDeclaredParameter(parameterFromSubclass, multipleDefaultsInSuper)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
checkNameAndDefaultForFakeOverrideParameter(declared, parameterFromSubclass, multipleDefaultsInSuper)
|
checkNameAndDefaultForFakeOverrideParameter(declared, parameterFromSubclass, multipleDefaultsInSuper)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkNameAndDefaultForDeclaredParameter(descriptor: ValueParameterDescriptor, multipleDefaultsInSuper: Boolean) {
|
private fun checkNameAndDefaultForDeclaredParameter(descriptor: ValueParameterDescriptor, multipleDefaultsInSuper: Boolean) {
|
||||||
val parameter = DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as? KtParameter ?: error("Declaration not found for parameter: " + descriptor)
|
val parameter = DescriptorToSourceUtils.descriptorToDeclaration(descriptor) as? KtParameter
|
||||||
|
?: error("Declaration not found for parameter: " + descriptor)
|
||||||
|
|
||||||
if (descriptor.declaresDefaultValue()) {
|
if (descriptor.declaresDefaultValue()) {
|
||||||
trace.report(DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE.on(parameter))
|
trace.report(DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE.on(parameter))
|
||||||
@@ -418,22 +424,25 @@ class OverrideResolver(
|
|||||||
for (parameterFromSuperclass in descriptor.overriddenDescriptors) {
|
for (parameterFromSuperclass in descriptor.overriddenDescriptors) {
|
||||||
if (shouldReportParameterNameOverrideWarning(descriptor, parameterFromSuperclass)) {
|
if (shouldReportParameterNameOverrideWarning(descriptor, parameterFromSuperclass)) {
|
||||||
|
|
||||||
trace.report(PARAMETER_NAME_CHANGED_ON_OVERRIDE.on(
|
trace.report(
|
||||||
|
PARAMETER_NAME_CHANGED_ON_OVERRIDE.on(
|
||||||
parameter,
|
parameter,
|
||||||
parameterFromSuperclass.containingDeclaration.containingDeclaration as ClassDescriptor,
|
parameterFromSuperclass.containingDeclaration.containingDeclaration as ClassDescriptor,
|
||||||
parameterFromSuperclass)
|
parameterFromSuperclass
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkNameAndDefaultForFakeOverrideParameter(
|
private fun checkNameAndDefaultForFakeOverrideParameter(
|
||||||
containingFunction: CallableMemberDescriptor,
|
containingFunction: CallableMemberDescriptor,
|
||||||
descriptor: ValueParameterDescriptor,
|
descriptor: ValueParameterDescriptor,
|
||||||
multipleDefaultsInSuper: Boolean
|
multipleDefaultsInSuper: Boolean
|
||||||
) {
|
) {
|
||||||
val containingClass = containingFunction.containingDeclaration
|
val containingClass = containingFunction.containingDeclaration
|
||||||
val classElement = DescriptorToSourceUtils.descriptorToDeclaration(containingClass) as KtClassOrObject? ?: error("Declaration not found for class: " + containingClass)
|
val classElement = DescriptorToSourceUtils.descriptorToDeclaration(containingClass) as KtClassOrObject?
|
||||||
|
?: error("Declaration not found for class: " + containingClass)
|
||||||
|
|
||||||
if (multipleDefaultsInSuper) {
|
if (multipleDefaultsInSuper) {
|
||||||
trace.report(MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE.on(classElement, descriptor))
|
trace.report(MULTIPLE_DEFAULTS_INHERITED_FROM_SUPERTYPES_WHEN_NO_EXPLICIT_OVERRIDE.on(classElement, descriptor))
|
||||||
@@ -441,10 +450,12 @@ class OverrideResolver(
|
|||||||
|
|
||||||
for (parameterFromSuperclass in descriptor.overriddenDescriptors) {
|
for (parameterFromSuperclass in descriptor.overriddenDescriptors) {
|
||||||
if (shouldReportParameterNameOverrideWarning(descriptor, parameterFromSuperclass)) {
|
if (shouldReportParameterNameOverrideWarning(descriptor, parameterFromSuperclass)) {
|
||||||
trace.report(DIFFERENT_NAMES_FOR_THE_SAME_PARAMETER_IN_SUPERTYPES.on(
|
trace.report(
|
||||||
|
DIFFERENT_NAMES_FOR_THE_SAME_PARAMETER_IN_SUPERTYPES.on(
|
||||||
classElement,
|
classElement,
|
||||||
containingFunction.overriddenDescriptors,
|
containingFunction.overriddenDescriptors,
|
||||||
parameterFromSuperclass.index + 1)
|
parameterFromSuperclass.index + 1
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -468,11 +479,24 @@ class OverrideResolver(
|
|||||||
for (descriptor in memberDescriptor.overriddenDescriptors) {
|
for (descriptor in memberDescriptor.overriddenDescriptors) {
|
||||||
val compare = Visibilities.compare(visibility, descriptor.visibility)
|
val compare = Visibilities.compare(visibility, descriptor.visibility)
|
||||||
if (compare == null) {
|
if (compare == null) {
|
||||||
trace.report(CANNOT_CHANGE_ACCESS_PRIVILEGE.on(declaration, descriptor.visibility, descriptor, descriptor.containingDeclaration))
|
trace.report(
|
||||||
|
CANNOT_CHANGE_ACCESS_PRIVILEGE.on(
|
||||||
|
declaration,
|
||||||
|
descriptor.visibility,
|
||||||
|
descriptor,
|
||||||
|
descriptor.containingDeclaration
|
||||||
|
)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
} else if (compare < 0) {
|
||||||
else if (compare < 0) {
|
trace.report(
|
||||||
trace.report(CANNOT_WEAKEN_ACCESS_PRIVILEGE.on(declaration, descriptor.visibility, descriptor, descriptor.containingDeclaration))
|
CANNOT_WEAKEN_ACCESS_PRIVILEGE.on(
|
||||||
|
declaration,
|
||||||
|
descriptor.visibility,
|
||||||
|
descriptor,
|
||||||
|
descriptor.containingDeclaration
|
||||||
|
)
|
||||||
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -481,8 +505,8 @@ class OverrideResolver(
|
|||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
fun resolveUnknownVisibilities(
|
fun resolveUnknownVisibilities(
|
||||||
descriptors: Collection<CallableMemberDescriptor>,
|
descriptors: Collection<CallableMemberDescriptor>,
|
||||||
trace: BindingTrace
|
trace: BindingTrace
|
||||||
) {
|
) {
|
||||||
for (descriptor in descriptors) {
|
for (descriptor in descriptors) {
|
||||||
OverridingUtil.resolveUnknownVisibilityForMember(descriptor, createCannotInferVisibilityReporter(trace))
|
OverridingUtil.resolveUnknownVisibilityForMember(descriptor, createCannotInferVisibilityReporter(trace))
|
||||||
@@ -515,9 +539,9 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkInheritedAndDelegatedSignatures(
|
private fun checkInheritedAndDelegatedSignatures(
|
||||||
classDescriptor: ClassDescriptor,
|
classDescriptor: ClassDescriptor,
|
||||||
inheritedReportStrategy: CheckInheritedSignaturesReportStrategy,
|
inheritedReportStrategy: CheckInheritedSignaturesReportStrategy,
|
||||||
overrideReportStrategyForDelegates: CheckOverrideReportStrategy?
|
overrideReportStrategyForDelegates: CheckOverrideReportStrategy?
|
||||||
) {
|
) {
|
||||||
for (member in DescriptorUtils.getAllDescriptors(classDescriptor.defaultType.memberScope)) {
|
for (member in DescriptorUtils.getAllDescriptors(classDescriptor.defaultType.memberScope)) {
|
||||||
if (member is CallableMemberDescriptor) {
|
if (member is CallableMemberDescriptor) {
|
||||||
@@ -527,9 +551,9 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkInheritedAndDelegatedSignatures(
|
private fun checkInheritedAndDelegatedSignatures(
|
||||||
descriptor: CallableMemberDescriptor,
|
descriptor: CallableMemberDescriptor,
|
||||||
reportingStrategy: CheckInheritedSignaturesReportStrategy,
|
reportingStrategy: CheckInheritedSignaturesReportStrategy,
|
||||||
overrideReportStrategyForDelegates: CheckOverrideReportStrategy?
|
overrideReportStrategyForDelegates: CheckOverrideReportStrategy?
|
||||||
) {
|
) {
|
||||||
val kind = descriptor.kind
|
val kind = descriptor.kind
|
||||||
if (kind != FAKE_OVERRIDE && kind != DELEGATION) return
|
if (kind != FAKE_OVERRIDE && kind != DELEGATION) return
|
||||||
@@ -545,9 +569,11 @@ class OverrideResolver(
|
|||||||
|
|
||||||
val allOverriddenDeclarations = ContainerUtil.flatten(overriddenDeclarationsByDirectParent.values)
|
val allOverriddenDeclarations = ContainerUtil.flatten(overriddenDeclarationsByDirectParent.values)
|
||||||
val allFilteredOverriddenDeclarations = OverridingUtil.filterOutOverridden(
|
val allFilteredOverriddenDeclarations = OverridingUtil.filterOutOverridden(
|
||||||
Sets.newLinkedHashSet(allOverriddenDeclarations))
|
Sets.newLinkedHashSet(allOverriddenDeclarations)
|
||||||
|
)
|
||||||
|
|
||||||
val relevantDirectlyOverridden = getRelevantDirectlyOverridden(overriddenDeclarationsByDirectParent, allFilteredOverriddenDeclarations)
|
val relevantDirectlyOverridden =
|
||||||
|
getRelevantDirectlyOverridden(overriddenDeclarationsByDirectParent, allFilteredOverriddenDeclarations)
|
||||||
|
|
||||||
checkInheritedDescriptorsGroup(descriptor, relevantDirectlyOverridden, reportingStrategy)
|
checkInheritedDescriptorsGroup(descriptor, relevantDirectlyOverridden, reportingStrategy)
|
||||||
|
|
||||||
@@ -560,8 +586,8 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val (concreteOverridden, abstractOverridden) = relevantDirectlyOverridden
|
val (concreteOverridden, abstractOverridden) = relevantDirectlyOverridden
|
||||||
.filter { !isOrOverridesSynthesized(it) }
|
.filter { !isOrOverridesSynthesized(it) }
|
||||||
.partition { it.modality != Modality.ABSTRACT }
|
.partition { it.modality != Modality.ABSTRACT }
|
||||||
|
|
||||||
val numImplementations = concreteOverridden.size
|
val numImplementations = concreteOverridden.size
|
||||||
|
|
||||||
@@ -587,8 +613,8 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkMissingOverridesByJava8Restrictions(
|
private fun checkMissingOverridesByJava8Restrictions(
|
||||||
relevantDirectlyOverridden: Set<CallableMemberDescriptor>,
|
relevantDirectlyOverridden: Set<CallableMemberDescriptor>,
|
||||||
reportingStrategy: CheckInheritedSignaturesReportStrategy
|
reportingStrategy: CheckInheritedSignaturesReportStrategy
|
||||||
) {
|
) {
|
||||||
// Java 8:
|
// Java 8:
|
||||||
// -- class should implement an abstract member of a super-class,
|
// -- class should implement an abstract member of a super-class,
|
||||||
@@ -608,8 +634,7 @@ class OverrideResolver(
|
|||||||
if (overridden.modality === Modality.ABSTRACT) {
|
if (overridden.modality === Modality.ABSTRACT) {
|
||||||
overridesAbstractInBaseClass = overridden
|
overridesAbstractInBaseClass = overridden
|
||||||
}
|
}
|
||||||
}
|
} else if (containingDeclaration.kind == ClassKind.INTERFACE) {
|
||||||
else if (containingDeclaration.kind == ClassKind.INTERFACE) {
|
|
||||||
overriddenInterfaceMembers.add(overridden)
|
overriddenInterfaceMembers.add(overridden)
|
||||||
if (overridden.modality !== Modality.ABSTRACT) {
|
if (overridden.modality !== Modality.ABSTRACT) {
|
||||||
overridesNonAbstractInterfaceMember = true
|
overridesNonAbstractInterfaceMember = true
|
||||||
@@ -629,14 +654,14 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun collectAbstractMethodsWithMoreSpecificReturnType(
|
private fun collectAbstractMethodsWithMoreSpecificReturnType(
|
||||||
abstractOverridden: List<CallableMemberDescriptor>,
|
abstractOverridden: List<CallableMemberDescriptor>,
|
||||||
implementation: CallableMemberDescriptor
|
implementation: CallableMemberDescriptor
|
||||||
): List<CallableMemberDescriptor> =
|
): List<CallableMemberDescriptor> =
|
||||||
abstractOverridden.filter { abstractMember -> !isReturnTypeOkForOverride(abstractMember, implementation) }
|
abstractOverridden.filter { abstractMember -> !isReturnTypeOkForOverride(abstractMember, implementation) }
|
||||||
|
|
||||||
private fun getRelevantDirectlyOverridden(
|
private fun getRelevantDirectlyOverridden(
|
||||||
overriddenByParent: MutableMap<CallableMemberDescriptor, Set<CallableMemberDescriptor>>,
|
overriddenByParent: MutableMap<CallableMemberDescriptor, Set<CallableMemberDescriptor>>,
|
||||||
allFilteredOverriddenDeclarations: Set<CallableMemberDescriptor>
|
allFilteredOverriddenDeclarations: Set<CallableMemberDescriptor>
|
||||||
): Set<CallableMemberDescriptor> {
|
): Set<CallableMemberDescriptor> {
|
||||||
/* Let the following class hierarchy is declared:
|
/* Let the following class hierarchy is declared:
|
||||||
|
|
||||||
@@ -678,9 +703,9 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isRelevant(
|
private fun isRelevant(
|
||||||
declarationSet: Set<CallableMemberDescriptor>,
|
declarationSet: Set<CallableMemberDescriptor>,
|
||||||
allDeclarationSets: Collection<Set<CallableMemberDescriptor>>,
|
allDeclarationSets: Collection<Set<CallableMemberDescriptor>>,
|
||||||
allFilteredOverriddenDeclarations: Set<CallableMemberDescriptor>
|
allFilteredOverriddenDeclarations: Set<CallableMemberDescriptor>
|
||||||
): Boolean {
|
): Boolean {
|
||||||
for (otherSet in allDeclarationSets) {
|
for (otherSet in allDeclarationSets) {
|
||||||
if (otherSet === declarationSet) continue
|
if (otherSet === declarationSet) continue
|
||||||
@@ -691,7 +716,7 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun collectOverriddenDeclarations(
|
private fun collectOverriddenDeclarations(
|
||||||
directOverriddenDescriptors: Collection<CallableMemberDescriptor>
|
directOverriddenDescriptors: Collection<CallableMemberDescriptor>
|
||||||
): MutableMap<CallableMemberDescriptor, Set<CallableMemberDescriptor>> {
|
): MutableMap<CallableMemberDescriptor, Set<CallableMemberDescriptor>> {
|
||||||
val overriddenDeclarationsByDirectParent = Maps.newLinkedHashMap<CallableMemberDescriptor, Set<CallableMemberDescriptor>>()
|
val overriddenDeclarationsByDirectParent = Maps.newLinkedHashMap<CallableMemberDescriptor, Set<CallableMemberDescriptor>>()
|
||||||
for (descriptor in directOverriddenDescriptors) {
|
for (descriptor in directOverriddenDescriptors) {
|
||||||
@@ -703,9 +728,9 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkInheritedDescriptorsGroup(
|
private fun checkInheritedDescriptorsGroup(
|
||||||
descriptor: CallableMemberDescriptor,
|
descriptor: CallableMemberDescriptor,
|
||||||
overriddenDescriptors: Collection<CallableMemberDescriptor>,
|
overriddenDescriptors: Collection<CallableMemberDescriptor>,
|
||||||
reportingStrategy: CheckInheritedSignaturesReportStrategy
|
reportingStrategy: CheckInheritedSignaturesReportStrategy
|
||||||
) {
|
) {
|
||||||
if (overriddenDescriptors.size <= 1) return
|
if (overriddenDescriptors.size <= 1) return
|
||||||
|
|
||||||
@@ -713,12 +738,12 @@ class OverrideResolver(
|
|||||||
|
|
||||||
for (overriddenDescriptor in overriddenDescriptors) {
|
for (overriddenDescriptor in overriddenDescriptors) {
|
||||||
if (propertyDescriptor != null) {
|
if (propertyDescriptor != null) {
|
||||||
val overriddenPropertyDescriptor = overriddenDescriptor.assertedCast<PropertyDescriptor> { "$overriddenDescriptor is not a property" }
|
val overriddenPropertyDescriptor =
|
||||||
|
overriddenDescriptor.assertedCast<PropertyDescriptor> { "$overriddenDescriptor is not a property" }
|
||||||
if (!isPropertyTypeOkForOverride(overriddenPropertyDescriptor, propertyDescriptor)) {
|
if (!isPropertyTypeOkForOverride(overriddenPropertyDescriptor, propertyDescriptor)) {
|
||||||
reportingStrategy.typeMismatchOnInheritance(propertyDescriptor, overriddenPropertyDescriptor)
|
reportingStrategy.typeMismatchOnInheritance(propertyDescriptor, overriddenPropertyDescriptor)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (!isReturnTypeOkForOverride(overriddenDescriptor, descriptor)) {
|
if (!isReturnTypeOkForOverride(overriddenDescriptor, descriptor)) {
|
||||||
reportingStrategy.typeMismatchOnInheritance(descriptor, overriddenDescriptor)
|
reportingStrategy.typeMismatchOnInheritance(descriptor, overriddenDescriptor)
|
||||||
}
|
}
|
||||||
@@ -727,8 +752,8 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkOverridesForMemberMarkedOverride(
|
private fun checkOverridesForMemberMarkedOverride(
|
||||||
declared: CallableMemberDescriptor,
|
declared: CallableMemberDescriptor,
|
||||||
reportError: CheckOverrideReportForDeclaredMemberStrategy
|
reportError: CheckOverrideReportForDeclaredMemberStrategy
|
||||||
) {
|
) {
|
||||||
val overriddenDescriptors = declared.overriddenDescriptors
|
val overriddenDescriptors = declared.overriddenDescriptors
|
||||||
|
|
||||||
@@ -743,17 +768,16 @@ class OverrideResolver(
|
|||||||
val invisibleOverriddenDescriptor = findInvisibleOverriddenDescriptor(declared, declaringClass)
|
val invisibleOverriddenDescriptor = findInvisibleOverriddenDescriptor(declared, declaringClass)
|
||||||
if (invisibleOverriddenDescriptor != null) {
|
if (invisibleOverriddenDescriptor != null) {
|
||||||
reportError.cannotOverrideInvisibleMember(declared, invisibleOverriddenDescriptor)
|
reportError.cannotOverrideInvisibleMember(declared, invisibleOverriddenDescriptor)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
reportError.nothingToOverride(declared)
|
reportError.nothingToOverride(declared)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkOverridesForMember(
|
private fun checkOverridesForMember(
|
||||||
memberDescriptor: CallableMemberDescriptor,
|
memberDescriptor: CallableMemberDescriptor,
|
||||||
overriddenDescriptors: Collection<CallableMemberDescriptor>,
|
overriddenDescriptors: Collection<CallableMemberDescriptor>,
|
||||||
reportError: CheckOverrideReportStrategy
|
reportError: CheckOverrideReportStrategy
|
||||||
) {
|
) {
|
||||||
val propertyMemberDescriptor = if (memberDescriptor is PropertyDescriptor) memberDescriptor else null
|
val propertyMemberDescriptor = if (memberDescriptor is PropertyDescriptor) memberDescriptor else null
|
||||||
|
|
||||||
@@ -769,8 +793,7 @@ class OverrideResolver(
|
|||||||
if (!isPropertyTypeOkForOverride(overriddenProperty, propertyMemberDescriptor)) {
|
if (!isPropertyTypeOkForOverride(overriddenProperty, propertyMemberDescriptor)) {
|
||||||
reportError.propertyTypeMismatchOnOverride(propertyMemberDescriptor, overriddenProperty)
|
reportError.propertyTypeMismatchOnOverride(propertyMemberDescriptor, overriddenProperty)
|
||||||
}
|
}
|
||||||
}
|
} else if (!isReturnTypeOkForOverride(overridden, memberDescriptor)) {
|
||||||
else if (!isReturnTypeOkForOverride(overridden, memberDescriptor)) {
|
|
||||||
reportError.returnTypeMismatchOnOverride(memberDescriptor, overridden)
|
reportError.returnTypeMismatchOnOverride(memberDescriptor, overridden)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -781,8 +804,8 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isReturnTypeOkForOverride(
|
private fun isReturnTypeOkForOverride(
|
||||||
superDescriptor: CallableDescriptor,
|
superDescriptor: CallableDescriptor,
|
||||||
subDescriptor: CallableDescriptor
|
subDescriptor: CallableDescriptor
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor) ?: return false
|
val typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor) ?: return false
|
||||||
|
|
||||||
@@ -796,8 +819,8 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun prepareTypeSubstitutor(
|
private fun prepareTypeSubstitutor(
|
||||||
superDescriptor: CallableDescriptor,
|
superDescriptor: CallableDescriptor,
|
||||||
subDescriptor: CallableDescriptor
|
subDescriptor: CallableDescriptor
|
||||||
): TypeSubstitutor? {
|
): TypeSubstitutor? {
|
||||||
val superTypeParameters = superDescriptor.typeParameters
|
val superTypeParameters = superDescriptor.typeParameters
|
||||||
val subTypeParameters = subDescriptor.typeParameters
|
val subTypeParameters = subDescriptor.typeParameters
|
||||||
@@ -812,8 +835,8 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isPropertyTypeOkForOverride(
|
private fun isPropertyTypeOkForOverride(
|
||||||
superDescriptor: PropertyDescriptor,
|
superDescriptor: PropertyDescriptor,
|
||||||
subDescriptor: PropertyDescriptor
|
subDescriptor: PropertyDescriptor
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor) ?: return false
|
val typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor) ?: return false
|
||||||
|
|
||||||
@@ -821,8 +844,7 @@ class OverrideResolver(
|
|||||||
|
|
||||||
return if (superDescriptor.isVar) {
|
return if (superDescriptor.isVar) {
|
||||||
KotlinTypeChecker.DEFAULT.equalTypes(subDescriptor.type, substitutedSuperReturnType)
|
KotlinTypeChecker.DEFAULT.equalTypes(subDescriptor.type, substitutedSuperReturnType)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
KotlinTypeChecker.DEFAULT.isSubtypeOf(subDescriptor.type, substitutedSuperReturnType)
|
KotlinTypeChecker.DEFAULT.isSubtypeOf(subDescriptor.type, substitutedSuperReturnType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -840,8 +862,8 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun findInvisibleOverriddenDescriptor(
|
private fun findInvisibleOverriddenDescriptor(
|
||||||
declared: CallableMemberDescriptor,
|
declared: CallableMemberDescriptor,
|
||||||
declaringClass: ClassDescriptor
|
declaringClass: ClassDescriptor
|
||||||
): CallableMemberDescriptor? {
|
): CallableMemberDescriptor? {
|
||||||
for (supertype in declaringClass.typeConstructor.supertypes) {
|
for (supertype in declaringClass.typeConstructor.supertypes) {
|
||||||
val all = Sets.newLinkedHashSet<CallableMemberDescriptor>()
|
val all = Sets.newLinkedHashSet<CallableMemberDescriptor>()
|
||||||
@@ -850,8 +872,10 @@ class OverrideResolver(
|
|||||||
for (fromSuper in all) {
|
for (fromSuper in all) {
|
||||||
if (OverridingUtil.DEFAULT.isOverridableBy(fromSuper, declared, null).result == OVERRIDABLE) {
|
if (OverridingUtil.DEFAULT.isOverridableBy(fromSuper, declared, null).result == OVERRIDABLE) {
|
||||||
if (OverridingUtil.isVisibleForOverride(declared, fromSuper)) {
|
if (OverridingUtil.isVisibleForOverride(declared, fromSuper)) {
|
||||||
throw IllegalStateException("Descriptor " + fromSuper + " is overridable by " + declared +
|
throw IllegalStateException(
|
||||||
" and visible but does not appear in its getOverriddenDescriptors()")
|
"Descriptor " + fromSuper + " is overridable by " + declared +
|
||||||
|
" and visible but does not appear in its getOverriddenDescriptors()"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
return fromSuper
|
return fromSuper
|
||||||
}
|
}
|
||||||
@@ -861,12 +885,12 @@ class OverrideResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun shouldReportParameterNameOverrideWarning(
|
fun shouldReportParameterNameOverrideWarning(
|
||||||
parameterFromSubclass: ValueParameterDescriptor,
|
parameterFromSubclass: ValueParameterDescriptor,
|
||||||
parameterFromSuperclass: ValueParameterDescriptor
|
parameterFromSuperclass: ValueParameterDescriptor
|
||||||
): Boolean {
|
): Boolean {
|
||||||
return parameterFromSubclass.containingDeclaration.hasStableParameterNames() &&
|
return parameterFromSubclass.containingDeclaration.hasStableParameterNames() &&
|
||||||
parameterFromSuperclass.containingDeclaration.hasStableParameterNames() &&
|
parameterFromSuperclass.containingDeclaration.hasStableParameterNames() &&
|
||||||
parameterFromSuperclass.name != parameterFromSubclass.name
|
parameterFromSuperclass.name != parameterFromSubclass.name
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkPropertyKind(descriptor: CallableMemberDescriptor, isVar: Boolean): Boolean {
|
private fun checkPropertyKind(descriptor: CallableMemberDescriptor, isVar: Boolean): Boolean {
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ interface TypeBinding<out P : PsiElement> : TypeHolder<TypeBinding<P>> {
|
|||||||
override val arguments: List<TypeArgumentBinding<P>?>
|
override val arguments: List<TypeArgumentBinding<P>?>
|
||||||
}
|
}
|
||||||
|
|
||||||
interface TypeArgumentBinding<out P: PsiElement> : TypeHolderArgument<TypeBinding<P>>
|
interface TypeArgumentBinding<out P : PsiElement> : TypeHolderArgument<TypeBinding<P>>
|
||||||
|
|
||||||
fun KtTypeReference.createTypeBinding(trace: BindingContext): TypeBinding<KtTypeElement>? {
|
fun KtTypeReference.createTypeBinding(trace: BindingContext): TypeBinding<KtTypeElement>? {
|
||||||
val type = trace[BindingContext.TYPE, this]
|
val type = trace[BindingContext.TYPE, this]
|
||||||
@@ -51,7 +51,7 @@ private fun createTypeBindingFromPsi(trace: BindingContext, psiElement: KtTypeEl
|
|||||||
ExplicitTypeBinding(trace, psiElement, type)
|
ExplicitTypeBinding(trace, psiElement, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KtCallableDeclaration.createTypeBindingForReturnType(trace: BindingContext): TypeBinding<PsiElement>? {
|
fun KtCallableDeclaration.createTypeBindingForReturnType(trace: BindingContext): TypeBinding<PsiElement>? {
|
||||||
val jetTypeReference = typeReference
|
val jetTypeReference = typeReference
|
||||||
if (jetTypeReference != null) return jetTypeReference.createTypeBinding(trace)
|
if (jetTypeReference != null) return jetTypeReference.createTypeBinding(trace)
|
||||||
|
|
||||||
@@ -61,16 +61,16 @@ fun KtCallableDeclaration.createTypeBindingForReturnType(trace: BindingContext):
|
|||||||
return descriptor.returnType?.let { NoTypeElementBinding(trace, this, it) }
|
return descriptor.returnType?.let { NoTypeElementBinding(trace, this, it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TypeArgumentBindingImpl<out P: PsiElement>(
|
private class TypeArgumentBindingImpl<out P : PsiElement>(
|
||||||
override val projection: TypeProjection,
|
override val projection: TypeProjection,
|
||||||
override val typeParameter: TypeParameterDescriptor?,
|
override val typeParameter: TypeParameterDescriptor?,
|
||||||
override val holder: TypeBinding<P>
|
override val holder: TypeBinding<P>
|
||||||
) : TypeArgumentBinding<P>
|
) : TypeArgumentBinding<P>
|
||||||
|
|
||||||
private class ExplicitTypeBinding(
|
private class ExplicitTypeBinding(
|
||||||
private val trace: BindingContext,
|
private val trace: BindingContext,
|
||||||
override val psiElement: KtTypeElement,
|
override val psiElement: KtTypeElement,
|
||||||
override val type: KotlinType
|
override val type: KotlinType
|
||||||
) : TypeBinding<KtTypeElement> {
|
) : TypeBinding<KtTypeElement> {
|
||||||
override val isInAbbreviation: Boolean get() = false
|
override val isInAbbreviation: Boolean get() = false
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ private class ExplicitTypeBinding(
|
|||||||
assert(type.getAbbreviatedType() == null) { "Non-abbreviated type expected: $type" }
|
assert(type.getAbbreviatedType() == null) { "Non-abbreviated type expected: $type" }
|
||||||
val isErrorBinding = run {
|
val isErrorBinding = run {
|
||||||
val sizeIsEqual = psiTypeArguments.size == type.arguments.size
|
val sizeIsEqual = psiTypeArguments.size == type.arguments.size
|
||||||
&& psiTypeArguments.size == type.constructor.parameters.size
|
&& psiTypeArguments.size == type.constructor.parameters.size
|
||||||
type.isError || !sizeIsEqual
|
type.isError || !sizeIsEqual
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,59 +93,57 @@ private class ExplicitTypeBinding(
|
|||||||
val nextJetType = trace[BindingContext.TYPE, jetTypeReference] ?: return@map null
|
val nextJetType = trace[BindingContext.TYPE, jetTypeReference] ?: return@map null
|
||||||
|
|
||||||
return@map TypeArgumentBindingImpl(
|
return@map TypeArgumentBindingImpl(
|
||||||
TypeProjectionImpl(nextJetType),
|
TypeProjectionImpl(nextJetType),
|
||||||
null,
|
null,
|
||||||
createTypeBindingFromPsi(trace, jetTypeElement, nextJetType)
|
createTypeBindingFromPsi(trace, jetTypeElement, nextJetType)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val typeProjection = type.arguments[index]
|
val typeProjection = type.arguments[index]
|
||||||
return@map TypeArgumentBindingImpl(
|
return@map TypeArgumentBindingImpl(
|
||||||
typeProjection,
|
typeProjection,
|
||||||
type.constructor.parameters[index],
|
type.constructor.parameters[index],
|
||||||
createTypeBindingFromPsi(trace, jetTypeElement, typeProjection.type)
|
createTypeBindingFromPsi(trace, jetTypeElement, typeProjection.type)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class AbbreviatedTypeBinding(
|
private class AbbreviatedTypeBinding(
|
||||||
override val type: KotlinType,
|
override val type: KotlinType,
|
||||||
override val psiElement: KtTypeElement
|
override val psiElement: KtTypeElement
|
||||||
): TypeBinding<KtTypeElement> {
|
) : TypeBinding<KtTypeElement> {
|
||||||
override val isInAbbreviation: Boolean get() = true
|
override val isInAbbreviation: Boolean get() = true
|
||||||
|
|
||||||
override val arguments: List<TypeArgumentBinding<KtTypeElement>?>
|
override val arguments: List<TypeArgumentBinding<KtTypeElement>?>
|
||||||
get() = createTypeArgumentBindingsWithSinglePsiElement(type) {
|
get() = createTypeArgumentBindingsWithSinglePsiElement(type) { argumentType ->
|
||||||
argumentType ->
|
|
||||||
AbbreviatedTypeBinding(argumentType, psiElement)
|
AbbreviatedTypeBinding(argumentType, psiElement)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class NoTypeElementBinding<out P : PsiElement>(
|
private class NoTypeElementBinding<out P : PsiElement>(
|
||||||
private val trace: BindingContext,
|
private val trace: BindingContext,
|
||||||
override val psiElement: P,
|
override val psiElement: P,
|
||||||
override val type: KotlinType
|
override val type: KotlinType
|
||||||
): TypeBinding<P> {
|
) : TypeBinding<P> {
|
||||||
override val isInAbbreviation: Boolean get() = false
|
override val isInAbbreviation: Boolean get() = false
|
||||||
|
|
||||||
override val arguments: List<TypeArgumentBinding<P>?>
|
override val arguments: List<TypeArgumentBinding<P>?>
|
||||||
get() = createTypeArgumentBindingsWithSinglePsiElement(type) {
|
get() = createTypeArgumentBindingsWithSinglePsiElement(type) { argumentType ->
|
||||||
argumentType ->
|
|
||||||
NoTypeElementBinding(trace, psiElement, argumentType)
|
NoTypeElementBinding(trace, psiElement, argumentType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun <P : PsiElement> createTypeArgumentBindingsWithSinglePsiElement(
|
internal fun <P : PsiElement> createTypeArgumentBindingsWithSinglePsiElement(
|
||||||
type: KotlinType,
|
type: KotlinType,
|
||||||
createBinding: (KotlinType) -> TypeBinding<P>
|
createBinding: (KotlinType) -> TypeBinding<P>
|
||||||
) : List<TypeArgumentBinding<P>> {
|
): List<TypeArgumentBinding<P>> {
|
||||||
val isErrorBinding = type.isError || type.constructor.parameters.size != type.arguments.size
|
val isErrorBinding = type.isError || type.constructor.parameters.size != type.arguments.size
|
||||||
return type.arguments.mapIndexed { index, typeProjection ->
|
return type.arguments.mapIndexed { index, typeProjection ->
|
||||||
TypeArgumentBindingImpl(
|
TypeArgumentBindingImpl(
|
||||||
typeProjection,
|
typeProjection,
|
||||||
if (isErrorBinding) null else type.constructor.parameters[index],
|
if (isErrorBinding) null else type.constructor.parameters[index],
|
||||||
createBinding(typeProjection.type)
|
createBinding(typeProjection.type)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,11 +21,11 @@ import org.jetbrains.kotlin.psi.KtPropertyAccessor
|
|||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
class VariableAsPropertyInfo(
|
class VariableAsPropertyInfo(
|
||||||
val propertyGetter: KtPropertyAccessor?,
|
val propertyGetter: KtPropertyAccessor?,
|
||||||
val propertySetter: KtPropertyAccessor?,
|
val propertySetter: KtPropertyAccessor?,
|
||||||
val variableType: KotlinType?,
|
val variableType: KotlinType?,
|
||||||
val hasBody: Boolean,
|
val hasBody: Boolean,
|
||||||
val hasDelegate: Boolean
|
val hasDelegate: Boolean
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
fun createFromDestructuringDeclarationEntry(type: KotlinType): VariableAsPropertyInfo {
|
fun createFromDestructuringDeclarationEntry(type: KotlinType): VariableAsPropertyInfo {
|
||||||
|
|||||||
+1
-1
@@ -114,7 +114,7 @@ class VariableTypeAndInitializerResolver(
|
|||||||
if (!variable.hasInitializer() || variable.isVar) return
|
if (!variable.hasInitializer() || variable.isVar) return
|
||||||
variableDescriptor.setCompileTimeInitializer(
|
variableDescriptor.setCompileTimeInitializer(
|
||||||
storageManager.createRecursionTolerantNullableLazyValue(
|
storageManager.createRecursionTolerantNullableLazyValue(
|
||||||
computeInitializer@{
|
computeInitializer@ {
|
||||||
if (!DescriptorUtils.shouldRecordInitializerForProperty(
|
if (!DescriptorUtils.shouldRecordInitializerForProperty(
|
||||||
variableDescriptor,
|
variableDescriptor,
|
||||||
variableType
|
variableType
|
||||||
|
|||||||
@@ -57,19 +57,19 @@ import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class CallCompleter(
|
class CallCompleter(
|
||||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||||
private val candidateResolver: CandidateResolver,
|
private val candidateResolver: CandidateResolver,
|
||||||
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
||||||
private val callCheckers: Iterable<CallChecker>,
|
private val callCheckers: Iterable<CallChecker>,
|
||||||
private val builtIns: KotlinBuiltIns,
|
private val builtIns: KotlinBuiltIns,
|
||||||
private val languageVersionSettings: LanguageVersionSettings,
|
private val languageVersionSettings: LanguageVersionSettings,
|
||||||
private val deprecationResolver: DeprecationResolver,
|
private val deprecationResolver: DeprecationResolver,
|
||||||
private val effectSystem: EffectSystem
|
private val effectSystem: EffectSystem
|
||||||
) {
|
) {
|
||||||
fun <D : CallableDescriptor> completeCall(
|
fun <D : CallableDescriptor> completeCall(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
results: OverloadResolutionResultsImpl<D>,
|
results: OverloadResolutionResultsImpl<D>,
|
||||||
tracing: TracingStrategy
|
tracing: TracingStrategy
|
||||||
): OverloadResolutionResultsImpl<D> {
|
): OverloadResolutionResultsImpl<D> {
|
||||||
|
|
||||||
val resolvedCall = if (results.isSingleResult) results.resultingCall else null
|
val resolvedCall = if (results.isSingleResult) results.resultingCall else null
|
||||||
@@ -87,8 +87,8 @@ class CallCompleter(
|
|||||||
else
|
else
|
||||||
resolvedCall.call.calleeExpression
|
resolvedCall.call.calleeExpression
|
||||||
val reportOn =
|
val reportOn =
|
||||||
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
|
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
|
||||||
else resolvedCall.call.callElement
|
else resolvedCall.call.callElement
|
||||||
|
|
||||||
val callCheckerContext = CallCheckerContext(context, languageVersionSettings, deprecationResolver)
|
val callCheckerContext = CallCheckerContext(context, languageVersionSettings, deprecationResolver)
|
||||||
for (callChecker in callCheckers) {
|
for (callChecker in callCheckers) {
|
||||||
@@ -107,30 +107,34 @@ class CallCompleter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> completeAllCandidates(
|
private fun <D : CallableDescriptor> completeAllCandidates(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
results: OverloadResolutionResultsImpl<D>
|
results: OverloadResolutionResultsImpl<D>
|
||||||
) {
|
) {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val candidates = (if (context.collectAllCandidates) {
|
val candidates = (if (context.collectAllCandidates) {
|
||||||
results.allCandidates!!
|
results.allCandidates!!
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
results.resultingCalls
|
results.resultingCalls
|
||||||
}) as Collection<MutableResolvedCall<D>>
|
}) as Collection<MutableResolvedCall<D>>
|
||||||
|
|
||||||
val temporaryBindingTrace = TemporaryBindingTrace.create(context.trace, "Trace to complete a candidate that is not a resulting call")
|
val temporaryBindingTrace =
|
||||||
candidates.filterNot { resolvedCall -> resolvedCall.isCompleted }.forEach {
|
TemporaryBindingTrace.create(context.trace, "Trace to complete a candidate that is not a resulting call")
|
||||||
resolvedCall ->
|
candidates.filterNot { resolvedCall -> resolvedCall.isCompleted }.forEach { resolvedCall ->
|
||||||
|
|
||||||
completeResolvedCallAndArguments(resolvedCall, results, context.replaceBindingTrace(temporaryBindingTrace), TracingStrategy.EMPTY)
|
completeResolvedCallAndArguments(
|
||||||
|
resolvedCall,
|
||||||
|
results,
|
||||||
|
context.replaceBindingTrace(temporaryBindingTrace),
|
||||||
|
TracingStrategy.EMPTY
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> completeResolvedCallAndArguments(
|
private fun <D : CallableDescriptor> completeResolvedCallAndArguments(
|
||||||
resolvedCall: MutableResolvedCall<D>?,
|
resolvedCall: MutableResolvedCall<D>?,
|
||||||
results: OverloadResolutionResultsImpl<D>,
|
results: OverloadResolutionResultsImpl<D>,
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
tracing: TracingStrategy
|
tracing: TracingStrategy
|
||||||
) {
|
) {
|
||||||
if (resolvedCall == null || resolvedCall.isCompleted || resolvedCall.constraintSystem == null) {
|
if (resolvedCall == null || resolvedCall.isCompleted || resolvedCall.constraintSystem == null) {
|
||||||
completeArguments(context, results)
|
completeArguments(context, results)
|
||||||
@@ -149,24 +153,23 @@ class CallCompleter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> MutableResolvedCall<D>.completeConstraintSystem(
|
private fun <D : CallableDescriptor> MutableResolvedCall<D>.completeConstraintSystem(
|
||||||
expectedType: KotlinType,
|
expectedType: KotlinType,
|
||||||
trace: BindingTrace
|
trace: BindingTrace
|
||||||
) {
|
) {
|
||||||
val returnType = candidateDescriptor.returnType
|
val returnType = candidateDescriptor.returnType
|
||||||
|
|
||||||
val expectedReturnType =
|
val expectedReturnType =
|
||||||
if (call.isCallableReference()) {
|
if (call.isCallableReference()) {
|
||||||
// TODO: compute generic type argument for R in the kotlin.Function<R> supertype (KT-12963)
|
// TODO: compute generic type argument for R in the kotlin.Function<R> supertype (KT-12963)
|
||||||
if (!TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) expectedType.getReturnTypeFromFunctionType()
|
if (!TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) expectedType.getReturnTypeFromFunctionType()
|
||||||
else TypeUtils.NO_EXPECTED_TYPE
|
else TypeUtils.NO_EXPECTED_TYPE
|
||||||
}
|
} else expectedType
|
||||||
else expectedType
|
|
||||||
|
|
||||||
fun ConstraintSystem.Builder.typeInSystem(type: KotlinType?): KotlinType? =
|
fun ConstraintSystem.Builder.typeInSystem(type: KotlinType?): KotlinType? =
|
||||||
type?.let {
|
type?.let {
|
||||||
val substitutor = typeVariableSubstitutors[call.toHandle()] ?: error("No substitutor for call: $call")
|
val substitutor = typeVariableSubstitutors[call.toHandle()] ?: error("No substitutor for call: $call")
|
||||||
substitutor.substitute(it, Variance.INVARIANT)
|
substitutor.substitute(it, Variance.INVARIANT)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateSystemIfNeeded(buildSystemWithAdditionalConstraints: (ConstraintSystem.Builder) -> ConstraintSystem?) {
|
fun updateSystemIfNeeded(buildSystemWithAdditionalConstraints: (ConstraintSystem.Builder) -> ConstraintSystem?) {
|
||||||
val system = buildSystemWithAdditionalConstraints(constraintSystem!!.toBuilder())
|
val system = buildSystemWithAdditionalConstraints(constraintSystem!!.toBuilder())
|
||||||
@@ -181,8 +184,7 @@ class CallCompleter(
|
|||||||
if (returnTypeInSystem != null) {
|
if (returnTypeInSystem != null) {
|
||||||
builder.addSubtypeConstraint(returnTypeInSystem, expectedReturnType, EXPECTED_TYPE_POSITION.position())
|
builder.addSubtypeConstraint(returnTypeInSystem, expectedReturnType, EXPECTED_TYPE_POSITION.position())
|
||||||
builder.build()
|
builder.build()
|
||||||
}
|
} else null
|
||||||
else null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,17 +208,21 @@ class CallCompleter(
|
|||||||
builder.addSubtypeConstraint(returnTypeInSystem, builtIns.unitType, EXPECTED_TYPE_POSITION.position())
|
builder.addSubtypeConstraint(returnTypeInSystem, builtIns.unitType, EXPECTED_TYPE_POSITION.position())
|
||||||
val system = builder.build()
|
val system = builder.build()
|
||||||
if (system.status.isSuccessful()) system else null
|
if (system.status.isSuccessful()) system else null
|
||||||
}
|
} else null
|
||||||
else null
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (call.isCallableReference() && !TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) {
|
if (call.isCallableReference() && !TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) {
|
||||||
updateSystemIfNeeded { builder ->
|
updateSystemIfNeeded { builder ->
|
||||||
candidateDescriptor.valueParameters.zip(expectedType.getValueParameterTypesFromFunctionType()).forEach { (parameter, argument) ->
|
candidateDescriptor.valueParameters.zip(expectedType.getValueParameterTypesFromFunctionType())
|
||||||
val valueParameterInSystem = builder.typeInSystem(parameter.type)
|
.forEach { (parameter, argument) ->
|
||||||
builder.addSubtypeConstraint(valueParameterInSystem, argument.type, VALUE_PARAMETER_POSITION.position(parameter.index))
|
val valueParameterInSystem = builder.typeInSystem(parameter.type)
|
||||||
}
|
builder.addSubtypeConstraint(
|
||||||
|
valueParameterInSystem,
|
||||||
|
argument.type,
|
||||||
|
VALUE_PARAMETER_POSITION.position(parameter.index)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
builder.build()
|
builder.build()
|
||||||
}
|
}
|
||||||
@@ -231,8 +237,8 @@ class CallCompleter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> MutableResolvedCall<D>.updateResolutionStatusFromConstraintSystem(
|
private fun <D : CallableDescriptor> MutableResolvedCall<D>.updateResolutionStatusFromConstraintSystem(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
tracing: TracingStrategy
|
tracing: TracingStrategy
|
||||||
) {
|
) {
|
||||||
val contextWithResolvedCall = CallCandidateResolutionContext.createForCallBeingAnalyzed(this, context, tracing)
|
val contextWithResolvedCall = CallCandidateResolutionContext.createForCallBeingAnalyzed(this, context, tracing)
|
||||||
val valueArgumentsCheckingResult = candidateResolver.checkAllValueArguments(contextWithResolvedCall, RESOLVE_FUNCTION_ARGUMENTS)
|
val valueArgumentsCheckingResult = candidateResolver.checkAllValueArguments(contextWithResolvedCall, RESOLVE_FUNCTION_ARGUMENTS)
|
||||||
@@ -248,8 +254,8 @@ class CallCompleter(
|
|||||||
val receiverType = extensionReceiver?.type
|
val receiverType = extensionReceiver?.type
|
||||||
|
|
||||||
val errorData = InferenceErrorData.create(
|
val errorData = InferenceErrorData.create(
|
||||||
candidateDescriptor, constraintSystem!!, valueArgumentsCheckingResult.argumentTypes,
|
candidateDescriptor, constraintSystem!!, valueArgumentsCheckingResult.argumentTypes,
|
||||||
receiverType, context.expectedType, context.call
|
receiverType, context.expectedType, context.call
|
||||||
)
|
)
|
||||||
tracing.typeInferenceFailed(context, errorData)
|
tracing.typeInferenceFailed(context, errorData)
|
||||||
|
|
||||||
@@ -257,8 +263,8 @@ class CallCompleter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> completeArguments(
|
private fun <D : CallableDescriptor> completeArguments(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
results: OverloadResolutionResultsImpl<D>
|
results: OverloadResolutionResultsImpl<D>
|
||||||
) {
|
) {
|
||||||
if (context.checkArguments != CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS) return
|
if (context.checkArguments != CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS) return
|
||||||
|
|
||||||
@@ -268,8 +274,7 @@ class CallCompleter(
|
|||||||
val resolvedCall = results.resultingCall
|
val resolvedCall = results.resultingCall
|
||||||
getArgumentMapping = { argument -> resolvedCall.getArgumentMapping(argument) }
|
getArgumentMapping = { argument -> resolvedCall.getArgumentMapping(argument) }
|
||||||
getDataFlowInfoForArgument = { argument -> resolvedCall.dataFlowInfoForArguments.getInfo(argument) }
|
getDataFlowInfoForArgument = { argument -> resolvedCall.dataFlowInfoForArguments.getInfo(argument) }
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
getArgumentMapping = { ArgumentUnmapped }
|
getArgumentMapping = { ArgumentUnmapped }
|
||||||
getDataFlowInfoForArgument = { context.dataFlowInfo }
|
getDataFlowInfoForArgument = { context.dataFlowInfo }
|
||||||
}
|
}
|
||||||
@@ -278,21 +283,22 @@ class CallCompleter(
|
|||||||
val argumentMapping = getArgumentMapping(valueArgument!!)
|
val argumentMapping = getArgumentMapping(valueArgument!!)
|
||||||
val (expectedType, callPosition) = when (argumentMapping) {
|
val (expectedType, callPosition) = when (argumentMapping) {
|
||||||
is ArgumentMatch -> Pair(
|
is ArgumentMatch -> Pair(
|
||||||
getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument, context),
|
getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument, context),
|
||||||
CallPosition.ValueArgumentPosition(results.resultingCall, argumentMapping.valueParameter, valueArgument))
|
CallPosition.ValueArgumentPosition(results.resultingCall, argumentMapping.valueParameter, valueArgument)
|
||||||
|
)
|
||||||
else -> Pair(TypeUtils.NO_EXPECTED_TYPE, CallPosition.Unknown)
|
else -> Pair(TypeUtils.NO_EXPECTED_TYPE, CallPosition.Unknown)
|
||||||
}
|
}
|
||||||
val newContext =
|
val newContext =
|
||||||
context.replaceDataFlowInfo(getDataFlowInfoForArgument(valueArgument))
|
context.replaceDataFlowInfo(getDataFlowInfoForArgument(valueArgument))
|
||||||
.replaceExpectedType(expectedType)
|
.replaceExpectedType(expectedType)
|
||||||
.replaceCallPosition(callPosition)
|
.replaceCallPosition(callPosition)
|
||||||
completeOneArgument(valueArgument, newContext)
|
completeOneArgument(valueArgument, newContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun completeOneArgument(
|
private fun completeOneArgument(
|
||||||
valueArgument: ValueArgument,
|
valueArgument: ValueArgument,
|
||||||
context: BasicCallResolutionContext
|
context: BasicCallResolutionContext
|
||||||
) {
|
) {
|
||||||
if (valueArgument.isExternal()) return
|
if (valueArgument.isExternal()) return
|
||||||
|
|
||||||
@@ -307,8 +313,7 @@ class CallCompleter(
|
|||||||
val resolvedCall = results.resultingCall
|
val resolvedCall = results.resultingCall
|
||||||
updatedType = if (resolvedCall.hasInferredReturnType()) {
|
updatedType = if (resolvedCall.hasInferredReturnType()) {
|
||||||
resolvedCall.makeNullableTypeIfSafeReceiver(resolvedCall.resultingDescriptor?.returnType, context)
|
resolvedCall.makeNullableTypeIfSafeReceiver(resolvedCall.resultingDescriptor?.returnType, context)
|
||||||
}
|
} else null
|
||||||
else null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For the cases like 'foo(1)' the type of '1' depends on expected type (it can be Int, Byte, etc.),
|
// For the cases like 'foo(1)' the type of '1' depends on expected type (it can be Int, Byte, etc.),
|
||||||
@@ -336,24 +341,24 @@ class CallCompleter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun completeCallForArgument(
|
private fun completeCallForArgument(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
context: BasicCallResolutionContext
|
context: BasicCallResolutionContext
|
||||||
): OverloadResolutionResultsImpl<*>? {
|
): OverloadResolutionResultsImpl<*>? {
|
||||||
val cachedData = getResolutionResultsCachedData(expression, context) ?: return null
|
val cachedData = getResolutionResultsCachedData(expression, context) ?: return null
|
||||||
val (cachedResolutionResults, cachedContext, tracing) = cachedData
|
val (cachedResolutionResults, cachedContext, tracing) = cachedData
|
||||||
|
|
||||||
val contextForArgument = cachedContext.replaceBindingTrace(context.trace)
|
val contextForArgument = cachedContext.replaceBindingTrace(context.trace)
|
||||||
.replaceExpectedType(context.expectedType).replaceCollectAllCandidates(false).replaceCallPosition(context.callPosition)
|
.replaceExpectedType(context.expectedType).replaceCollectAllCandidates(false).replaceCallPosition(context.callPosition)
|
||||||
|
|
||||||
return completeCall(contextForArgument, cachedResolutionResults, tracing)
|
return completeCall(contextForArgument, cachedResolutionResults, tracing)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateRecordedTypeForArgument(
|
private fun updateRecordedTypeForArgument(
|
||||||
updatedType: KotlinType?,
|
updatedType: KotlinType?,
|
||||||
recordedType: KotlinType?,
|
recordedType: KotlinType?,
|
||||||
argumentExpression: KtExpression,
|
argumentExpression: KtExpression,
|
||||||
statementFilter: StatementFilter,
|
statementFilter: StatementFilter,
|
||||||
trace: BindingTrace
|
trace: BindingTrace
|
||||||
): KotlinType? {
|
): KotlinType? {
|
||||||
//workaround for KT-8218
|
//workaround for KT-8218
|
||||||
if ((!ErrorUtils.containsErrorType(recordedType) && recordedType == updatedType) || updatedType == null) return updatedType
|
if ((!ErrorUtils.containsErrorType(recordedType) && recordedType == updatedType) || updatedType == null) return updatedType
|
||||||
|
|||||||
+122
-103
@@ -67,13 +67,13 @@ import org.jetbrains.kotlin.types.expressions.typeInfoFactory.noTypeInfo
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class CallExpressionResolver(
|
class CallExpressionResolver(
|
||||||
private val callResolver: CallResolver,
|
private val callResolver: CallResolver,
|
||||||
private val constantExpressionEvaluator: ConstantExpressionEvaluator,
|
private val constantExpressionEvaluator: ConstantExpressionEvaluator,
|
||||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||||
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
||||||
private val builtIns: KotlinBuiltIns,
|
private val builtIns: KotlinBuiltIns,
|
||||||
private val qualifiedExpressionResolver: QualifiedExpressionResolver,
|
private val qualifiedExpressionResolver: QualifiedExpressionResolver,
|
||||||
private val languageVersionSettings: LanguageVersionSettings
|
private val languageVersionSettings: LanguageVersionSettings
|
||||||
) {
|
) {
|
||||||
private lateinit var expressionTypingServices: ExpressionTypingServices
|
private lateinit var expressionTypingServices: ExpressionTypingServices
|
||||||
|
|
||||||
@@ -84,13 +84,16 @@ class CallExpressionResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getResolvedCallForFunction(
|
private fun getResolvedCallForFunction(
|
||||||
call: Call,
|
call: Call,
|
||||||
context: ResolutionContext<*>,
|
context: ResolutionContext<*>,
|
||||||
checkArguments: CheckArgumentTypesMode,
|
checkArguments: CheckArgumentTypesMode,
|
||||||
initialDataFlowInfoForArguments: DataFlowInfo
|
initialDataFlowInfoForArguments: DataFlowInfo
|
||||||
): Pair<Boolean, ResolvedCall<FunctionDescriptor>?> {
|
): Pair<Boolean, ResolvedCall<FunctionDescriptor>?> {
|
||||||
val results = callResolver.resolveFunctionCall(BasicCallResolutionContext.create(
|
val results = callResolver.resolveFunctionCall(
|
||||||
context, call, checkArguments, DataFlowInfoForArgumentsImpl(initialDataFlowInfoForArguments, call)))
|
BasicCallResolutionContext.create(
|
||||||
|
context, call, checkArguments, DataFlowInfoForArgumentsImpl(initialDataFlowInfoForArguments, call)
|
||||||
|
)
|
||||||
|
)
|
||||||
return if (!results.isNothing)
|
return if (!results.isNothing)
|
||||||
Pair(true, OverloadResolutionResultsUtil.getResultingCall(results, context))
|
Pair(true, OverloadResolutionResultsUtil.getResultingCall(results, context))
|
||||||
else
|
else
|
||||||
@@ -98,23 +101,25 @@ class CallExpressionResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getVariableType(
|
private fun getVariableType(
|
||||||
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
|
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
|
||||||
callOperationNode: ASTNode?, context: ExpressionTypingContext
|
callOperationNode: ASTNode?, context: ExpressionTypingContext
|
||||||
): Pair<Boolean, KotlinType?> {
|
): Pair<Boolean, KotlinType?> {
|
||||||
val temporaryForVariable = TemporaryTraceAndCache.create(
|
val temporaryForVariable = TemporaryTraceAndCache.create(
|
||||||
context, "trace to resolve as local variable or property", nameExpression)
|
context, "trace to resolve as local variable or property", nameExpression
|
||||||
|
)
|
||||||
val call = CallMaker.makePropertyCall(receiver, callOperationNode, nameExpression)
|
val call = CallMaker.makePropertyCall(receiver, callOperationNode, nameExpression)
|
||||||
val contextForVariable = BasicCallResolutionContext.create(
|
val contextForVariable = BasicCallResolutionContext.create(
|
||||||
context.replaceTraceAndCache(temporaryForVariable),
|
context.replaceTraceAndCache(temporaryForVariable),
|
||||||
call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS)
|
call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS
|
||||||
|
)
|
||||||
val resolutionResult = callResolver.resolveSimpleProperty(contextForVariable)
|
val resolutionResult = callResolver.resolveSimpleProperty(contextForVariable)
|
||||||
|
|
||||||
// if the expression is a receiver in a qualified expression, it should be resolved after the selector is resolved
|
// if the expression is a receiver in a qualified expression, it should be resolved after the selector is resolved
|
||||||
val isLHSOfDot = KtPsiUtil.isLHSOfDot(nameExpression)
|
val isLHSOfDot = KtPsiUtil.isLHSOfDot(nameExpression)
|
||||||
if (!resolutionResult.isNothing && resolutionResult.resultCode != CANDIDATES_WITH_WRONG_RECEIVER) {
|
if (!resolutionResult.isNothing && resolutionResult.resultCode != CANDIDATES_WITH_WRONG_RECEIVER) {
|
||||||
val isQualifier = isLHSOfDot &&
|
val isQualifier = isLHSOfDot &&
|
||||||
resolutionResult.isSingleResult &&
|
resolutionResult.isSingleResult &&
|
||||||
resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject
|
resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject
|
||||||
if (!isQualifier) {
|
if (!isQualifier) {
|
||||||
temporaryForVariable.commit()
|
temporaryForVariable.commit()
|
||||||
return Pair(true, if (resolutionResult.isSingleResult) resolutionResult.resultingDescriptor.returnType else null)
|
return Pair(true, if (resolutionResult.isSingleResult) resolutionResult.resultingDescriptor.returnType else null)
|
||||||
@@ -122,25 +127,30 @@ class CallExpressionResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
temporaryForVariable.commit()
|
temporaryForVariable.commit()
|
||||||
return Pair(!resolutionResult.isNothing,
|
return Pair(
|
||||||
if (resolutionResult.isSingleResult) resolutionResult.resultingDescriptor.returnType else null)
|
!resolutionResult.isNothing,
|
||||||
|
if (resolutionResult.isSingleResult) resolutionResult.resultingDescriptor.returnType else null
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSimpleNameExpressionTypeInfo(
|
fun getSimpleNameExpressionTypeInfo(
|
||||||
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
|
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
|
||||||
callOperationNode: ASTNode?, context: ExpressionTypingContext
|
callOperationNode: ASTNode?, context: ExpressionTypingContext
|
||||||
) = getSimpleNameExpressionTypeInfo(nameExpression, receiver, callOperationNode, context, context.dataFlowInfo)
|
) = getSimpleNameExpressionTypeInfo(nameExpression, receiver, callOperationNode, context, context.dataFlowInfo)
|
||||||
|
|
||||||
private fun getSimpleNameExpressionTypeInfo(
|
private fun getSimpleNameExpressionTypeInfo(
|
||||||
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
|
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
|
||||||
callOperationNode: ASTNode?, context: ExpressionTypingContext,
|
callOperationNode: ASTNode?, context: ExpressionTypingContext,
|
||||||
initialDataFlowInfoForArguments: DataFlowInfo
|
initialDataFlowInfoForArguments: DataFlowInfo
|
||||||
): KotlinTypeInfo {
|
): KotlinTypeInfo {
|
||||||
|
|
||||||
val temporaryForVariable = TemporaryTraceAndCache.create(
|
val temporaryForVariable = TemporaryTraceAndCache.create(
|
||||||
context, "trace to resolve as variable", nameExpression)
|
context, "trace to resolve as variable", nameExpression
|
||||||
val (notNothing, type) = getVariableType(nameExpression, receiver, callOperationNode,
|
)
|
||||||
context.replaceTraceAndCache(temporaryForVariable))
|
val (notNothing, type) = getVariableType(
|
||||||
|
nameExpression, receiver, callOperationNode,
|
||||||
|
context.replaceTraceAndCache(temporaryForVariable)
|
||||||
|
)
|
||||||
|
|
||||||
if (notNothing) {
|
if (notNothing) {
|
||||||
temporaryForVariable.commit()
|
temporaryForVariable.commit()
|
||||||
@@ -149,10 +159,12 @@ class CallExpressionResolver(
|
|||||||
|
|
||||||
val call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, emptyList())
|
val call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, emptyList())
|
||||||
val temporaryForFunction = TemporaryTraceAndCache.create(
|
val temporaryForFunction = TemporaryTraceAndCache.create(
|
||||||
context, "trace to resolve as function", nameExpression)
|
context, "trace to resolve as function", nameExpression
|
||||||
|
)
|
||||||
val newContext = context.replaceTraceAndCache(temporaryForFunction)
|
val newContext = context.replaceTraceAndCache(temporaryForFunction)
|
||||||
val (resolveResult, resolvedCall) = getResolvedCallForFunction(
|
val (resolveResult, resolvedCall) = getResolvedCallForFunction(
|
||||||
call, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, initialDataFlowInfoForArguments)
|
call, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, initialDataFlowInfoForArguments
|
||||||
|
)
|
||||||
if (resolveResult) {
|
if (resolveResult) {
|
||||||
val functionDescriptor = resolvedCall?.resultingDescriptor
|
val functionDescriptor = resolvedCall?.resultingDescriptor
|
||||||
if (functionDescriptor !is ConstructorDescriptor) {
|
if (functionDescriptor !is ConstructorDescriptor) {
|
||||||
@@ -173,11 +185,12 @@ class CallExpressionResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getCallExpressionTypeInfo(
|
fun getCallExpressionTypeInfo(
|
||||||
callExpression: KtCallExpression, receiver: ReceiverValue?,
|
callExpression: KtCallExpression, receiver: ReceiverValue?,
|
||||||
callOperationNode: ASTNode?, context: ExpressionTypingContext
|
callOperationNode: ASTNode?, context: ExpressionTypingContext
|
||||||
): KotlinTypeInfo {
|
): KotlinTypeInfo {
|
||||||
val typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(
|
val typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(
|
||||||
callExpression, receiver, callOperationNode, context, context.dataFlowInfo)
|
callExpression, receiver, callOperationNode, context, context.dataFlowInfo
|
||||||
|
)
|
||||||
if (context.contextDependency == INDEPENDENT) {
|
if (context.contextDependency == INDEPENDENT) {
|
||||||
dataFlowAnalyzer.checkType(typeInfo.type, callExpression, context)
|
dataFlowAnalyzer.checkType(typeInfo.type, callExpression, context)
|
||||||
}
|
}
|
||||||
@@ -189,19 +202,21 @@ class CallExpressionResolver(
|
|||||||
* Determines the result type and data flow information after the call.
|
* Determines the result type and data flow information after the call.
|
||||||
*/
|
*/
|
||||||
private fun getCallExpressionTypeInfoWithoutFinalTypeCheck(
|
private fun getCallExpressionTypeInfoWithoutFinalTypeCheck(
|
||||||
callExpression: KtCallExpression, receiver: Receiver?,
|
callExpression: KtCallExpression, receiver: Receiver?,
|
||||||
callOperationNode: ASTNode?, context: ExpressionTypingContext,
|
callOperationNode: ASTNode?, context: ExpressionTypingContext,
|
||||||
initialDataFlowInfoForArguments: DataFlowInfo
|
initialDataFlowInfoForArguments: DataFlowInfo
|
||||||
): KotlinTypeInfo {
|
): KotlinTypeInfo {
|
||||||
val call = CallMaker.makeCall(receiver, callOperationNode, callExpression)
|
val call = CallMaker.makeCall(receiver, callOperationNode, callExpression)
|
||||||
|
|
||||||
val temporaryForFunction = TemporaryTraceAndCache.create(
|
val temporaryForFunction = TemporaryTraceAndCache.create(
|
||||||
context, "trace to resolve as function call", callExpression)
|
context, "trace to resolve as function call", callExpression
|
||||||
|
)
|
||||||
val (resolveResult, resolvedCall) = getResolvedCallForFunction(
|
val (resolveResult, resolvedCall) = getResolvedCallForFunction(
|
||||||
call,
|
call,
|
||||||
context.replaceTraceAndCache(temporaryForFunction),
|
context.replaceTraceAndCache(temporaryForFunction),
|
||||||
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||||
initialDataFlowInfoForArguments)
|
initialDataFlowInfoForArguments
|
||||||
|
)
|
||||||
if (resolveResult) {
|
if (resolveResult) {
|
||||||
val functionDescriptor = resolvedCall?.resultingDescriptor
|
val functionDescriptor = resolvedCall?.resultingDescriptor
|
||||||
temporaryForFunction.commit()
|
temporaryForFunction.commit()
|
||||||
@@ -246,9 +261,12 @@ class CallExpressionResolver(
|
|||||||
val calleeExpression = callExpression.calleeExpression
|
val calleeExpression = callExpression.calleeExpression
|
||||||
if (calleeExpression is KtSimpleNameExpression && callExpression.typeArgumentList == null) {
|
if (calleeExpression is KtSimpleNameExpression && callExpression.typeArgumentList == null) {
|
||||||
val temporaryForVariable = TemporaryTraceAndCache.create(
|
val temporaryForVariable = TemporaryTraceAndCache.create(
|
||||||
context, "trace to resolve as variable with 'invoke' call", callExpression)
|
context, "trace to resolve as variable with 'invoke' call", callExpression
|
||||||
val (notNothing, type) = getVariableType(calleeExpression, receiver, callOperationNode,
|
)
|
||||||
context.replaceTraceAndCache(temporaryForVariable))
|
val (notNothing, type) = getVariableType(
|
||||||
|
calleeExpression, receiver, callOperationNode,
|
||||||
|
context.replaceTraceAndCache(temporaryForVariable)
|
||||||
|
)
|
||||||
val qualifier = temporaryForVariable.trace.get(BindingContext.QUALIFIER, calleeExpression)
|
val qualifier = temporaryForVariable.trace.get(BindingContext.QUALIFIER, calleeExpression)
|
||||||
if (notNothing && (qualifier == null || qualifier !is PackageQualifier)) {
|
if (notNothing && (qualifier == null || qualifier !is PackageQualifier)) {
|
||||||
|
|
||||||
@@ -258,14 +276,18 @@ class CallExpressionResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
temporaryForVariable.commit()
|
temporaryForVariable.commit()
|
||||||
context.trace.report(FUNCTION_EXPECTED.on(calleeExpression, calleeExpression,
|
context.trace.report(
|
||||||
type ?: ErrorUtils.createErrorType("")))
|
FUNCTION_EXPECTED.on(
|
||||||
|
calleeExpression, calleeExpression,
|
||||||
|
type ?: ErrorUtils.createErrorType("")
|
||||||
|
)
|
||||||
|
)
|
||||||
argumentTypeResolver.analyzeArgumentsAndRecordTypes(
|
argumentTypeResolver.analyzeArgumentsAndRecordTypes(
|
||||||
BasicCallResolutionContext.create(
|
BasicCallResolutionContext.create(
|
||||||
context, call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
context, call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||||
DataFlowInfoForArgumentsImpl(initialDataFlowInfoForArguments, call)
|
DataFlowInfoForArgumentsImpl(initialDataFlowInfoForArguments, call)
|
||||||
),
|
),
|
||||||
ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS
|
ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS
|
||||||
)
|
)
|
||||||
return noTypeInfo(context)
|
return noTypeInfo(context)
|
||||||
}
|
}
|
||||||
@@ -275,41 +297,41 @@ class CallExpressionResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun KtQualifiedExpression.elementChain(context: ExpressionTypingContext) =
|
private fun KtQualifiedExpression.elementChain(context: ExpressionTypingContext) =
|
||||||
qualifiedExpressionResolver.resolveQualifierInExpressionAndUnroll(this, context) {
|
qualifiedExpressionResolver.resolveQualifierInExpressionAndUnroll(this, context) { nameExpression ->
|
||||||
nameExpression ->
|
val resolutionResult = resolveSimpleName(context, nameExpression)
|
||||||
val resolutionResult = resolveSimpleName(context, nameExpression)
|
|
||||||
|
|
||||||
if (resolutionResult.isSingleResult && resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject) {
|
if (resolutionResult.isSingleResult && resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject) {
|
||||||
false
|
false
|
||||||
}
|
} else when (resolutionResult.resultCode) {
|
||||||
else when (resolutionResult.resultCode) {
|
NAME_NOT_FOUND, CANDIDATES_WITH_WRONG_RECEIVER -> false
|
||||||
NAME_NOT_FOUND, CANDIDATES_WITH_WRONG_RECEIVER -> false
|
else -> !context.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) || resolutionResult.isSuccess
|
||||||
else -> !context.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) || resolutionResult.isSuccess
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun resolveSimpleName(
|
private fun resolveSimpleName(
|
||||||
context: ExpressionTypingContext, expression: KtSimpleNameExpression
|
context: ExpressionTypingContext, expression: KtSimpleNameExpression
|
||||||
): OverloadResolutionResults<VariableDescriptor> {
|
): OverloadResolutionResults<VariableDescriptor> {
|
||||||
val temporaryForVariable = TemporaryTraceAndCache.create(context, "trace to resolve as local variable or property", expression)
|
val temporaryForVariable = TemporaryTraceAndCache.create(context, "trace to resolve as local variable or property", expression)
|
||||||
val call = CallMaker.makePropertyCall(null, null, expression)
|
val call = CallMaker.makePropertyCall(null, null, expression)
|
||||||
val contextForVariable = BasicCallResolutionContext.create(
|
val contextForVariable = BasicCallResolutionContext.create(
|
||||||
context.replaceTraceAndCache(temporaryForVariable), call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS
|
context.replaceTraceAndCache(temporaryForVariable), call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS
|
||||||
)
|
)
|
||||||
return callResolver.resolveSimpleProperty(contextForVariable)
|
return callResolver.resolveSimpleProperty(contextForVariable)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getUnsafeSelectorTypeInfo(
|
private fun getUnsafeSelectorTypeInfo(
|
||||||
receiver: Receiver,
|
receiver: Receiver,
|
||||||
callOperationNode: ASTNode?,
|
callOperationNode: ASTNode?,
|
||||||
selectorExpression: KtExpression?,
|
selectorExpression: KtExpression?,
|
||||||
context: ExpressionTypingContext,
|
context: ExpressionTypingContext,
|
||||||
initialDataFlowInfoForArguments: DataFlowInfo
|
initialDataFlowInfoForArguments: DataFlowInfo
|
||||||
): KotlinTypeInfo = when (selectorExpression) {
|
): KotlinTypeInfo = when (selectorExpression) {
|
||||||
is KtCallExpression -> getCallExpressionTypeInfoWithoutFinalTypeCheck(
|
is KtCallExpression -> getCallExpressionTypeInfoWithoutFinalTypeCheck(
|
||||||
selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments)
|
selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments
|
||||||
|
)
|
||||||
is KtSimpleNameExpression -> getSimpleNameExpressionTypeInfo(
|
is KtSimpleNameExpression -> getSimpleNameExpressionTypeInfo(
|
||||||
selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments)
|
selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments
|
||||||
|
)
|
||||||
is KtExpression -> {
|
is KtExpression -> {
|
||||||
expressionTypingServices.getTypeInfo(selectorExpression, context)
|
expressionTypingServices.getTypeInfo(selectorExpression, context)
|
||||||
context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression))
|
context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression))
|
||||||
@@ -323,14 +345,14 @@ class CallExpressionResolver(
|
|||||||
var initialDataFlowInfoForArguments = context.dataFlowInfo
|
var initialDataFlowInfoForArguments = context.dataFlowInfo
|
||||||
val receiverDataFlowValue = (receiver as? ReceiverValue)?.let { DataFlowValueFactory.createDataFlowValue(it, context) }
|
val receiverDataFlowValue = (receiver as? ReceiverValue)?.let { DataFlowValueFactory.createDataFlowValue(it, context) }
|
||||||
val receiverCanBeNull = receiverDataFlowValue != null &&
|
val receiverCanBeNull = receiverDataFlowValue != null &&
|
||||||
initialDataFlowInfoForArguments.getStableNullability(receiverDataFlowValue).canBeNull()
|
initialDataFlowInfoForArguments.getStableNullability(receiverDataFlowValue).canBeNull()
|
||||||
if (receiverDataFlowValue != null && element.safe) {
|
if (receiverDataFlowValue != null && element.safe) {
|
||||||
// Additional "receiver != null" information should be applied if we consider a safe call
|
// Additional "receiver != null" information should be applied if we consider a safe call
|
||||||
if (receiverCanBeNull) {
|
if (receiverCanBeNull) {
|
||||||
initialDataFlowInfoForArguments = initialDataFlowInfoForArguments.disequate(
|
initialDataFlowInfoForArguments = initialDataFlowInfoForArguments.disequate(
|
||||||
receiverDataFlowValue, DataFlowValue.nullValue(builtIns), languageVersionSettings)
|
receiverDataFlowValue, DataFlowValue.nullValue(builtIns), languageVersionSettings
|
||||||
}
|
)
|
||||||
else if (receiver is ReceiverValue) {
|
} else if (receiver is ReceiverValue) {
|
||||||
reportUnnecessarySafeCall(context.trace, receiver.type, element.node, receiver)
|
reportUnnecessarySafeCall(context.trace, receiver.type, element.node, receiver)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -361,8 +383,7 @@ class CallExpressionResolver(
|
|||||||
val value = constantExpressionEvaluator.evaluateExpression(qualified, context.trace, context.expectedType)
|
val value = constantExpressionEvaluator.evaluateExpression(qualified, context.trace, context.expectedType)
|
||||||
return if (value != null && value.isPure) {
|
return if (value != null && value.isPure) {
|
||||||
dataFlowAnalyzer.createCompileTimeConstantTypeInfo(value, qualified, context)
|
dataFlowAnalyzer.createCompileTimeConstantTypeInfo(value, qualified, context)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (context.contextDependency == INDEPENDENT) {
|
if (context.contextDependency == INDEPENDENT) {
|
||||||
dataFlowAnalyzer.checkType(selectorTypeInfo.type, qualified, context)
|
dataFlowAnalyzer.checkType(selectorTypeInfo.type, qualified, context)
|
||||||
}
|
}
|
||||||
@@ -409,20 +430,19 @@ class CallExpressionResolver(
|
|||||||
val receiverType = receiverTypeInfo.type ?: ErrorUtils.createErrorType("Type for " + element.receiver.text)
|
val receiverType = receiverTypeInfo.type ?: ErrorUtils.createErrorType("Type for " + element.receiver.text)
|
||||||
|
|
||||||
val receiver = trace.get(BindingContext.QUALIFIER, element.receiver)
|
val receiver = trace.get(BindingContext.QUALIFIER, element.receiver)
|
||||||
?: ExpressionReceiver.create(element.receiver, receiverType, trace.bindingContext)
|
?: ExpressionReceiver.create(element.receiver, receiverType, trace.bindingContext)
|
||||||
|
|
||||||
val qualifiedExpression = element.qualified
|
val qualifiedExpression = element.qualified
|
||||||
val lastStage = qualifiedExpression === expression
|
val lastStage = qualifiedExpression === expression
|
||||||
// Drop NO_EXPECTED_TYPE / INDEPENDENT at last stage
|
// Drop NO_EXPECTED_TYPE / INDEPENDENT at last stage
|
||||||
val contextForSelector = (if (lastStage) context else currentContext).replaceDataFlowInfo(
|
val contextForSelector = (if (lastStage) context else currentContext).replaceDataFlowInfo(
|
||||||
if (receiver is ReceiverValue && TypeUtils.isNullableType(receiver.type) && !element.safe) {
|
if (receiver is ReceiverValue && TypeUtils.isNullableType(receiver.type) && !element.safe) {
|
||||||
// Call with nullable receiver: take data flow info from branch point
|
// Call with nullable receiver: take data flow info from branch point
|
||||||
branchPointDataFlowInfo
|
branchPointDataFlowInfo
|
||||||
}
|
} else {
|
||||||
else {
|
// Take data flow info from the current receiver
|
||||||
// Take data flow info from the current receiver
|
receiverTypeInfo.dataFlowInfo
|
||||||
receiverTypeInfo.dataFlowInfo
|
}
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
val selectorTypeInfo = getSafeOrUnsafeSelectorTypeInfo(receiver, element, contextForSelector)
|
val selectorTypeInfo = getSafeOrUnsafeSelectorTypeInfo(receiver, element, contextForSelector)
|
||||||
@@ -432,8 +452,9 @@ class CallExpressionResolver(
|
|||||||
branchPointDataFlowInfo = selectorTypeInfo.dataFlowInfo
|
branchPointDataFlowInfo = selectorTypeInfo.dataFlowInfo
|
||||||
}
|
}
|
||||||
|
|
||||||
resultTypeInfo = checkSelectorTypeInfo(qualifiedExpression, selectorTypeInfo, contextForSelector).
|
resultTypeInfo = checkSelectorTypeInfo(qualifiedExpression, selectorTypeInfo, contextForSelector).replaceDataFlowInfo(
|
||||||
replaceDataFlowInfo(branchPointDataFlowInfo)
|
branchPointDataFlowInfo
|
||||||
|
)
|
||||||
if (!lastStage) {
|
if (!lastStage) {
|
||||||
recordResultTypeInfo(qualifiedExpression, resultTypeInfo, contextForSelector)
|
recordResultTypeInfo(qualifiedExpression, resultTypeInfo, contextForSelector)
|
||||||
}
|
}
|
||||||
@@ -444,9 +465,9 @@ class CallExpressionResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveDeferredReceiverInQualifiedExpression(
|
private fun resolveDeferredReceiverInQualifiedExpression(
|
||||||
qualifier: Qualifier,
|
qualifier: Qualifier,
|
||||||
selectorExpression: KtExpression?,
|
selectorExpression: KtExpression?,
|
||||||
context: ExpressionTypingContext
|
context: ExpressionTypingContext
|
||||||
) {
|
) {
|
||||||
val calleeExpression = KtPsiUtil.deparenthesize(selectorExpression.getCalleeExpressionIfAny())
|
val calleeExpression = KtPsiUtil.deparenthesize(selectorExpression.getCalleeExpressionIfAny())
|
||||||
val selectorDescriptor = (calleeExpression as? KtReferenceExpression)?.let {
|
val selectorDescriptor = (calleeExpression as? KtReferenceExpression)?.let {
|
||||||
@@ -469,33 +490,31 @@ class CallExpressionResolver(
|
|||||||
if (parent != null) {
|
if (parent != null) {
|
||||||
return isUnderAnnotationClassDeclaration(trace, parent)
|
return isUnderAnnotationClassDeclaration(trace, parent)
|
||||||
}
|
}
|
||||||
}
|
} else if (parent is KtParameter) {
|
||||||
else if (parent is KtParameter) {
|
|
||||||
return isUnderAnnotationClassDeclaration(trace, parent)
|
return isUnderAnnotationClassDeclaration(trace, parent)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isUnderAnnotationClassDeclaration(trace: BindingTrace, parent: PsiElement) =
|
private fun isUnderAnnotationClassDeclaration(trace: BindingTrace, parent: PsiElement) =
|
||||||
parent.getParentOfType<KtClass>(true)?.let {
|
parent.getParentOfType<KtClass>(true)?.let {
|
||||||
DescriptorUtils.isAnnotationClass(trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, it))
|
DescriptorUtils.isAnnotationClass(trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, it))
|
||||||
} ?: false
|
} ?: false
|
||||||
|
|
||||||
fun reportUnnecessarySafeCall(
|
fun reportUnnecessarySafeCall(
|
||||||
trace: BindingTrace, type: KotlinType,
|
trace: BindingTrace, type: KotlinType,
|
||||||
callOperationNode: ASTNode, explicitReceiver: Receiver?
|
callOperationNode: ASTNode, explicitReceiver: Receiver?
|
||||||
) = trace.report(
|
) = trace.report(
|
||||||
if (explicitReceiver is ExpressionReceiver && explicitReceiver.expression is KtSuperExpression) {
|
if (explicitReceiver is ExpressionReceiver && explicitReceiver.expression is KtSuperExpression) {
|
||||||
UNEXPECTED_SAFE_CALL.on(callOperationNode.psi)
|
UNEXPECTED_SAFE_CALL.on(callOperationNode.psi)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
UNNECESSARY_SAFE_CALL.on(callOperationNode.psi, type)
|
UNNECESSARY_SAFE_CALL.on(callOperationNode.psi, type)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
private fun checkNestedClassAccess(
|
private fun checkNestedClassAccess(
|
||||||
expression: KtQualifiedExpression,
|
expression: KtQualifiedExpression,
|
||||||
context: ExpressionTypingContext
|
context: ExpressionTypingContext
|
||||||
) {
|
) {
|
||||||
val selectorExpression = expression.selectorExpression ?: return
|
val selectorExpression = expression.selectorExpression ?: return
|
||||||
|
|
||||||
|
|||||||
@@ -80,13 +80,13 @@ fun replaceReturnTypeForCallable(type: KotlinType, given: KotlinType): KotlinTyp
|
|||||||
fun replaceReturnTypeByUnknown(type: KotlinType) = replaceReturnTypeForCallable(type, DONT_CARE)
|
fun replaceReturnTypeByUnknown(type: KotlinType) = replaceReturnTypeForCallable(type, DONT_CARE)
|
||||||
|
|
||||||
private fun replaceTypeArguments(type: KotlinType, newArguments: List<TypeProjection>) =
|
private fun replaceTypeArguments(type: KotlinType, newArguments: List<TypeProjection>) =
|
||||||
KotlinTypeFactory.simpleType(type.annotations, type.constructor, newArguments, type.isMarkedNullable)
|
KotlinTypeFactory.simpleType(type.annotations, type.constructor, newArguments, type.isMarkedNullable)
|
||||||
|
|
||||||
private fun getParameterArgumentsOfCallableType(type: KotlinType) =
|
private fun getParameterArgumentsOfCallableType(type: KotlinType) =
|
||||||
type.arguments.dropLast(1)
|
type.arguments.dropLast(1)
|
||||||
|
|
||||||
fun getReturnTypeForCallable(type: KotlinType) =
|
fun getReturnTypeForCallable(type: KotlinType) =
|
||||||
type.arguments.last().type
|
type.arguments.last().type
|
||||||
|
|
||||||
private fun CallableDescriptor.hasReturnTypeDependentOnUninferredParams(constraintSystem: ConstraintSystem): Boolean {
|
private fun CallableDescriptor.hasReturnTypeDependentOnUninferredParams(constraintSystem: ConstraintSystem): Boolean {
|
||||||
val returnType = returnType ?: return false
|
val returnType = returnType ?: return false
|
||||||
@@ -125,8 +125,10 @@ fun getErasedReceiverType(receiverParameterDescriptor: ReceiverParameterDescript
|
|||||||
receiverType.constructor
|
receiverType.constructor
|
||||||
}
|
}
|
||||||
|
|
||||||
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(receiverType.annotations, receiverTypeConstructor, fakeTypeArguments,
|
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
|
||||||
receiverType.isMarkedNullable, ErrorUtils.createErrorScope("Error scope for erased receiver type", /*throwExceptions=*/true))
|
receiverType.annotations, receiverTypeConstructor, fakeTypeArguments,
|
||||||
|
receiverType.isMarkedNullable, ErrorUtils.createErrorScope("Error scope for erased receiver type", /*throwExceptions=*/true)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isOrOverridesSynthesized(descriptor: CallableMemberDescriptor): Boolean {
|
fun isOrOverridesSynthesized(descriptor: CallableMemberDescriptor): Boolean {
|
||||||
@@ -163,7 +165,7 @@ fun isInfixCall(call: Call): Boolean {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun isSuperOrDelegatingConstructorCall(call: Call): Boolean =
|
fun isSuperOrDelegatingConstructorCall(call: Call): Boolean =
|
||||||
call.calleeExpression.let { it is KtConstructorCalleeExpression || it is KtConstructorDelegationReferenceExpression }
|
call.calleeExpression.let { it is KtConstructorCalleeExpression || it is KtConstructorDelegationReferenceExpression }
|
||||||
|
|
||||||
fun isInvokeCallOnVariable(call: Call): Boolean {
|
fun isInvokeCallOnVariable(call: Call): Boolean {
|
||||||
if (call.callType !== Call.CallType.INVOKE) return false
|
if (call.callType !== Call.CallType.INVOKE) return false
|
||||||
@@ -183,9 +185,9 @@ fun getSuperCallExpression(call: Call): KtSuperExpression? {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun getEffectiveExpectedType(
|
fun getEffectiveExpectedType(
|
||||||
parameterDescriptor: ValueParameterDescriptor,
|
parameterDescriptor: ValueParameterDescriptor,
|
||||||
argument: ValueArgument,
|
argument: ValueArgument,
|
||||||
context: ResolutionContext<*>
|
context: ResolutionContext<*>
|
||||||
): KotlinType {
|
): KotlinType {
|
||||||
if (argument.getSpreadElement() != null || shouldCheckAsArray(parameterDescriptor, argument, context)) {
|
if (argument.getSpreadElement() != null || shouldCheckAsArray(parameterDescriptor, argument, context)) {
|
||||||
if (parameterDescriptor.varargElementType == null) {
|
if (parameterDescriptor.varargElementType == null) {
|
||||||
@@ -203,9 +205,9 @@ fun getEffectiveExpectedType(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun shouldCheckAsArray(
|
private fun shouldCheckAsArray(
|
||||||
parameterDescriptor: ValueParameterDescriptor,
|
parameterDescriptor: ValueParameterDescriptor,
|
||||||
argument: ValueArgument,
|
argument: ValueArgument,
|
||||||
context: ResolutionContext<*>
|
context: ResolutionContext<*>
|
||||||
): Boolean {
|
): Boolean {
|
||||||
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.AssigningArraysToVarargsInNamedFormInAnnotations)) return false
|
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.AssigningArraysToVarargsInNamedFormInAnnotations)) return false
|
||||||
|
|
||||||
@@ -223,29 +225,30 @@ fun isArrayOrArrayLiteral(argument: ValueArgument, context: ResolutionContext<*>
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun createResolutionCandidatesForConstructors(
|
fun createResolutionCandidatesForConstructors(
|
||||||
lexicalScope: LexicalScope,
|
lexicalScope: LexicalScope,
|
||||||
call: Call,
|
call: Call,
|
||||||
typeWithConstructors: KotlinType,
|
typeWithConstructors: KotlinType,
|
||||||
useKnownTypeSubstitutor: Boolean,
|
useKnownTypeSubstitutor: Boolean,
|
||||||
syntheticScopes: SyntheticScopes
|
syntheticScopes: SyntheticScopes
|
||||||
): List<ResolutionCandidate<ConstructorDescriptor>> {
|
): List<ResolutionCandidate<ConstructorDescriptor>> {
|
||||||
val classWithConstructors = typeWithConstructors.constructor.declarationDescriptor as ClassDescriptor
|
val classWithConstructors = typeWithConstructors.constructor.declarationDescriptor as ClassDescriptor
|
||||||
|
|
||||||
val unwrappedType = typeWithConstructors.unwrap()
|
val unwrappedType = typeWithConstructors.unwrap()
|
||||||
val knownSubstitutor =
|
val knownSubstitutor =
|
||||||
if (useKnownTypeSubstitutor)
|
if (useKnownTypeSubstitutor)
|
||||||
TypeSubstitutor.create(
|
TypeSubstitutor.create(
|
||||||
(unwrappedType as? AbbreviatedType)?.abbreviation ?: unwrappedType
|
(unwrappedType as? AbbreviatedType)?.abbreviation ?: unwrappedType
|
||||||
)
|
)
|
||||||
else null
|
else null
|
||||||
|
|
||||||
val typeAliasDescriptor =
|
val typeAliasDescriptor =
|
||||||
if (unwrappedType is AbbreviatedType)
|
if (unwrappedType is AbbreviatedType)
|
||||||
unwrappedType.abbreviation.constructor.declarationDescriptor as? TypeAliasDescriptor
|
unwrappedType.abbreviation.constructor.declarationDescriptor as? TypeAliasDescriptor
|
||||||
else
|
else
|
||||||
null
|
null
|
||||||
|
|
||||||
val constructors = typeAliasDescriptor?.constructors?.mapNotNull(TypeAliasConstructorDescriptor::withDispatchReceiver) ?: classWithConstructors.constructors
|
val constructors = typeAliasDescriptor?.constructors?.mapNotNull(TypeAliasConstructorDescriptor::withDispatchReceiver)
|
||||||
|
?: classWithConstructors.constructors
|
||||||
|
|
||||||
if (constructors.isEmpty()) return emptyList()
|
if (constructors.isEmpty()) return emptyList()
|
||||||
|
|
||||||
@@ -262,8 +265,7 @@ fun createResolutionCandidatesForConstructors(
|
|||||||
|
|
||||||
receiverKind = ExplicitReceiverKind.DISPATCH_RECEIVER
|
receiverKind = ExplicitReceiverKind.DISPATCH_RECEIVER
|
||||||
dispatchReceiver = receiver.value
|
dispatchReceiver = receiver.value
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
receiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
|
receiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
|
||||||
dispatchReceiver = null
|
dispatchReceiver = null
|
||||||
}
|
}
|
||||||
@@ -276,12 +278,12 @@ fun createResolutionCandidatesForConstructors(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun KtLambdaExpression.getCorrespondingParameterForFunctionArgument(
|
fun KtLambdaExpression.getCorrespondingParameterForFunctionArgument(
|
||||||
bindingContext: BindingContext
|
bindingContext: BindingContext
|
||||||
): ValueParameterDescriptor? {
|
): ValueParameterDescriptor? {
|
||||||
val resolvedCall = KtPsiUtil.getParentCallIfPresent(this)?.getResolvedCall(bindingContext) ?: return null
|
val resolvedCall = KtPsiUtil.getParentCallIfPresent(this)?.getResolvedCall(bindingContext) ?: return null
|
||||||
val valueArgument =
|
val valueArgument =
|
||||||
resolvedCall.call.getValueArgumentForExpression(this)
|
resolvedCall.call.getValueArgumentForExpression(this)
|
||||||
?: return null
|
?: return null
|
||||||
val mapping = resolvedCall.getArgumentMapping(valueArgument) as? ArgumentMatch ?: return null
|
val mapping = resolvedCall.getArgumentMapping(valueArgument) as? ArgumentMatch ?: return null
|
||||||
|
|
||||||
return mapping.valueParameter
|
return mapping.valueParameter
|
||||||
|
|||||||
@@ -57,15 +57,15 @@ import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class CandidateResolver(
|
class CandidateResolver(
|
||||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||||
private val genericCandidateResolver: GenericCandidateResolver,
|
private val genericCandidateResolver: GenericCandidateResolver,
|
||||||
private val reflectionTypes: ReflectionTypes,
|
private val reflectionTypes: ReflectionTypes,
|
||||||
private val additionalTypeCheckers: Iterable<AdditionalTypeChecker>,
|
private val additionalTypeCheckers: Iterable<AdditionalTypeChecker>,
|
||||||
private val smartCastManager: SmartCastManager
|
private val smartCastManager: SmartCastManager
|
||||||
) {
|
) {
|
||||||
fun <D : CallableDescriptor> performResolutionForCandidateCall(
|
fun <D : CallableDescriptor> performResolutionForCandidateCall(
|
||||||
context: CallCandidateResolutionContext<D>,
|
context: CallCandidateResolutionContext<D>,
|
||||||
checkArguments: CheckArgumentTypesMode
|
checkArguments: CheckArgumentTypesMode
|
||||||
): Unit = with(context) {
|
): Unit = with(context) {
|
||||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||||
|
|
||||||
@@ -107,8 +107,7 @@ class CandidateResolver(
|
|||||||
&& candidateCall.knownTypeParametersSubstitutor == null
|
&& candidateCall.knownTypeParametersSubstitutor == null
|
||||||
) {
|
) {
|
||||||
genericCandidateResolver.inferTypeArguments(this)
|
genericCandidateResolver.inferTypeArguments(this)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
checkAllValueArguments(this, SHAPE_FUNCTION_ARGUMENTS).status
|
checkAllValueArguments(this, SHAPE_FUNCTION_ARGUMENTS).status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -117,8 +116,7 @@ class CandidateResolver(
|
|||||||
val ktTypeArguments = call.typeArguments
|
val ktTypeArguments = call.typeArguments
|
||||||
if (candidateCall.knownTypeParametersSubstitutor != null) {
|
if (candidateCall.knownTypeParametersSubstitutor != null) {
|
||||||
candidateCall.setResultingSubstitutor(candidateCall.knownTypeParametersSubstitutor!!)
|
candidateCall.setResultingSubstitutor(candidateCall.knownTypeParametersSubstitutor!!)
|
||||||
}
|
} else if (ktTypeArguments.isNotEmpty()) {
|
||||||
else if (ktTypeArguments.isNotEmpty()) {
|
|
||||||
// Explicit type arguments passed
|
// Explicit type arguments passed
|
||||||
|
|
||||||
val typeArguments = ArrayList<KotlinType>()
|
val typeArguments = ArrayList<KotlinType>()
|
||||||
@@ -130,9 +128,11 @@ class CandidateResolver(
|
|||||||
|
|
||||||
val expectedTypeArgumentCount = candidateDescriptor.typeParameters.size
|
val expectedTypeArgumentCount = candidateDescriptor.typeParameters.size
|
||||||
for (index in ktTypeArguments.size..expectedTypeArgumentCount - 1) {
|
for (index in ktTypeArguments.size..expectedTypeArgumentCount - 1) {
|
||||||
typeArguments.add(ErrorUtils.createErrorType(
|
typeArguments.add(
|
||||||
|
ErrorUtils.createErrorType(
|
||||||
"Explicit type argument expected for " + candidateDescriptor.typeParameters[index].name
|
"Explicit type argument expected for " + candidateDescriptor.typeParameters[index].name
|
||||||
))
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
val substitution = FunctionDescriptorUtil.createSubstitution(candidateDescriptor as FunctionDescriptor, typeArguments)
|
val substitution = FunctionDescriptorUtil.createSubstitution(candidateDescriptor as FunctionDescriptor, typeArguments)
|
||||||
val substitutor = TypeSubstitutor.create(SubstitutionFilteringInternalResolveAnnotations(substitution))
|
val substitutor = TypeSubstitutor.create(SubstitutionFilteringInternalResolveAnnotations(substitution))
|
||||||
@@ -140,8 +140,7 @@ class CandidateResolver(
|
|||||||
if (expectedTypeArgumentCount != ktTypeArguments.size) {
|
if (expectedTypeArgumentCount != ktTypeArguments.size) {
|
||||||
candidateCall.addStatus(WRONG_NUMBER_OF_TYPE_ARGUMENTS_ERROR)
|
candidateCall.addStatus(WRONG_NUMBER_OF_TYPE_ARGUMENTS_ERROR)
|
||||||
tracing.wrongNumberOfTypeArguments(trace, expectedTypeArgumentCount, candidateDescriptor)
|
tracing.wrongNumberOfTypeArguments(trace, expectedTypeArgumentCount, candidateDescriptor)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
checkGenericBoundsInAFunctionCall(ktTypeArguments, typeArguments, candidateDescriptor, substitutor, trace)
|
checkGenericBoundsInAFunctionCall(ktTypeArguments, typeArguments, candidateDescriptor, substitutor, trace)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,31 +148,30 @@ class CandidateResolver(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.mapArguments()
|
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.mapArguments() = check {
|
||||||
= check {
|
val argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(
|
||||||
val argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(
|
call, tracing, candidateCall
|
||||||
call, tracing, candidateCall)
|
)
|
||||||
if (!argumentMappingStatus.isSuccess) {
|
if (!argumentMappingStatus.isSuccess) {
|
||||||
candidateCall.addStatus(ARGUMENTS_MAPPING_ERROR)
|
candidateCall.addStatus(ARGUMENTS_MAPPING_ERROR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkExpectedCallableType()
|
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkExpectedCallableType() = check {
|
||||||
= check {
|
if (!noExpectedType(expectedType)) {
|
||||||
if (!noExpectedType(expectedType)) {
|
val candidateKCallableType = DoubleColonExpressionResolver.createKCallableTypeForReference(
|
||||||
val candidateKCallableType = DoubleColonExpressionResolver.createKCallableTypeForReference(
|
candidateCall.candidateDescriptor,
|
||||||
candidateCall.candidateDescriptor,
|
(call.callElement.parent as? KtCallableReferenceExpression)?.receiverExpression?.let {
|
||||||
(call.callElement.parent as? KtCallableReferenceExpression)?.receiverExpression?.let {
|
trace.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, it)
|
||||||
trace.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, it)
|
},
|
||||||
},
|
reflectionTypes, scope.ownerDescriptor
|
||||||
reflectionTypes, scope.ownerDescriptor
|
)
|
||||||
)
|
if (candidateKCallableType == null ||
|
||||||
if (candidateKCallableType == null ||
|
!canBeSubtype(candidateKCallableType, expectedType, candidateCall.candidateDescriptor.typeParameters)) {
|
||||||
!canBeSubtype(candidateKCallableType, expectedType, candidateCall.candidateDescriptor.typeParameters)) {
|
candidateCall.addStatus(OTHER_ERROR)
|
||||||
candidateCall.addStatus(OTHER_ERROR)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun canBeSubtype(subType: KotlinType, superType: KotlinType, candidateTypeParameters: List<TypeParameterDescriptor>): Boolean {
|
private fun canBeSubtype(subType: KotlinType, superType: KotlinType, candidateTypeParameters: List<TypeParameterDescriptor>): Boolean {
|
||||||
// Here we need to check that there exists a substitution from type parameters (used in types in candidate signature)
|
// Here we need to check that there exists a substitution from type parameters (used in types in candidate signature)
|
||||||
@@ -191,11 +189,12 @@ class CandidateResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun CallCandidateResolutionContext<*>.checkVisibilityWithDispatchReceiver(
|
private fun CallCandidateResolutionContext<*>.checkVisibilityWithDispatchReceiver(
|
||||||
receiverArgument: ReceiverValue?,
|
receiverArgument: ReceiverValue?,
|
||||||
smartCastType: KotlinType?
|
smartCastType: KotlinType?
|
||||||
): ResolutionStatus {
|
): ResolutionStatus {
|
||||||
val invisibleMember = Visibilities.findInvisibleMember(
|
val invisibleMember = Visibilities.findInvisibleMember(
|
||||||
getReceiverValueWithSmartCast(receiverArgument, smartCastType), candidateDescriptor, scope.ownerDescriptor)
|
getReceiverValueWithSmartCast(receiverArgument, smartCastType), candidateDescriptor, scope.ownerDescriptor
|
||||||
|
)
|
||||||
return if (invisibleMember != null) {
|
return if (invisibleMember != null) {
|
||||||
tracing.invisibleMember(trace, invisibleMember)
|
tracing.invisibleMember(trace, invisibleMember)
|
||||||
INVISIBLE_MEMBER_ERROR
|
INVISIBLE_MEMBER_ERROR
|
||||||
@@ -205,17 +204,17 @@ class CandidateResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun CallCandidateResolutionContext<*>.isCandidateVisibleOrExtensionReceiver(
|
private fun CallCandidateResolutionContext<*>.isCandidateVisibleOrExtensionReceiver(
|
||||||
receiverArgument: ReceiverValue?,
|
receiverArgument: ReceiverValue?,
|
||||||
smartCastType: KotlinType?,
|
smartCastType: KotlinType?,
|
||||||
isDispatchReceiver: Boolean
|
isDispatchReceiver: Boolean
|
||||||
) = !isDispatchReceiver || isCandidateVisible(receiverArgument, smartCastType)
|
) = !isDispatchReceiver || isCandidateVisible(receiverArgument, smartCastType)
|
||||||
|
|
||||||
private fun CallCandidateResolutionContext<*>.isCandidateVisible(
|
private fun CallCandidateResolutionContext<*>.isCandidateVisible(
|
||||||
receiverArgument: ReceiverValue?,
|
receiverArgument: ReceiverValue?,
|
||||||
smartCastType: KotlinType?
|
smartCastType: KotlinType?
|
||||||
) = Visibilities.findInvisibleMember(
|
) = Visibilities.findInvisibleMember(
|
||||||
getReceiverValueWithSmartCast(receiverArgument, smartCastType),
|
getReceiverValueWithSmartCast(receiverArgument, smartCastType),
|
||||||
candidateDescriptor, scope.ownerDescriptor
|
candidateDescriptor, scope.ownerDescriptor
|
||||||
) == null
|
) == null
|
||||||
|
|
||||||
private fun CallCandidateResolutionContext<*>.checkExtensionReceiver() = checkAndReport {
|
private fun CallCandidateResolutionContext<*>.checkExtensionReceiver() = checkAndReport {
|
||||||
@@ -224,17 +223,14 @@ class CandidateResolver(
|
|||||||
if (receiverParameter != null && receiverArgument == null) {
|
if (receiverParameter != null && receiverArgument == null) {
|
||||||
tracing.missingReceiver(candidateCall.trace, receiverParameter)
|
tracing.missingReceiver(candidateCall.trace, receiverParameter)
|
||||||
OTHER_ERROR
|
OTHER_ERROR
|
||||||
}
|
} else if (receiverParameter == null && receiverArgument != null) {
|
||||||
else if (receiverParameter == null && receiverArgument != null) {
|
|
||||||
tracing.noReceiverAllowed(candidateCall.trace)
|
tracing.noReceiverAllowed(candidateCall.trace)
|
||||||
if (call.calleeExpression is KtSimpleNameExpression) {
|
if (call.calleeExpression is KtSimpleNameExpression) {
|
||||||
RECEIVER_PRESENCE_ERROR
|
RECEIVER_PRESENCE_ERROR
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
OTHER_ERROR
|
OTHER_ERROR
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
SUCCESS
|
SUCCESS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -248,8 +244,7 @@ class CandidateResolver(
|
|||||||
&& DescriptorUtils.isStaticNestedClass(candidateDescriptor.containingDeclaration)
|
&& DescriptorUtils.isStaticNestedClass(candidateDescriptor.containingDeclaration)
|
||||||
) {
|
) {
|
||||||
nestedClass = candidateDescriptor.containingDeclaration
|
nestedClass = candidateDescriptor.containingDeclaration
|
||||||
}
|
} else if (candidateDescriptor is FakeCallableDescriptorForObject) {
|
||||||
else if (candidateDescriptor is FakeCallableDescriptorForObject) {
|
|
||||||
nestedClass = candidateDescriptor.getReferencedObject()
|
nestedClass = candidateDescriptor.getReferencedObject()
|
||||||
}
|
}
|
||||||
if (nestedClass != null) {
|
if (nestedClass != null) {
|
||||||
@@ -341,8 +336,9 @@ class CandidateResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <D : CallableDescriptor> checkAllValueArguments(
|
fun <D : CallableDescriptor> checkAllValueArguments(
|
||||||
context: CallCandidateResolutionContext<D>,
|
context: CallCandidateResolutionContext<D>,
|
||||||
resolveFunctionArgumentBodies: ResolveArgumentsMode): ValueArgumentsCheckingResult {
|
resolveFunctionArgumentBodies: ResolveArgumentsMode
|
||||||
|
): ValueArgumentsCheckingResult {
|
||||||
val checkingResult = checkValueArgumentTypes(context, context.candidateCall, resolveFunctionArgumentBodies)
|
val checkingResult = checkValueArgumentTypes(context, context.candidateCall, resolveFunctionArgumentBodies)
|
||||||
var resultStatus = checkingResult.status
|
var resultStatus = checkingResult.status
|
||||||
resultStatus = resultStatus.combine(checkReceivers(context))
|
resultStatus = resultStatus.combine(checkReceivers(context))
|
||||||
@@ -351,9 +347,9 @@ class CandidateResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor, C : CallResolutionContext<C>> checkValueArgumentTypes(
|
private fun <D : CallableDescriptor, C : CallResolutionContext<C>> checkValueArgumentTypes(
|
||||||
context: CallResolutionContext<C>,
|
context: CallResolutionContext<C>,
|
||||||
candidateCall: MutableResolvedCall<D>,
|
candidateCall: MutableResolvedCall<D>,
|
||||||
resolveFunctionArgumentBodies: ResolveArgumentsMode
|
resolveFunctionArgumentBodies: ResolveArgumentsMode
|
||||||
): ValueArgumentsCheckingResult {
|
): ValueArgumentsCheckingResult {
|
||||||
var resultStatus = SUCCESS
|
var resultStatus = SUCCESS
|
||||||
val argumentTypes = Lists.newArrayList<KotlinType>()
|
val argumentTypes = Lists.newArrayList<KotlinType>()
|
||||||
@@ -373,27 +369,26 @@ class CandidateResolver(
|
|||||||
var resultingType: KotlinType? = type
|
var resultingType: KotlinType? = type
|
||||||
if (type == null || (type.isError && !type.isFunctionPlaceholder)) {
|
if (type == null || (type.isError && !type.isFunctionPlaceholder)) {
|
||||||
matchStatus = ArgumentMatchStatus.ARGUMENT_HAS_NO_TYPE
|
matchStatus = ArgumentMatchStatus.ARGUMENT_HAS_NO_TYPE
|
||||||
}
|
} else if (!noExpectedType(expectedType)) {
|
||||||
else if (!noExpectedType(expectedType)) {
|
|
||||||
if (!ArgumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) {
|
if (!ArgumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) {
|
||||||
val smartCast = smartCastValueArgumentTypeIfPossible(expression, newContext.expectedType, type, newContext)
|
val smartCast = smartCastValueArgumentTypeIfPossible(expression, newContext.expectedType, type, newContext)
|
||||||
if (smartCast == null) {
|
if (smartCast == null) {
|
||||||
resultStatus = tryNotNullableArgument(type, expectedType) ?: OTHER_ERROR
|
resultStatus = tryNotNullableArgument(type, expectedType) ?: OTHER_ERROR
|
||||||
matchStatus = ArgumentMatchStatus.TYPE_MISMATCH
|
matchStatus = ArgumentMatchStatus.TYPE_MISMATCH
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
resultingType = smartCast
|
resultingType = smartCast
|
||||||
}
|
}
|
||||||
}
|
} else if (ErrorUtils.containsUninferredParameter(expectedType)) {
|
||||||
else if (ErrorUtils.containsUninferredParameter(expectedType)) {
|
|
||||||
matchStatus = ArgumentMatchStatus.MATCH_MODULO_UNINFERRED_TYPES
|
matchStatus = ArgumentMatchStatus.MATCH_MODULO_UNINFERRED_TYPES
|
||||||
}
|
}
|
||||||
|
|
||||||
val spreadElement = argument.getSpreadElement()
|
val spreadElement = argument.getSpreadElement()
|
||||||
if (spreadElement != null && !type.isFlexible() && type.isMarkedNullable) {
|
if (spreadElement != null && !type.isFlexible() && type.isMarkedNullable) {
|
||||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context)
|
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context)
|
||||||
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(dataFlowValue, expectedType, expression, context,
|
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(
|
||||||
call = null, recordExpressionType = false)
|
dataFlowValue, expectedType, expression, context,
|
||||||
|
call = null, recordExpressionType = false
|
||||||
|
)
|
||||||
if (smartCastResult == null || !smartCastResult.isCorrect) {
|
if (smartCastResult == null || !smartCastResult.isCorrect) {
|
||||||
context.trace.report(Errors.SPREAD_OF_NULLABLE.on(spreadElement))
|
context.trace.report(Errors.SPREAD_OF_NULLABLE.on(spreadElement))
|
||||||
}
|
}
|
||||||
@@ -407,10 +402,10 @@ class CandidateResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun smartCastValueArgumentTypeIfPossible(
|
private fun smartCastValueArgumentTypeIfPossible(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
expectedType: KotlinType,
|
expectedType: KotlinType,
|
||||||
actualType: KotlinType,
|
actualType: KotlinType,
|
||||||
context: ResolutionContext<*>
|
context: ResolutionContext<*>
|
||||||
): KotlinType? {
|
): KotlinType? {
|
||||||
val receiverToCast = ExpressionReceiver.create(KtPsiUtil.safeDeparenthesize(expression), actualType, context.trace.bindingContext)
|
val receiverToCast = ExpressionReceiver.create(KtPsiUtil.safeDeparenthesize(expression), actualType, context.trace.bindingContext)
|
||||||
val variants = smartCastManager.getSmartCastVariantsExcludingReceiver(context, receiverToCast)
|
val variants = smartCastManager.getSmartCastVariantsExcludingReceiver(context, receiverToCast)
|
||||||
@@ -440,8 +435,8 @@ class CandidateResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun CallCandidateResolutionContext<*>.checkReceiverTypeError(
|
private fun CallCandidateResolutionContext<*>.checkReceiverTypeError(
|
||||||
receiverParameterDescriptor: ReceiverParameterDescriptor?,
|
receiverParameterDescriptor: ReceiverParameterDescriptor?,
|
||||||
receiverArgument: ReceiverValue?
|
receiverArgument: ReceiverValue?
|
||||||
) = checkAndReport {
|
) = checkAndReport {
|
||||||
if (receiverParameterDescriptor == null || receiverArgument == null) return@checkAndReport SUCCESS
|
if (receiverParameterDescriptor == null || receiverArgument == null) return@checkAndReport SUCCESS
|
||||||
|
|
||||||
@@ -463,42 +458,48 @@ class CandidateResolver(
|
|||||||
// both 'b' (receiver) and 'foo' (this object) might be nullable. In the first case we mark dot, in the second 'foo'.
|
// both 'b' (receiver) and 'foo' (this object) might be nullable. In the first case we mark dot, in the second 'foo'.
|
||||||
// Class 'CallForImplicitInvoke' helps up to recognise this case, and parameter 'implicitInvokeCheck' helps us to distinguish whether we check receiver or this object.
|
// Class 'CallForImplicitInvoke' helps up to recognise this case, and parameter 'implicitInvokeCheck' helps us to distinguish whether we check receiver or this object.
|
||||||
|
|
||||||
resultStatus = resultStatus.combine(context.checkReceiver(
|
resultStatus = resultStatus.combine(
|
||||||
|
context.checkReceiver(
|
||||||
candidateCall,
|
candidateCall,
|
||||||
candidateCall.resultingDescriptor.extensionReceiverParameter,
|
candidateCall.resultingDescriptor.extensionReceiverParameter,
|
||||||
candidateCall.extensionReceiver,
|
candidateCall.extensionReceiver,
|
||||||
candidateCall.explicitReceiverKind.isExtensionReceiver,
|
candidateCall.explicitReceiverKind.isExtensionReceiver,
|
||||||
implicitInvokeCheck = false, isDispatchReceiver = false
|
implicitInvokeCheck = false, isDispatchReceiver = false
|
||||||
))
|
)
|
||||||
|
)
|
||||||
|
|
||||||
resultStatus = resultStatus.combine(context.checkReceiver(
|
resultStatus = resultStatus.combine(
|
||||||
|
context.checkReceiver(
|
||||||
candidateCall,
|
candidateCall,
|
||||||
candidateCall.resultingDescriptor.dispatchReceiverParameter, candidateCall.dispatchReceiver,
|
candidateCall.resultingDescriptor.dispatchReceiverParameter, candidateCall.dispatchReceiver,
|
||||||
candidateCall.explicitReceiverKind.isDispatchReceiver,
|
candidateCall.explicitReceiverKind.isDispatchReceiver,
|
||||||
// for the invocation 'foo(1)' where foo is a variable of function type we should mark 'foo' if there is unsafe call error
|
// for the invocation 'foo(1)' where foo is a variable of function type we should mark 'foo' if there is unsafe call error
|
||||||
implicitInvokeCheck = context.call is CallForImplicitInvoke,
|
implicitInvokeCheck = context.call is CallForImplicitInvoke,
|
||||||
isDispatchReceiver = true
|
isDispatchReceiver = true
|
||||||
))
|
)
|
||||||
|
)
|
||||||
|
|
||||||
if (!context.isDebuggerContext
|
if (!context.isDebuggerContext
|
||||||
&& candidateCall.dispatchReceiver != null
|
&& candidateCall.dispatchReceiver != null
|
||||||
// Do not report error if it's already reported when checked without receiver
|
// Do not report error if it's already reported when checked without receiver
|
||||||
&& context.isCandidateVisible(receiverArgument = Visibilities.ALWAYS_SUITABLE_RECEIVER, smartCastType = null)) {
|
&& context.isCandidateVisible(receiverArgument = Visibilities.ALWAYS_SUITABLE_RECEIVER, smartCastType = null)) {
|
||||||
resultStatus = resultStatus.combine(
|
resultStatus = resultStatus.combine(
|
||||||
context.checkVisibilityWithDispatchReceiver(
|
context.checkVisibilityWithDispatchReceiver(
|
||||||
candidateCall.dispatchReceiver, candidateCall.smartCastDispatchReceiverType))
|
candidateCall.dispatchReceiver, candidateCall.smartCastDispatchReceiverType
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return resultStatus
|
return resultStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkReceiver(
|
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkReceiver(
|
||||||
candidateCall: MutableResolvedCall<D>,
|
candidateCall: MutableResolvedCall<D>,
|
||||||
receiverParameter: ReceiverParameterDescriptor?,
|
receiverParameter: ReceiverParameterDescriptor?,
|
||||||
receiverArgument: ReceiverValue?,
|
receiverArgument: ReceiverValue?,
|
||||||
isExplicitReceiver: Boolean,
|
isExplicitReceiver: Boolean,
|
||||||
implicitInvokeCheck: Boolean,
|
implicitInvokeCheck: Boolean,
|
||||||
isDispatchReceiver: Boolean
|
isDispatchReceiver: Boolean
|
||||||
): ResolutionStatus {
|
): ResolutionStatus {
|
||||||
if (receiverParameter == null || receiverArgument == null) return SUCCESS
|
if (receiverParameter == null || receiverArgument == null) return SUCCESS
|
||||||
val candidateDescriptor = candidateCall.candidateDescriptor
|
val candidateDescriptor = candidateCall.candidateDescriptor
|
||||||
@@ -513,14 +514,15 @@ class CandidateResolver(
|
|||||||
val smartCastSubtypingResult = smartCastManager.getSmartCastReceiverResult(receiverArgument, expectedReceiverParameterType, this)
|
val smartCastSubtypingResult = smartCastManager.getSmartCastReceiverResult(receiverArgument, expectedReceiverParameterType, this)
|
||||||
if (smartCastSubtypingResult == null) {
|
if (smartCastSubtypingResult == null) {
|
||||||
tracing.wrongReceiverType(
|
tracing.wrongReceiverType(
|
||||||
trace, receiverParameter, receiverArgument,
|
trace, receiverParameter, receiverArgument,
|
||||||
this.replaceCallPosition(CallPosition.ExtensionReceiverPosition(candidateCall)))
|
this.replaceCallPosition(CallPosition.ExtensionReceiverPosition(candidateCall))
|
||||||
|
)
|
||||||
return OTHER_ERROR
|
return OTHER_ERROR
|
||||||
}
|
}
|
||||||
|
|
||||||
val notNullReceiverExpected = smartCastSubtypingResult != SmartCastManager.ReceiverSmartCastResult.OK
|
val notNullReceiverExpected = smartCastSubtypingResult != SmartCastManager.ReceiverSmartCastResult.OK
|
||||||
val smartCastNeeded =
|
val smartCastNeeded =
|
||||||
notNullReceiverExpected || !isCandidateVisibleOrExtensionReceiver(receiverArgument, null, isDispatchReceiver)
|
notNullReceiverExpected || !isCandidateVisibleOrExtensionReceiver(receiverArgument, null, isDispatchReceiver)
|
||||||
var reportUnsafeCall = false
|
var reportUnsafeCall = false
|
||||||
|
|
||||||
var nullableImplicitInvokeReceiver = false
|
var nullableImplicitInvokeReceiver = false
|
||||||
@@ -547,26 +549,23 @@ class CandidateResolver(
|
|||||||
if (dataFlowValue.immanentNullability.canBeNonNull()) {
|
if (dataFlowValue.immanentNullability.canBeNonNull()) {
|
||||||
expression?.let { trace.record(BindingContext.SMARTCAST_NULL, it) }
|
expression?.let { trace.record(BindingContext.SMARTCAST_NULL, it) }
|
||||||
}
|
}
|
||||||
}
|
} else if (!nullableImplicitInvokeReceiver && smartCastNeeded) {
|
||||||
else if (!nullableImplicitInvokeReceiver && smartCastNeeded) {
|
|
||||||
// Look if smart cast has some useful nullability info
|
// Look if smart cast has some useful nullability info
|
||||||
|
|
||||||
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(
|
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(
|
||||||
dataFlowValue, expectedReceiverParameterType,
|
dataFlowValue, expectedReceiverParameterType,
|
||||||
{ possibleSmartCast -> isCandidateVisibleOrExtensionReceiver(receiverArgument, possibleSmartCast, isDispatchReceiver) },
|
{ possibleSmartCast -> isCandidateVisibleOrExtensionReceiver(receiverArgument, possibleSmartCast, isDispatchReceiver) },
|
||||||
expression, this, candidateCall.call, recordExpressionType = true
|
expression, this, candidateCall.call, recordExpressionType = true
|
||||||
)
|
)
|
||||||
|
|
||||||
if (smartCastResult == null) {
|
if (smartCastResult == null) {
|
||||||
if (notNullReceiverExpected) {
|
if (notNullReceiverExpected) {
|
||||||
reportUnsafeCall = true
|
reportUnsafeCall = true
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (isDispatchReceiver) {
|
if (isDispatchReceiver) {
|
||||||
candidateCall.setSmartCastDispatchReceiverType(smartCastResult.resultType)
|
candidateCall.setSmartCastDispatchReceiverType(smartCastResult.resultType)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
candidateCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType)
|
candidateCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType)
|
||||||
}
|
}
|
||||||
if (!smartCastResult.isCorrect) {
|
if (!smartCastResult.isCorrect) {
|
||||||
@@ -589,11 +588,11 @@ class CandidateResolver(
|
|||||||
inner class ValueArgumentsCheckingResult(val status: ResolutionStatus, val argumentTypes: List<KotlinType>)
|
inner class ValueArgumentsCheckingResult(val status: ResolutionStatus, val argumentTypes: List<KotlinType>)
|
||||||
|
|
||||||
private fun CallCandidateResolutionContext<*>.checkGenericBoundsInAFunctionCall(
|
private fun CallCandidateResolutionContext<*>.checkGenericBoundsInAFunctionCall(
|
||||||
ktTypeArguments: List<KtTypeProjection>,
|
ktTypeArguments: List<KtTypeProjection>,
|
||||||
typeArguments: List<KotlinType>,
|
typeArguments: List<KotlinType>,
|
||||||
functionDescriptor: CallableDescriptor,
|
functionDescriptor: CallableDescriptor,
|
||||||
substitutor: TypeSubstitutor,
|
substitutor: TypeSubstitutor,
|
||||||
trace: BindingTrace
|
trace: BindingTrace
|
||||||
) {
|
) {
|
||||||
if (functionDescriptor is TypeAliasConstructorDescriptor) {
|
if (functionDescriptor is TypeAliasConstructorDescriptor) {
|
||||||
checkGenericBoundsInTypeAliasConstructorCall(ktTypeArguments, functionDescriptor, substitutor, trace)
|
checkGenericBoundsInTypeAliasConstructorCall(ktTypeArguments, functionDescriptor, substitutor, trace)
|
||||||
@@ -612,10 +611,10 @@ class CandidateResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class TypeAliasSingleStepExpansionReportStrategy(
|
private class TypeAliasSingleStepExpansionReportStrategy(
|
||||||
private val callElement: KtElement,
|
private val callElement: KtElement,
|
||||||
typeAlias: TypeAliasDescriptor,
|
typeAlias: TypeAliasDescriptor,
|
||||||
ktTypeArguments: List<KtTypeProjection>,
|
ktTypeArguments: List<KtTypeProjection>,
|
||||||
private val trace: BindingTrace
|
private val trace: BindingTrace
|
||||||
) : TypeAliasExpansionReportStrategy {
|
) : TypeAliasExpansionReportStrategy {
|
||||||
init {
|
init {
|
||||||
assert(!typeAlias.expandedType.isError) { "Incorrect type alias: $typeAlias" }
|
assert(!typeAlias.expandedType.isError) { "Incorrect type alias: $typeAlias" }
|
||||||
@@ -627,7 +626,11 @@ class CandidateResolver(
|
|||||||
// can't happen in single-step expansion
|
// can't happen in single-step expansion
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun conflictingProjection(typeAlias: TypeAliasDescriptor, typeParameter: TypeParameterDescriptor?, substitutedArgument: KotlinType) {
|
override fun conflictingProjection(
|
||||||
|
typeAlias: TypeAliasDescriptor,
|
||||||
|
typeParameter: TypeParameterDescriptor?,
|
||||||
|
substitutedArgument: KotlinType
|
||||||
|
) {
|
||||||
// can't happen in single-step expansion
|
// can't happen in single-step expansion
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -639,24 +642,28 @@ class CandidateResolver(
|
|||||||
// can't happen in single-step expansion
|
// can't happen in single-step expansion
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun boundsViolationInSubstitution(bound: KotlinType, unsubstitutedArgument: KotlinType, argument: KotlinType, typeParameter: TypeParameterDescriptor) {
|
override fun boundsViolationInSubstitution(
|
||||||
|
bound: KotlinType,
|
||||||
|
unsubstitutedArgument: KotlinType,
|
||||||
|
argument: KotlinType,
|
||||||
|
typeParameter: TypeParameterDescriptor
|
||||||
|
) {
|
||||||
val descriptorForUnsubstitutedArgument = unsubstitutedArgument.constructor.declarationDescriptor
|
val descriptorForUnsubstitutedArgument = unsubstitutedArgument.constructor.declarationDescriptor
|
||||||
val argumentElement = argumentsMapping[descriptorForUnsubstitutedArgument]
|
val argumentElement = argumentsMapping[descriptorForUnsubstitutedArgument]
|
||||||
val argumentTypeReferenceElement = argumentElement?.typeReference
|
val argumentTypeReferenceElement = argumentElement?.typeReference
|
||||||
if (argumentTypeReferenceElement != null) {
|
if (argumentTypeReferenceElement != null) {
|
||||||
trace.report(UPPER_BOUND_VIOLATED.on(argumentTypeReferenceElement, bound, argument))
|
trace.report(UPPER_BOUND_VIOLATED.on(argumentTypeReferenceElement, bound, argument))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(callElement, bound, argument, typeParameter))
|
trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(callElement, bound, argument, typeParameter))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CallCandidateResolutionContext<*>.checkGenericBoundsInTypeAliasConstructorCall(
|
private fun CallCandidateResolutionContext<*>.checkGenericBoundsInTypeAliasConstructorCall(
|
||||||
ktTypeArguments: List<KtTypeProjection>,
|
ktTypeArguments: List<KtTypeProjection>,
|
||||||
typeAliasConstructorDescriptor: TypeAliasConstructorDescriptor,
|
typeAliasConstructorDescriptor: TypeAliasConstructorDescriptor,
|
||||||
typeAliasParametersSubstitutor: TypeSubstitutor,
|
typeAliasParametersSubstitutor: TypeSubstitutor,
|
||||||
trace: BindingTrace
|
trace: BindingTrace
|
||||||
) {
|
) {
|
||||||
val substitutedType = typeAliasParametersSubstitutor.substitute(typeAliasConstructorDescriptor.returnType, Variance.INVARIANT)!!
|
val substitutedType = typeAliasParametersSubstitutor.substitute(typeAliasConstructorDescriptor.returnType, Variance.INVARIANT)!!
|
||||||
val boundsSubstitutor = TypeSubstitutor.create(substitutedType)
|
val boundsSubstitutor = TypeSubstitutor.create(substitutedType)
|
||||||
@@ -677,10 +684,10 @@ class CandidateResolver(
|
|||||||
|
|
||||||
|
|
||||||
private fun checkTypeInTypeAliasSubstitutionRec(
|
private fun checkTypeInTypeAliasSubstitutionRec(
|
||||||
reportStrategy: TypeAliasExpansionReportStrategy,
|
reportStrategy: TypeAliasExpansionReportStrategy,
|
||||||
unsubstitutedType: KotlinType,
|
unsubstitutedType: KotlinType,
|
||||||
typeAliasParametersSubstitutor: TypeSubstitutor,
|
typeAliasParametersSubstitutor: TypeSubstitutor,
|
||||||
boundsSubstitutor: TypeSubstitutor
|
boundsSubstitutor: TypeSubstitutor
|
||||||
) {
|
) {
|
||||||
// TODO refactor TypeResolver
|
// TODO refactor TypeResolver
|
||||||
val typeParameters = unsubstitutedType.constructor.parameters
|
val typeParameters = unsubstitutedType.constructor.parameters
|
||||||
@@ -688,30 +695,41 @@ class CandidateResolver(
|
|||||||
// TODO do not perform substitution for type arguments multiple times
|
// TODO do not perform substitution for type arguments multiple times
|
||||||
val substitutedTypeArguments = typeAliasParametersSubstitutor.safeSubstitute(unsubstitutedType, Variance.INVARIANT).arguments
|
val substitutedTypeArguments = typeAliasParametersSubstitutor.safeSubstitute(unsubstitutedType, Variance.INVARIANT).arguments
|
||||||
|
|
||||||
for (i in 0 ..Math.min(typeParameters.size, substitutedTypeArguments.size) - 1) {
|
for (i in 0..Math.min(typeParameters.size, substitutedTypeArguments.size) - 1) {
|
||||||
val substitutedTypeProjection = substitutedTypeArguments[i]
|
val substitutedTypeProjection = substitutedTypeArguments[i]
|
||||||
if (substitutedTypeProjection.isStarProjection) continue
|
if (substitutedTypeProjection.isStarProjection) continue
|
||||||
|
|
||||||
val typeParameter = typeParameters[i]
|
val typeParameter = typeParameters[i]
|
||||||
val substitutedTypeArgument = substitutedTypeProjection.type
|
val substitutedTypeArgument = substitutedTypeProjection.type
|
||||||
val unsubstitutedTypeArgument = unsubstitutedType.arguments[i].type
|
val unsubstitutedTypeArgument = unsubstitutedType.arguments[i].type
|
||||||
DescriptorResolver.checkBoundsInTypeAlias(reportStrategy, unsubstitutedTypeArgument, substitutedTypeArgument, typeParameter, boundsSubstitutor)
|
DescriptorResolver.checkBoundsInTypeAlias(
|
||||||
|
reportStrategy,
|
||||||
|
unsubstitutedTypeArgument,
|
||||||
|
substitutedTypeArgument,
|
||||||
|
typeParameter,
|
||||||
|
boundsSubstitutor
|
||||||
|
)
|
||||||
|
|
||||||
checkTypeInTypeAliasSubstitutionRec(reportStrategy, unsubstitutedTypeArgument, typeAliasParametersSubstitutor, boundsSubstitutor)
|
checkTypeInTypeAliasSubstitutionRec(
|
||||||
|
reportStrategy,
|
||||||
|
unsubstitutedTypeArgument,
|
||||||
|
typeAliasParametersSubstitutor,
|
||||||
|
boundsSubstitutor
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.shouldContinue() =
|
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.shouldContinue() =
|
||||||
candidateResolveMode == CandidateResolveMode.FULLY || candidateCall.status.possibleTransformToSuccess()
|
candidateResolveMode == CandidateResolveMode.FULLY || candidateCall.status.possibleTransformToSuccess()
|
||||||
|
|
||||||
private inline fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.check(
|
private inline fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.check(
|
||||||
crossinline checker: CallCandidateResolutionContext<D>.() -> Unit
|
crossinline checker: CallCandidateResolutionContext<D>.() -> Unit
|
||||||
) {
|
) {
|
||||||
if (shouldContinue()) checker() else candidateCall.addRemainingTasks { checker() }
|
if (shouldContinue()) checker() else candidateCall.addRemainingTasks { checker() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkAndReport(
|
private inline fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkAndReport(
|
||||||
crossinline checker: CallCandidateResolutionContext<D>.() -> ResolutionStatus
|
crossinline checker: CallCandidateResolutionContext<D>.() -> ResolutionStatus
|
||||||
) {
|
) {
|
||||||
check {
|
check {
|
||||||
candidateCall.addStatus(checker())
|
candidateCall.addStatus(checker())
|
||||||
|
|||||||
+38
-22
@@ -38,10 +38,10 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
|||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
class DiagnosticReporterByTrackingStrategy(
|
class DiagnosticReporterByTrackingStrategy(
|
||||||
val constantExpressionEvaluator: ConstantExpressionEvaluator,
|
val constantExpressionEvaluator: ConstantExpressionEvaluator,
|
||||||
val context: BasicCallResolutionContext,
|
val context: BasicCallResolutionContext,
|
||||||
val psiKotlinCall: PSIKotlinCall
|
val psiKotlinCall: PSIKotlinCall
|
||||||
): DiagnosticReporter {
|
) : DiagnosticReporter {
|
||||||
private val trace = context.trace as TrackingBindingTrace
|
private val trace = context.trace as TrackingBindingTrace
|
||||||
private val tracingStrategy: TracingStrategy get() = psiKotlinCall.tracingStrategy
|
private val tracingStrategy: TracingStrategy get() = psiKotlinCall.tracingStrategy
|
||||||
private val call: Call get() = psiKotlinCall.psiCall
|
private val call: Call get() = psiKotlinCall.psiCall
|
||||||
@@ -53,7 +53,10 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
override fun onCall(diagnostic: KotlinCallDiagnostic) {
|
override fun onCall(diagnostic: KotlinCallDiagnostic) {
|
||||||
when (diagnostic.javaClass) {
|
when (diagnostic.javaClass) {
|
||||||
VisibilityError::class.java -> tracingStrategy.invisibleMember(trace, (diagnostic as VisibilityError).invisibleMember)
|
VisibilityError::class.java -> tracingStrategy.invisibleMember(trace, (diagnostic as VisibilityError).invisibleMember)
|
||||||
NoValueForParameter::class.java -> tracingStrategy.noValueForParameter(trace, (diagnostic as NoValueForParameter).parameterDescriptor)
|
NoValueForParameter::class.java -> tracingStrategy.noValueForParameter(
|
||||||
|
trace,
|
||||||
|
(diagnostic as NoValueForParameter).parameterDescriptor
|
||||||
|
)
|
||||||
InstantiationOfAbstractClass::class.java -> tracingStrategy.instantiationOfAbstractClass(trace)
|
InstantiationOfAbstractClass::class.java -> tracingStrategy.instantiationOfAbstractClass(trace)
|
||||||
AbstractSuperCall::class.java -> tracingStrategy.abstractSuperCall(trace)
|
AbstractSuperCall::class.java -> tracingStrategy.abstractSuperCall(trace)
|
||||||
}
|
}
|
||||||
@@ -62,10 +65,10 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
override fun onTypeArguments(diagnostic: KotlinCallDiagnostic) {
|
override fun onTypeArguments(diagnostic: KotlinCallDiagnostic) {
|
||||||
val psiCallElement = psiKotlinCall.psiCall.callElement
|
val psiCallElement = psiKotlinCall.psiCall.callElement
|
||||||
val reportElement =
|
val reportElement =
|
||||||
if (psiCallElement is KtCallExpression)
|
if (psiCallElement is KtCallExpression)
|
||||||
psiCallElement.typeArgumentList ?: psiCallElement.calleeExpression ?: psiCallElement
|
psiCallElement.typeArgumentList ?: psiCallElement.calleeExpression ?: psiCallElement
|
||||||
else
|
else
|
||||||
psiCallElement
|
psiCallElement
|
||||||
|
|
||||||
when (diagnostic) {
|
when (diagnostic) {
|
||||||
is WrongCountOfTypeArguments -> {
|
is WrongCountOfTypeArguments -> {
|
||||||
@@ -123,8 +126,8 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onCallArgumentName(callArgument: KotlinCallArgument, diagnostic: KotlinCallDiagnostic) {
|
override fun onCallArgumentName(callArgument: KotlinCallArgument, diagnostic: KotlinCallDiagnostic) {
|
||||||
val nameReference = callArgument.psiCallArgument.valueArgument.getArgumentName()?.referenceExpression ?:
|
val nameReference = callArgument.psiCallArgument.valueArgument.getArgumentName()?.referenceExpression
|
||||||
error("Argument name should be not null for argument: $callArgument")
|
?: error("Argument name should be not null for argument: $callArgument")
|
||||||
when (diagnostic.javaClass) {
|
when (diagnostic.javaClass) {
|
||||||
NamedArgumentReference::class.java -> {
|
NamedArgumentReference::class.java -> {
|
||||||
trace.record(BindingContext.REFERENCE_TARGET, nameReference, (diagnostic as NamedArgumentReference).parameterDescriptor)
|
trace.record(BindingContext.REFERENCE_TARGET, nameReference, (diagnostic as NamedArgumentReference).parameterDescriptor)
|
||||||
@@ -133,10 +136,12 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
NameForAmbiguousParameter::class.java -> trace.report(NAME_FOR_AMBIGUOUS_PARAMETER.on(nameReference))
|
NameForAmbiguousParameter::class.java -> trace.report(NAME_FOR_AMBIGUOUS_PARAMETER.on(nameReference))
|
||||||
NameNotFound::class.java -> trace.report(NAMED_PARAMETER_NOT_FOUND.on(nameReference, nameReference))
|
NameNotFound::class.java -> trace.report(NAMED_PARAMETER_NOT_FOUND.on(nameReference, nameReference))
|
||||||
|
|
||||||
NamedArgumentNotAllowed::class.java -> trace.report(NAMED_ARGUMENTS_NOT_ALLOWED.on(
|
NamedArgumentNotAllowed::class.java -> trace.report(
|
||||||
|
NAMED_ARGUMENTS_NOT_ALLOWED.on(
|
||||||
nameReference,
|
nameReference,
|
||||||
if ((diagnostic as NamedArgumentNotAllowed).descriptor is FunctionInvokeDescriptor) INVOKE_ON_FUNCTION_TYPE else NON_KOTLIN_FUNCTION
|
if ((diagnostic as NamedArgumentNotAllowed).descriptor is FunctionInvokeDescriptor) INVOKE_ON_FUNCTION_TYPE else NON_KOTLIN_FUNCTION
|
||||||
))
|
)
|
||||||
|
)
|
||||||
ArgumentPassedTwice::class.java -> trace.report(ARGUMENT_PASSED_TWICE.on(nameReference))
|
ArgumentPassedTwice::class.java -> trace.report(ARGUMENT_PASSED_TWICE.on(nameReference))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -156,23 +161,29 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
is ExpressionKotlinCallArgumentImpl -> {
|
is ExpressionKotlinCallArgumentImpl -> {
|
||||||
trace.markAsReported()
|
trace.markAsReported()
|
||||||
val context = context.replaceDataFlowInfo(expressionArgument.dataFlowInfoBeforeThisArgument)
|
val context = context.replaceDataFlowInfo(expressionArgument.dataFlowInfoBeforeThisArgument)
|
||||||
val argumentExpression = KtPsiUtil.getLastElementDeparenthesized(expressionArgument.valueArgument.getArgumentExpression (), context.statementFilter)
|
val argumentExpression = KtPsiUtil.getLastElementDeparenthesized(
|
||||||
|
expressionArgument.valueArgument.getArgumentExpression(),
|
||||||
|
context.statementFilter
|
||||||
|
)
|
||||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expressionArgument.receiver.receiverValue, context)
|
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expressionArgument.receiver.receiverValue, context)
|
||||||
SmartCastManager.checkAndRecordPossibleCast(
|
SmartCastManager.checkAndRecordPossibleCast(
|
||||||
dataFlowValue, smartCastDiagnostic.smartCastType, argumentExpression, context, call,
|
dataFlowValue, smartCastDiagnostic.smartCastType, argumentExpression, context, call,
|
||||||
recordExpressionType = true)
|
recordExpressionType = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
is ReceiverExpressionKotlinCallArgument -> {
|
is ReceiverExpressionKotlinCallArgument -> {
|
||||||
trace.markAsReported()
|
trace.markAsReported()
|
||||||
val receiverValue = expressionArgument.receiver.receiverValue
|
val receiverValue = expressionArgument.receiver.receiverValue
|
||||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, context)
|
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, context)
|
||||||
SmartCastManager.checkAndRecordPossibleCast(
|
SmartCastManager.checkAndRecordPossibleCast(
|
||||||
dataFlowValue, smartCastDiagnostic.smartCastType, (receiverValue as? ExpressionReceiver)?.expression, context, call,
|
dataFlowValue, smartCastDiagnostic.smartCastType, (receiverValue as? ExpressionReceiver)?.expression, context, call,
|
||||||
recordExpressionType = true)
|
recordExpressionType = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
val resolvedCall = smartCastDiagnostic.kotlinCall?.psiKotlinCall?.psiCall?.getResolvedCall(trace.bindingContext) as? NewResolvedCallImpl<*>
|
val resolvedCall =
|
||||||
|
smartCastDiagnostic.kotlinCall?.psiKotlinCall?.psiCall?.getResolvedCall(trace.bindingContext) as? NewResolvedCallImpl<*>
|
||||||
if (resolvedCall != null && smartCastResult != null) {
|
if (resolvedCall != null && smartCastResult != null) {
|
||||||
if (resolvedCall.extensionReceiver == expressionArgument.receiver.receiverValue) {
|
if (resolvedCall.extensionReceiver == expressionArgument.receiver.receiverValue) {
|
||||||
resolvedCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType)
|
resolvedCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType)
|
||||||
@@ -194,7 +205,7 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
val constraintError = diagnostic as NewConstraintError
|
val constraintError = diagnostic as NewConstraintError
|
||||||
val position = constraintError.position.from
|
val position = constraintError.position.from
|
||||||
val argument = (position as? ArgumentConstraintPosition)?.argument
|
val argument = (position as? ArgumentConstraintPosition)?.argument
|
||||||
?: (position as? ReceiverConstraintPosition)?.argument
|
?: (position as? ReceiverConstraintPosition)?.argument
|
||||||
argument?.let {
|
argument?.let {
|
||||||
val expression = it.psiExpression ?: return
|
val expression = it.psiExpression ?: return
|
||||||
val deparenthesized = KtPsiUtil.safeDeparenthesize(expression)
|
val deparenthesized = KtPsiUtil.safeDeparenthesize(expression)
|
||||||
@@ -218,7 +229,12 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
val capturedError = diagnostic as CapturedTypeFromSubtyping
|
val capturedError = diagnostic as CapturedTypeFromSubtyping
|
||||||
(capturedError.position as? ArgumentConstraintPosition)?.let {
|
(capturedError.position as? ArgumentConstraintPosition)?.let {
|
||||||
val expression = it.argument.psiExpression ?: return
|
val expression = it.argument.psiExpression ?: return
|
||||||
trace.report(NEW_INFERENCE_ERROR.on(expression, "Capture type from subtyping ${capturedError.constraintType} for variable ${capturedError.typeVariable}"))
|
trace.report(
|
||||||
|
NEW_INFERENCE_ERROR.on(
|
||||||
|
expression,
|
||||||
|
"Capture type from subtyping ${capturedError.constraintType} for variable ${capturedError.typeVariable}"
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,7 +245,7 @@ class DiagnosticReporterByTrackingStrategy(
|
|||||||
val builtIns = context.scope.ownerDescriptor.builtIns
|
val builtIns = context.scope.ownerDescriptor.builtIns
|
||||||
val constantValue = constantExpressionEvaluator.evaluateToConstantValue(expression, trace, context.expectedType)
|
val constantValue = constantExpressionEvaluator.evaluateToConstantValue(expression, trace, context.expectedType)
|
||||||
val hasConstantTypeError = CompileTimeConstantChecker(context, builtIns, true)
|
val hasConstantTypeError = CompileTimeConstantChecker(context, builtIns, true)
|
||||||
.checkConstantExpressionType(constantValue, expression, constraintError.upperType)
|
.checkConstantExpressionType(constantValue, expression, constraintError.upperType)
|
||||||
if (hasConstantTypeError) return true
|
if (hasConstantTypeError) return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
+105
-95
@@ -66,9 +66,9 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
|||||||
private val SPECIAL_FUNCTION_NAMES = ResolveConstruct.values().map { it.specialFunctionName }.toSet()
|
private val SPECIAL_FUNCTION_NAMES = ResolveConstruct.values().map { it.specialFunctionName }.toSet()
|
||||||
|
|
||||||
class GenericCandidateResolver(
|
class GenericCandidateResolver(
|
||||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||||
private val coroutineInferenceSupport: CoroutineInferenceSupport,
|
private val coroutineInferenceSupport: CoroutineInferenceSupport,
|
||||||
private val languageVersionSettings: LanguageVersionSettings
|
private val languageVersionSettings: LanguageVersionSettings
|
||||||
) {
|
) {
|
||||||
fun <D : CallableDescriptor> inferTypeArguments(context: CallCandidateResolutionContext<D>): ResolutionStatus {
|
fun <D : CallableDescriptor> inferTypeArguments(context: CallCandidateResolutionContext<D>): ResolutionStatus {
|
||||||
val candidateCall = context.candidateCall
|
val candidateCall = context.candidateCall
|
||||||
@@ -90,7 +90,7 @@ class GenericCandidateResolver(
|
|||||||
// and throw the results away
|
// and throw the results away
|
||||||
// We'll type check the arguments later, with the inferred types expected
|
// We'll type check the arguments later, with the inferred types expected
|
||||||
addConstraintForValueArgument(
|
addConstraintForValueArgument(
|
||||||
valueArgument, valueParameterDescriptor, substituteDontCare, builder, context, SHAPE_FUNCTION_ARGUMENTS
|
valueArgument, valueParameterDescriptor, substituteDontCare, builder, context, SHAPE_FUNCTION_ARGUMENTS
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -114,9 +114,9 @@ class GenericCandidateResolver(
|
|||||||
receiverType = updateResultTypeForSmartCasts(receiverType, receiverArgument.expression, context)
|
receiverType = updateResultTypeForSmartCasts(receiverType, receiverArgument.expression, context)
|
||||||
}
|
}
|
||||||
builder.addSubtypeConstraint(
|
builder.addSubtypeConstraint(
|
||||||
receiverType,
|
receiverType,
|
||||||
builder.compositeSubstitutor().substitute(receiverParameter.type, Variance.INVARIANT),
|
builder.compositeSubstitutor().substitute(receiverParameter.type, Variance.INVARIANT),
|
||||||
RECEIVER_POSITION.position()
|
RECEIVER_POSITION.position()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,9 +133,9 @@ class GenericCandidateResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun ConstraintSystem.Builder.typeInSystem(call: Call, type: KotlinType?): KotlinType? =
|
private fun ConstraintSystem.Builder.typeInSystem(call: Call, type: KotlinType?): KotlinType? =
|
||||||
type?.let {
|
type?.let {
|
||||||
typeVariableSubstitutors[call.toHandle()]?.substitute(it, Variance.INVARIANT)
|
typeVariableSubstitutors[call.toHandle()]?.substitute(it, Variance.INVARIANT)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FunctionDescriptor.isFunctionForExpectTypeFromCastFeature(): Boolean {
|
private fun FunctionDescriptor.isFunctionForExpectTypeFromCastFeature(): Boolean {
|
||||||
val typeParameter = typeParameters.singleOrNull() ?: return false
|
val typeParameter = typeParameters.singleOrNull() ?: return false
|
||||||
@@ -153,8 +153,8 @@ class GenericCandidateResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun addExpectedTypeForExplicitCast(
|
private fun addExpectedTypeForExplicitCast(
|
||||||
context: CallCandidateResolutionContext<*>,
|
context: CallCandidateResolutionContext<*>,
|
||||||
builder: ConstraintSystem.Builder
|
builder: ConstraintSystem.Builder
|
||||||
) {
|
) {
|
||||||
if (!languageVersionSettings.supportsFeature(LanguageFeature.ExpectedTypeFromCast)) return
|
if (!languageVersionSettings.supportsFeature(LanguageFeature.ExpectedTypeFromCast)) return
|
||||||
|
|
||||||
@@ -185,8 +185,7 @@ class GenericCandidateResolver(
|
|||||||
val targetExpression = if (possibleQualifiedExpression is KtQualifiedExpression) {
|
val targetExpression = if (possibleQualifiedExpression is KtQualifiedExpression) {
|
||||||
if (possibleQualifiedExpression.selectorExpression != callExpression) return null
|
if (possibleQualifiedExpression.selectorExpression != callExpression) return null
|
||||||
possibleQualifiedExpression
|
possibleQualifiedExpression
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
callExpression
|
callExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -207,7 +206,7 @@ class GenericCandidateResolver(
|
|||||||
|
|
||||||
val boundsSubstitutor = TypeSubstitutor.create(type)
|
val boundsSubstitutor = TypeSubstitutor.create(type)
|
||||||
|
|
||||||
type.arguments.forEachIndexed forEachArgument@{ i, typeProjection ->
|
type.arguments.forEachIndexed forEachArgument@ { i, typeProjection ->
|
||||||
if (typeProjection.isStarProjection) return@forEachArgument // continue
|
if (typeProjection.isStarProjection) return@forEachArgument // continue
|
||||||
|
|
||||||
val typeParameter = typeConstructor.parameters[i]
|
val typeParameter = typeConstructor.parameters[i]
|
||||||
@@ -218,10 +217,10 @@ class GenericCandidateResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun addValidityConstraintsForTypeArgument(
|
private fun addValidityConstraintsForTypeArgument(
|
||||||
builder: ConstraintSystem.Builder,
|
builder: ConstraintSystem.Builder,
|
||||||
substitutedArgument: TypeProjection,
|
substitutedArgument: TypeProjection,
|
||||||
typeParameter: TypeParameterDescriptor,
|
typeParameter: TypeParameterDescriptor,
|
||||||
boundsSubstitutor: TypeSubstitutor
|
boundsSubstitutor: TypeSubstitutor
|
||||||
) {
|
) {
|
||||||
val substitutedType = substitutedArgument.type
|
val substitutedType = substitutedArgument.type
|
||||||
for (upperBound in typeParameter.upperBounds) {
|
for (upperBound in typeParameter.upperBounds) {
|
||||||
@@ -247,12 +246,12 @@ class GenericCandidateResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun addConstraintForValueArgument(
|
private fun addConstraintForValueArgument(
|
||||||
valueArgument: ValueArgument,
|
valueArgument: ValueArgument,
|
||||||
valueParameterDescriptor: ValueParameterDescriptor,
|
valueParameterDescriptor: ValueParameterDescriptor,
|
||||||
substitutor: TypeSubstitutor,
|
substitutor: TypeSubstitutor,
|
||||||
builder: ConstraintSystem.Builder,
|
builder: ConstraintSystem.Builder,
|
||||||
context: CallCandidateResolutionContext<*>,
|
context: CallCandidateResolutionContext<*>,
|
||||||
resolveFunctionArgumentBodies: ResolveArgumentsMode
|
resolveFunctionArgumentBodies: ResolveArgumentsMode
|
||||||
) {
|
) {
|
||||||
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
|
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
|
||||||
val argumentExpression = valueArgument.getArgumentExpression()
|
val argumentExpression = valueArgument.getArgumentExpression()
|
||||||
@@ -268,23 +267,24 @@ class GenericCandidateResolver(
|
|||||||
|
|
||||||
if (addConstraintForNestedCall(argumentExpression, constraintPosition, builder, newContext, effectiveExpectedType)) return
|
if (addConstraintForNestedCall(argumentExpression, constraintPosition, builder, newContext, effectiveExpectedType)) return
|
||||||
|
|
||||||
val type = updateResultTypeForSmartCasts(typeInfoForCall.type, argumentExpression, context.replaceDataFlowInfo(dataFlowInfoForArgument))
|
val type =
|
||||||
|
updateResultTypeForSmartCasts(typeInfoForCall.type, argumentExpression, context.replaceDataFlowInfo(dataFlowInfoForArgument))
|
||||||
|
|
||||||
if (argumentExpression is KtCallableReferenceExpression && type == null) return
|
if (argumentExpression is KtCallableReferenceExpression && type == null) return
|
||||||
|
|
||||||
builder.addSubtypeConstraint(
|
builder.addSubtypeConstraint(
|
||||||
type,
|
type,
|
||||||
builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT),
|
builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT),
|
||||||
constraintPosition
|
constraintPosition
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addConstraintForNestedCall(
|
private fun addConstraintForNestedCall(
|
||||||
argumentExpression: KtExpression?,
|
argumentExpression: KtExpression?,
|
||||||
constraintPosition: ConstraintPosition,
|
constraintPosition: ConstraintPosition,
|
||||||
builder: ConstraintSystem.Builder,
|
builder: ConstraintSystem.Builder,
|
||||||
context: CallCandidateResolutionContext<*>,
|
context: CallCandidateResolutionContext<*>,
|
||||||
effectiveExpectedType: KotlinType
|
effectiveExpectedType: KotlinType
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val resolutionResults = getResolutionResultsCachedData(argumentExpression, context)?.resolutionResults
|
val resolutionResults = getResolutionResultsCachedData(argumentExpression, context)?.resolutionResults
|
||||||
if (resolutionResults == null || !resolutionResults.isSingleResult) return false
|
if (resolutionResults == null || !resolutionResults.isSingleResult) return false
|
||||||
@@ -312,18 +312,18 @@ class GenericCandidateResolver(
|
|||||||
val argumentExpressionType = nestedCall.makeNullableTypeIfSafeReceiver(candidateWithFreshVariables.returnType, context)
|
val argumentExpressionType = nestedCall.makeNullableTypeIfSafeReceiver(candidateWithFreshVariables.returnType, context)
|
||||||
|
|
||||||
builder.addSubtypeConstraint(
|
builder.addSubtypeConstraint(
|
||||||
argumentExpressionType,
|
argumentExpressionType,
|
||||||
builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT),
|
builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT),
|
||||||
constraintPosition
|
constraintPosition
|
||||||
)
|
)
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateResultTypeForSmartCasts(
|
private fun updateResultTypeForSmartCasts(
|
||||||
type: KotlinType?,
|
type: KotlinType?,
|
||||||
argumentExpression: KtExpression?,
|
argumentExpression: KtExpression?,
|
||||||
context: ResolutionContext<*>
|
context: ResolutionContext<*>
|
||||||
): KotlinType? {
|
): KotlinType? {
|
||||||
val deparenthesizedArgument = KtPsiUtil.getLastElementDeparenthesized(argumentExpression, context.statementFilter)
|
val deparenthesizedArgument = KtPsiUtil.getLastElementDeparenthesized(argumentExpression, context.statementFilter)
|
||||||
if (deparenthesizedArgument == null || type == null) return type
|
if (deparenthesizedArgument == null || type == null) return type
|
||||||
@@ -345,7 +345,8 @@ class GenericCandidateResolver(
|
|||||||
// to inconsistency and errors in inference. See definition of `effectiveExpectedTypeInSystem` in `addConstraintForFunctionLiteralArgument`
|
// to inconsistency and errors in inference. See definition of `effectiveExpectedTypeInSystem` in `addConstraintForFunctionLiteralArgument`
|
||||||
val newContext = if (resolvedCall is VariableAsFunctionResolvedCall) {
|
val newContext = if (resolvedCall is VariableAsFunctionResolvedCall) {
|
||||||
CallCandidateResolutionContext.create(
|
CallCandidateResolutionContext.create(
|
||||||
resolvedCall, context, context.trace, context.tracing, resolvedCall.functionCall.call, context.candidateResolveMode)
|
resolvedCall, context, context.trace, context.tracing, resolvedCall.functionCall.call, context.candidateResolveMode
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
context
|
context
|
||||||
}
|
}
|
||||||
@@ -356,8 +357,10 @@ class GenericCandidateResolver(
|
|||||||
for (valueArgument in resolvedValueArgument.arguments) {
|
for (valueArgument in resolvedValueArgument.arguments) {
|
||||||
valueArgument.getArgumentExpression()?.let { argumentExpression ->
|
valueArgument.getArgumentExpression()?.let { argumentExpression ->
|
||||||
ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, newContext)?.let { functionLiteral ->
|
ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, newContext)?.let { functionLiteral ->
|
||||||
addConstraintForFunctionLiteralArgument(functionLiteral, valueArgument, valueParameterDescriptor, constraintSystem, newContext,
|
addConstraintForFunctionLiteralArgument(
|
||||||
resolvedCall.candidateDescriptor.returnType)
|
functionLiteral, valueArgument, valueParameterDescriptor, constraintSystem, newContext,
|
||||||
|
resolvedCall.candidateDescriptor.returnType
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// as inference for callable references depends on expected type,
|
// as inference for callable references depends on expected type,
|
||||||
@@ -367,20 +370,21 @@ class GenericCandidateResolver(
|
|||||||
// For example, type info for arguments is needed before call will be completed (See ControlStructureTypingVisitor.visitIfExpression)
|
// For example, type info for arguments is needed before call will be completed (See ControlStructureTypingVisitor.visitIfExpression)
|
||||||
val temporaryContextForCall = if (resolvedCall.candidateDescriptor.name in SPECIAL_FUNCTION_NAMES) {
|
val temporaryContextForCall = if (resolvedCall.candidateDescriptor.name in SPECIAL_FUNCTION_NAMES) {
|
||||||
newContext
|
newContext
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val temporaryBindingTrace = TemporaryBindingTrace.create(
|
val temporaryBindingTrace = TemporaryBindingTrace.create(
|
||||||
newContext.trace, "Trace to complete argument for call that might be not resulting call")
|
newContext.trace, "Trace to complete argument for call that might be not resulting call"
|
||||||
|
)
|
||||||
newContext.replaceBindingTrace(temporaryBindingTrace)
|
newContext.replaceBindingTrace(temporaryBindingTrace)
|
||||||
}
|
}
|
||||||
|
|
||||||
ArgumentTypeResolver.getCallableReferenceExpressionIfAny(argumentExpression, newContext)?.let { callableReference ->
|
ArgumentTypeResolver.getCallableReferenceExpressionIfAny(argumentExpression, newContext)?.let { callableReference ->
|
||||||
addConstraintForCallableReference(
|
addConstraintForCallableReference(
|
||||||
callableReference,
|
callableReference,
|
||||||
valueArgument,
|
valueArgument,
|
||||||
valueParameterDescriptor,
|
valueParameterDescriptor,
|
||||||
constraintSystem,
|
constraintSystem,
|
||||||
temporaryContextForCall)
|
temporaryContextForCall
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -395,24 +399,24 @@ class GenericCandidateResolver(
|
|||||||
// and we have some expected type Type, we can expected from literal to return Type
|
// and we have some expected type Type, we can expected from literal to return Type
|
||||||
// Otherwise we do not care about literal's exact return type
|
// Otherwise we do not care about literal's exact return type
|
||||||
private fun estimateLiteralReturnType(
|
private fun estimateLiteralReturnType(
|
||||||
context: CallCandidateResolutionContext<*>,
|
context: CallCandidateResolutionContext<*>,
|
||||||
literalExpectedType: KotlinType,
|
literalExpectedType: KotlinType,
|
||||||
ownerReturnType: KotlinType?
|
ownerReturnType: KotlinType?
|
||||||
) = if (!TypeUtils.noExpectedType(context.expectedType) &&
|
) = if (!TypeUtils.noExpectedType(context.expectedType) &&
|
||||||
ownerReturnType != null &&
|
ownerReturnType != null &&
|
||||||
TypeUtils.isTypeParameter(ownerReturnType) &&
|
TypeUtils.isTypeParameter(ownerReturnType) &&
|
||||||
literalExpectedType.isFunctionTypeOrSubtype &&
|
literalExpectedType.isFunctionTypeOrSubtype &&
|
||||||
getReturnTypeForCallable(literalExpectedType) == ownerReturnType)
|
getReturnTypeForCallable(literalExpectedType) == ownerReturnType)
|
||||||
context.expectedType
|
context.expectedType
|
||||||
else DONT_CARE
|
else DONT_CARE
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> addConstraintForFunctionLiteralArgument(
|
private fun <D : CallableDescriptor> addConstraintForFunctionLiteralArgument(
|
||||||
functionLiteral: KtFunction,
|
functionLiteral: KtFunction,
|
||||||
valueArgument: ValueArgument,
|
valueArgument: ValueArgument,
|
||||||
valueParameterDescriptor: ValueParameterDescriptor,
|
valueParameterDescriptor: ValueParameterDescriptor,
|
||||||
constraintSystem: ConstraintSystem.Builder,
|
constraintSystem: ConstraintSystem.Builder,
|
||||||
context: CallCandidateResolutionContext<D>,
|
context: CallCandidateResolutionContext<D>,
|
||||||
argumentOwnerReturnType: KotlinType?
|
argumentOwnerReturnType: KotlinType?
|
||||||
) {
|
) {
|
||||||
val argumentExpression = valueArgument.getArgumentExpression() ?: return
|
val argumentExpression = valueArgument.getArgumentExpression() ?: return
|
||||||
|
|
||||||
@@ -439,24 +443,27 @@ class GenericCandidateResolver(
|
|||||||
val dataFlowInfoForArgument = dataFlowInfoForArguments.getInfo(valueArgument)
|
val dataFlowInfoForArgument = dataFlowInfoForArguments.getInfo(valueArgument)
|
||||||
|
|
||||||
val effectiveExpectedTypeInSystem =
|
val effectiveExpectedTypeInSystem =
|
||||||
constraintSystem.typeVariableSubstitutors[context.call.toHandle()]?.substitute(effectiveExpectedType, Variance.INVARIANT)
|
constraintSystem.typeVariableSubstitutors[context.call.toHandle()]?.substitute(effectiveExpectedType, Variance.INVARIANT)
|
||||||
|
|
||||||
//todo analyze function literal body once in 'dependent' mode, then complete it with respect to expected type
|
//todo analyze function literal body once in 'dependent' mode, then complete it with respect to expected type
|
||||||
val hasExpectedReturnType = !hasUnknownReturnType(expectedType)
|
val hasExpectedReturnType = !hasUnknownReturnType(expectedType)
|
||||||
val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
|
val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
|
||||||
if (hasExpectedReturnType) {
|
if (hasExpectedReturnType) {
|
||||||
val temporaryToResolveFunctionLiteral = TemporaryTraceAndCache.create(
|
val temporaryToResolveFunctionLiteral = TemporaryTraceAndCache.create(
|
||||||
context, "trace to resolve function literal with expected return type", argumentExpression)
|
context, "trace to resolve function literal with expected return type", argumentExpression
|
||||||
|
)
|
||||||
|
|
||||||
val statementExpression = KtPsiUtil.getExpressionOrLastStatementInBlock(functionLiteral.bodyExpression) ?: return
|
val statementExpression = KtPsiUtil.getExpressionOrLastStatementInBlock(functionLiteral.bodyExpression) ?: return
|
||||||
val mismatch = BooleanArray(1)
|
val mismatch = BooleanArray(1)
|
||||||
val errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch(
|
val errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch(
|
||||||
temporaryToResolveFunctionLiteral.trace, statementExpression, mismatch)
|
temporaryToResolveFunctionLiteral.trace, statementExpression, mismatch
|
||||||
|
)
|
||||||
val newContext = context.replaceBindingTrace(errorInterceptingTrace).replaceExpectedType(expectedType)
|
val newContext = context.replaceBindingTrace(errorInterceptingTrace).replaceExpectedType(expectedType)
|
||||||
.replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache)
|
.replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache)
|
||||||
.replaceContextDependency(INDEPENDENT)
|
.replaceContextDependency(INDEPENDENT)
|
||||||
val type = argumentTypeResolver.getFunctionLiteralTypeInfo(
|
val type = argumentTypeResolver.getFunctionLiteralTypeInfo(
|
||||||
argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).type
|
argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS
|
||||||
|
).type
|
||||||
if (!mismatch[0]) {
|
if (!mismatch[0]) {
|
||||||
constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position)
|
constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position)
|
||||||
temporaryToResolveFunctionLiteral.commit()
|
temporaryToResolveFunctionLiteral.commit()
|
||||||
@@ -466,36 +473,38 @@ class GenericCandidateResolver(
|
|||||||
val estimatedReturnType = estimateLiteralReturnType(context, effectiveExpectedType, argumentOwnerReturnType)
|
val estimatedReturnType = estimateLiteralReturnType(context, effectiveExpectedType, argumentOwnerReturnType)
|
||||||
val expectedTypeWithEstimatedReturnType = replaceReturnTypeForCallable(expectedType, estimatedReturnType)
|
val expectedTypeWithEstimatedReturnType = replaceReturnTypeForCallable(expectedType, estimatedReturnType)
|
||||||
val newContext = context.replaceExpectedType(expectedTypeWithEstimatedReturnType).replaceDataFlowInfo(dataFlowInfoForArgument)
|
val newContext = context.replaceExpectedType(expectedTypeWithEstimatedReturnType).replaceDataFlowInfo(dataFlowInfoForArgument)
|
||||||
.replaceContextDependency(INDEPENDENT)
|
.replaceContextDependency(INDEPENDENT)
|
||||||
val type = argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).type
|
val type =
|
||||||
|
argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS)
|
||||||
|
.type
|
||||||
constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position)
|
constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> addConstraintForCallableReference(
|
private fun <D : CallableDescriptor> addConstraintForCallableReference(
|
||||||
callableReference: KtCallableReferenceExpression,
|
callableReference: KtCallableReferenceExpression,
|
||||||
valueArgument: ValueArgument,
|
valueArgument: ValueArgument,
|
||||||
valueParameterDescriptor: ValueParameterDescriptor,
|
valueParameterDescriptor: ValueParameterDescriptor,
|
||||||
constraintSystem: ConstraintSystem.Builder,
|
constraintSystem: ConstraintSystem.Builder,
|
||||||
context: CallCandidateResolutionContext<D>
|
context: CallCandidateResolutionContext<D>
|
||||||
) {
|
) {
|
||||||
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
|
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
|
||||||
val expectedType = getExpectedTypeForCallableReference(callableReference, constraintSystem, context, effectiveExpectedType)
|
val expectedType = getExpectedTypeForCallableReference(callableReference, constraintSystem, context, effectiveExpectedType)
|
||||||
?: return
|
?: return
|
||||||
if (!ReflectionTypes.isCallableType(expectedType)) return
|
if (!ReflectionTypes.isCallableType(expectedType)) return
|
||||||
val resolvedType = getResolvedTypeForCallableReference(callableReference, context, expectedType, valueArgument) ?: return
|
val resolvedType = getResolvedTypeForCallableReference(callableReference, context, expectedType, valueArgument) ?: return
|
||||||
val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
|
val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
|
||||||
constraintSystem.addSubtypeConstraint(
|
constraintSystem.addSubtypeConstraint(
|
||||||
resolvedType,
|
resolvedType,
|
||||||
constraintSystem.typeVariableSubstitutors[context.call.toHandle()]?.substitute(effectiveExpectedType, Variance.INVARIANT),
|
constraintSystem.typeVariableSubstitutors[context.call.toHandle()]?.substitute(effectiveExpectedType, Variance.INVARIANT),
|
||||||
position
|
position
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> getExpectedTypeForCallableReference(
|
private fun <D : CallableDescriptor> getExpectedTypeForCallableReference(
|
||||||
callableReference: KtCallableReferenceExpression,
|
callableReference: KtCallableReferenceExpression,
|
||||||
constraintSystem: ConstraintSystem.Builder,
|
constraintSystem: ConstraintSystem.Builder,
|
||||||
context: CallCandidateResolutionContext<D>,
|
context: CallCandidateResolutionContext<D>,
|
||||||
effectiveExpectedType: KotlinType
|
effectiveExpectedType: KotlinType
|
||||||
): KotlinType? {
|
): KotlinType? {
|
||||||
val substitutedType = constraintSystem.build().currentSubstitutor.substitute(effectiveExpectedType, Variance.INVARIANT)
|
val substitutedType = constraintSystem.build().currentSubstitutor.substitute(effectiveExpectedType, Variance.INVARIANT)
|
||||||
if (substitutedType != null && !TypeUtils.isDontCarePlaceholder(substitutedType))
|
if (substitutedType != null && !TypeUtils.isDontCarePlaceholder(substitutedType))
|
||||||
@@ -509,19 +518,20 @@ class GenericCandidateResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> getResolvedTypeForCallableReference(
|
private fun <D : CallableDescriptor> getResolvedTypeForCallableReference(
|
||||||
callableReference: KtCallableReferenceExpression,
|
callableReference: KtCallableReferenceExpression,
|
||||||
context: CallCandidateResolutionContext<D>,
|
context: CallCandidateResolutionContext<D>,
|
||||||
expectedType: KotlinType,
|
expectedType: KotlinType,
|
||||||
valueArgument: ValueArgument
|
valueArgument: ValueArgument
|
||||||
): KotlinType? {
|
): KotlinType? {
|
||||||
val dataFlowInfoForArgument = context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument)
|
val dataFlowInfoForArgument = context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument)
|
||||||
val expectedTypeWithoutReturnType = if (!hasUnknownReturnType(expectedType)) replaceReturnTypeByUnknown(expectedType) else expectedType
|
val expectedTypeWithoutReturnType =
|
||||||
|
if (!hasUnknownReturnType(expectedType)) replaceReturnTypeByUnknown(expectedType) else expectedType
|
||||||
val newContext = context
|
val newContext = context
|
||||||
.replaceExpectedType(expectedTypeWithoutReturnType)
|
.replaceExpectedType(expectedTypeWithoutReturnType)
|
||||||
.replaceDataFlowInfo(dataFlowInfoForArgument)
|
.replaceDataFlowInfo(dataFlowInfoForArgument)
|
||||||
.replaceContextDependency(INDEPENDENT)
|
.replaceContextDependency(INDEPENDENT)
|
||||||
return argumentTypeResolver.getCallableReferenceTypeInfo(
|
return argumentTypeResolver.getCallableReferenceTypeInfo(
|
||||||
callableReference, callableReference, newContext, RESOLVE_FUNCTION_ARGUMENTS
|
callableReference, callableReference, newContext, RESOLVE_FUNCTION_ARGUMENTS
|
||||||
).type
|
).type
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -539,7 +549,7 @@ fun makeConstantSubstitutor(typeParameterDescriptors: Collection<TypeParameterDe
|
|||||||
|
|
||||||
return TypeSubstitutor.create(object : TypeConstructorSubstitution() {
|
return TypeSubstitutor.create(object : TypeConstructorSubstitution() {
|
||||||
override operator fun get(key: TypeConstructor) =
|
override operator fun get(key: TypeConstructor) =
|
||||||
if (key in constructors) projection else null
|
if (key in constructors) projection else null
|
||||||
|
|
||||||
override fun isEmpty() = false
|
override fun isEmpty() = false
|
||||||
})
|
})
|
||||||
|
|||||||
+1
-1
@@ -33,6 +33,6 @@ class CallReturnsArrayOfNothingChecker : CallChecker {
|
|||||||
if (this == null || isComputingDeferredType(this)) return false
|
if (this == null || isComputingDeferredType(this)) return false
|
||||||
|
|
||||||
return isArrayOfNothing() ||
|
return isArrayOfNothing() ||
|
||||||
arguments.any { !it.isStarProjection && it.type.containsArrayOfNothing() }
|
arguments.any { !it.isStarProjection && it.type.containsArrayOfNothing() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+8
-3
@@ -32,11 +32,16 @@ class CallableReferenceCompatibilityChecker : CallChecker {
|
|||||||
for ((_, resolvedArgument) in resolvedCall.valueArguments) {
|
for ((_, resolvedArgument) in resolvedCall.valueArguments) {
|
||||||
inner@ for (argument in resolvedArgument.arguments) {
|
inner@ for (argument in resolvedArgument.arguments) {
|
||||||
val argumentExpression = argument.getArgumentExpression() as? KtCallableReferenceExpression ?: continue@inner
|
val argumentExpression = argument.getArgumentExpression() as? KtCallableReferenceExpression ?: continue@inner
|
||||||
val callableReferenceResolvedCall = argumentExpression.callableReference.getResolvedCall(context.trace.bindingContext) ?: continue@inner
|
val callableReferenceResolvedCall =
|
||||||
|
argumentExpression.callableReference.getResolvedCall(context.trace.bindingContext) ?: continue@inner
|
||||||
if (callableReferenceResolvedCall.call.isCallableReference() &&
|
if (callableReferenceResolvedCall.call.isCallableReference() &&
|
||||||
callableReferenceResolvedCall.candidateDescriptor.typeParameters.isNotEmpty()) {
|
callableReferenceResolvedCall.candidateDescriptor.typeParameters.isNotEmpty()) {
|
||||||
context.trace.report(Errors.UNSUPPORTED_FEATURE.on(argumentExpression,
|
context.trace.report(
|
||||||
typeInferenceForCallableReferencesFeature to context.languageVersionSettings))
|
Errors.UNSUPPORTED_FEATURE.on(
|
||||||
|
argumentExpression,
|
||||||
|
typeInferenceForCallableReferencesFeature to context.languageVersionSettings
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -62,7 +62,7 @@ class CapturingInClosureChecker : CallChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isCapturedInInline(
|
private fun isCapturedInInline(
|
||||||
context: BindingContext, scopeContainer: DeclarationDescriptor, variableParent: DeclarationDescriptor
|
context: BindingContext, scopeContainer: DeclarationDescriptor, variableParent: DeclarationDescriptor
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val scopeDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(scopeContainer)
|
val scopeDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(scopeContainer)
|
||||||
if (!InlineUtil.canBeInlineArgument(scopeDeclaration)) return false
|
if (!InlineUtil.canBeInlineArgument(scopeDeclaration)) return false
|
||||||
@@ -70,7 +70,7 @@ class CapturingInClosureChecker : CallChecker {
|
|||||||
if (InlineUtil.isInlinedArgument(scopeDeclaration as KtFunction, context, false)) {
|
if (InlineUtil.isInlinedArgument(scopeDeclaration as KtFunction, context, false)) {
|
||||||
val scopeContainerParent = scopeContainer.containingDeclaration ?: error("parent is null for $scopeContainer")
|
val scopeContainerParent = scopeContainer.containingDeclaration ?: error("parent is null for $scopeContainer")
|
||||||
return !isCapturedVariable(variableParent, scopeContainerParent) ||
|
return !isCapturedVariable(variableParent, scopeContainerParent) ||
|
||||||
isCapturedInInline(context, scopeContainerParent, variableParent)
|
isCapturedInInline(context, scopeContainerParent, variableParent)
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-5
@@ -40,9 +40,9 @@ object DeprecatedCallChecker : CallChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun check(
|
private fun check(
|
||||||
targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement,
|
targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement,
|
||||||
languageVersionSettings: LanguageVersionSettings,
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
deprecationResolver: DeprecationResolver
|
deprecationResolver: DeprecationResolver
|
||||||
) {
|
) {
|
||||||
// Objects will be checked by DeprecatedClassifierUsageChecker
|
// Objects will be checked by DeprecatedClassifierUsageChecker
|
||||||
if (targetDescriptor is FakeCallableDescriptorForObject) return
|
if (targetDescriptor is FakeCallableDescriptorForObject) return
|
||||||
@@ -58,8 +58,7 @@ object DeprecatedCallChecker : CallChecker {
|
|||||||
for (deprecation in deprecations) {
|
for (deprecation in deprecations) {
|
||||||
trace.report(createDeprecationDiagnostic(element, deprecation, languageVersionSettings))
|
trace.report(createDeprecationDiagnostic(element, deprecation, languageVersionSettings))
|
||||||
}
|
}
|
||||||
}
|
} else if (targetDescriptor is PropertyDescriptor && shouldCheckPropertyGetter(element)) {
|
||||||
else if (targetDescriptor is PropertyDescriptor && shouldCheckPropertyGetter(element)) {
|
|
||||||
targetDescriptor.getter?.let { check(it, trace, element, languageVersionSettings, deprecationResolver) }
|
targetDescriptor.getter?.let { check(it, trace, element, languageVersionSettings, deprecationResolver) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -46,15 +46,15 @@ object DslScopeViolationCallChecker : CallChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkCallImplicitReceiver(
|
private fun checkCallImplicitReceiver(
|
||||||
callImplicitReceiver: ReceiverValue,
|
callImplicitReceiver: ReceiverValue,
|
||||||
resolvedCall: ResolvedCall<*>,
|
resolvedCall: ResolvedCall<*>,
|
||||||
reportOn: PsiElement,
|
reportOn: PsiElement,
|
||||||
context: CallCheckerContext
|
context: CallCheckerContext
|
||||||
) {
|
) {
|
||||||
val receiversUntilOneFromTheCall =
|
val receiversUntilOneFromTheCall =
|
||||||
context.scope.parentsWithSelf
|
context.scope.parentsWithSelf
|
||||||
.mapNotNull { (it as? LexicalScope)?.implicitReceiver?.value }
|
.mapNotNull { (it as? LexicalScope)?.implicitReceiver?.value }
|
||||||
.takeWhile { it != callImplicitReceiver }.toList()
|
.takeWhile { it != callImplicitReceiver }.toList()
|
||||||
|
|
||||||
if (receiversUntilOneFromTheCall.isEmpty()) return
|
if (receiversUntilOneFromTheCall.isEmpty()) return
|
||||||
|
|
||||||
@@ -62,7 +62,7 @@ object DslScopeViolationCallChecker : CallChecker {
|
|||||||
if (callDslMarkers.isEmpty()) return
|
if (callDslMarkers.isEmpty()) return
|
||||||
|
|
||||||
val closestAnotherReceiverWithSameDslMarker =
|
val closestAnotherReceiverWithSameDslMarker =
|
||||||
receiversUntilOneFromTheCall.firstOrNull { receiver -> receiver.type.extractDslMarkerFqNames().any(callDslMarkers::contains) }
|
receiversUntilOneFromTheCall.firstOrNull { receiver -> receiver.type.extractDslMarkerFqNames().any(callDslMarkers::contains) }
|
||||||
|
|
||||||
if (closestAnotherReceiverWithSameDslMarker != null) {
|
if (closestAnotherReceiverWithSameDslMarker != null) {
|
||||||
// TODO: report receivers configuration (what's one is used and what's one is the closest)
|
// TODO: report receivers configuration (what's one is used and what's one is the closest)
|
||||||
@@ -83,7 +83,7 @@ object DslScopeViolationCallChecker : CallChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
constructor.declarationDescriptor?.getAllSuperClassifiers()?.asIterable()
|
constructor.declarationDescriptor?.getAllSuperClassifiers()?.asIterable()
|
||||||
?.flatMapTo(result) { it.annotations.extractDslMarkerFqNames() }
|
?.flatMapTo(result) { it.annotations.extractDslMarkerFqNames() }
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@@ -91,7 +91,7 @@ object DslScopeViolationCallChecker : CallChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun Annotations.extractDslMarkerFqNames() =
|
private fun Annotations.extractDslMarkerFqNames() =
|
||||||
filter(AnnotationDescriptor::isDslMarker).map { it.fqName!! }
|
filter(AnnotationDescriptor::isDslMarker).map { it.fqName!! }
|
||||||
|
|
||||||
private fun AnnotationDescriptor.isDslMarker(): Boolean {
|
private fun AnnotationDescriptor.isDslMarker(): Boolean {
|
||||||
val classDescriptor = annotationClass ?: return false
|
val classDescriptor = annotationClass ?: return false
|
||||||
|
|||||||
+11
-10
@@ -49,9 +49,11 @@ class OperatorCallChecker : CallChecker {
|
|||||||
call is CallTransformer.CallForImplicitInvoke && call.itIsVariableAsFunctionCall) {
|
call is CallTransformer.CallForImplicitInvoke && call.itIsVariableAsFunctionCall) {
|
||||||
val outerCall = call.outerCall
|
val outerCall = call.outerCall
|
||||||
if (isConventionCall(outerCall) || isWrongCallWithExplicitTypeArguments(resolvedCall, outerCall)) {
|
if (isConventionCall(outerCall) || isWrongCallWithExplicitTypeArguments(resolvedCall, outerCall)) {
|
||||||
throw AssertionError("Illegal resolved call to variable with invoke for $outerCall. " +
|
throw AssertionError(
|
||||||
"Variable: ${resolvedCall.variableCall.resultingDescriptor}" +
|
"Illegal resolved call to variable with invoke for $outerCall. " +
|
||||||
"Invoke: ${resolvedCall.functionCall.resultingDescriptor}")
|
"Variable: ${resolvedCall.variableCall.resultingDescriptor}" +
|
||||||
|
"Invoke: ${resolvedCall.functionCall.resultingDescriptor}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,11 +91,11 @@ class OperatorCallChecker : CallChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun isWrongCallWithExplicitTypeArguments(
|
private fun isWrongCallWithExplicitTypeArguments(
|
||||||
resolvedCall: VariableAsFunctionResolvedCall,
|
resolvedCall: VariableAsFunctionResolvedCall,
|
||||||
outerCall: Call
|
outerCall: Call
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val passedTypeArgumentsToInvoke = outerCall.typeArguments.isNotEmpty() &&
|
val passedTypeArgumentsToInvoke = outerCall.typeArguments.isNotEmpty() &&
|
||||||
resolvedCall.functionCall.candidateDescriptor.typeParameters.isNotEmpty()
|
resolvedCall.functionCall.candidateDescriptor.typeParameters.isNotEmpty()
|
||||||
return passedTypeArgumentsToInvoke && resolvedCall.variableCall.candidateDescriptor.typeParameters.isNotEmpty()
|
return passedTypeArgumentsToInvoke && resolvedCall.variableCall.candidateDescriptor.typeParameters.isNotEmpty()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -108,8 +110,8 @@ fun shouldWarnAboutDeprecatedModFromBuiltIns(languageVersionSettings: LanguageVe
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkModConvention(
|
private fun checkModConvention(
|
||||||
descriptor: FunctionDescriptor, languageVersionSettings: LanguageVersionSettings,
|
descriptor: FunctionDescriptor, languageVersionSettings: LanguageVersionSettings,
|
||||||
diagnosticHolder: DiagnosticSink, modifier: PsiElement
|
diagnosticHolder: DiagnosticSink, modifier: PsiElement
|
||||||
) {
|
) {
|
||||||
if (!descriptor.isOperatorMod()) return
|
if (!descriptor.isOperatorMod()) return
|
||||||
|
|
||||||
@@ -117,8 +119,7 @@ private fun checkModConvention(
|
|||||||
if (shouldWarnAboutDeprecatedModFromBuiltIns(languageVersionSettings)) {
|
if (shouldWarnAboutDeprecatedModFromBuiltIns(languageVersionSettings)) {
|
||||||
addWarningAboutDeprecatedMod(descriptor, diagnosticHolder, modifier)
|
addWarningAboutDeprecatedMod(descriptor, diagnosticHolder, modifier)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)) {
|
if (languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)) {
|
||||||
addWarningAboutDeprecatedMod(descriptor, diagnosticHolder, modifier)
|
addWarningAboutDeprecatedMod(descriptor, diagnosticHolder, modifier)
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-4
@@ -33,8 +33,8 @@ enum class RttiOperation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class RttiExpressionInformation(
|
class RttiExpressionInformation(
|
||||||
val subject: KtExpression,
|
val subject: KtExpression,
|
||||||
val sourceType: KotlinType?,
|
val sourceType: KotlinType?,
|
||||||
val targetType: KotlinType?,
|
val targetType: KotlinType?,
|
||||||
val operation: RttiOperation
|
val operation: RttiOperation
|
||||||
)
|
)
|
||||||
+25
-12
@@ -56,9 +56,9 @@ object CoroutineSuspendCallChecker : CallChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val enclosingSuspendFunction = context.scope
|
val enclosingSuspendFunction = context.scope
|
||||||
.parentsWithSelf.firstOrNull {
|
.parentsWithSelf.firstOrNull {
|
||||||
it is LexicalScope && it.kind in ALLOWED_SCOPE_KINDS &&
|
it is LexicalScope && it.kind in ALLOWED_SCOPE_KINDS &&
|
||||||
it.ownerDescriptor.safeAs<FunctionDescriptor>()?.isSuspend == true
|
it.ownerDescriptor.safeAs<FunctionDescriptor>()?.isSuspend == true
|
||||||
}?.cast<LexicalScope>()?.ownerDescriptor?.cast<FunctionDescriptor>()
|
}?.cast<LexicalScope>()?.ownerDescriptor?.cast<FunctionDescriptor>()
|
||||||
|
|
||||||
when {
|
when {
|
||||||
@@ -67,19 +67,32 @@ object CoroutineSuspendCallChecker : CallChecker {
|
|||||||
|
|
||||||
if (!InlineUtil.checkNonLocalReturnUsage(enclosingSuspendFunction, callElement, context.resolutionContext)) {
|
if (!InlineUtil.checkNonLocalReturnUsage(enclosingSuspendFunction, callElement, context.resolutionContext)) {
|
||||||
context.trace.report(Errors.NON_LOCAL_SUSPENSION_POINT.on(reportOn))
|
context.trace.report(Errors.NON_LOCAL_SUSPENSION_POINT.on(reportOn))
|
||||||
}
|
} else if (context.scope.parentsWithSelf.any { it.isScopeForDefaultParameterValuesOf(enclosingSuspendFunction) }) {
|
||||||
else if (context.scope.parentsWithSelf.any { it.isScopeForDefaultParameterValuesOf(enclosingSuspendFunction) }) {
|
|
||||||
context.trace.report(Errors.UNSUPPORTED.on(reportOn, "suspend function calls in a context of default parameter value"))
|
context.trace.report(Errors.UNSUPPORTED.on(reportOn, "suspend function calls in a context of default parameter value"))
|
||||||
}
|
}
|
||||||
|
|
||||||
context.trace.record(BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL, resolvedCall.call, enclosingSuspendFunction)
|
context.trace.record(
|
||||||
|
BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL,
|
||||||
|
resolvedCall.call,
|
||||||
|
enclosingSuspendFunction
|
||||||
|
)
|
||||||
|
|
||||||
checkRestrictsSuspension(enclosingSuspendFunction, resolvedCall, reportOn, context)
|
checkRestrictsSuspension(enclosingSuspendFunction, resolvedCall, reportOn, context)
|
||||||
}
|
}
|
||||||
else -> {
|
else -> {
|
||||||
when (descriptor) {
|
when (descriptor) {
|
||||||
is FunctionDescriptor -> context.trace.report(Errors.ILLEGAL_SUSPEND_FUNCTION_CALL.on(reportOn, resolvedCall.candidateDescriptor))
|
is FunctionDescriptor -> context.trace.report(
|
||||||
is PropertyDescriptor -> context.trace.report(Errors.ILLEGAL_SUSPEND_PROPERTY_ACCESS.on(reportOn, resolvedCall.candidateDescriptor))
|
Errors.ILLEGAL_SUSPEND_FUNCTION_CALL.on(
|
||||||
|
reportOn,
|
||||||
|
resolvedCall.candidateDescriptor
|
||||||
|
)
|
||||||
|
)
|
||||||
|
is PropertyDescriptor -> context.trace.report(
|
||||||
|
Errors.ILLEGAL_SUSPEND_PROPERTY_ACCESS.on(
|
||||||
|
reportOn,
|
||||||
|
resolvedCall.candidateDescriptor
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,7 +100,7 @@ object CoroutineSuspendCallChecker : CallChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun HierarchicalScope.isScopeForDefaultParameterValuesOf(enclosingSuspendFunction: FunctionDescriptor) =
|
private fun HierarchicalScope.isScopeForDefaultParameterValuesOf(enclosingSuspendFunction: FunctionDescriptor) =
|
||||||
this is LexicalScope && this.kind == LexicalScopeKind.DEFAULT_VALUE && this.ownerDescriptor == enclosingSuspendFunction
|
this is LexicalScope && this.kind == LexicalScopeKind.DEFAULT_VALUE && this.ownerDescriptor == enclosingSuspendFunction
|
||||||
|
|
||||||
object BuilderFunctionsCallChecker : CallChecker {
|
object BuilderFunctionsCallChecker : CallChecker {
|
||||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||||
@@ -116,10 +129,10 @@ fun checkCoroutinesFeature(languageVersionSettings: LanguageVersionSettings, dia
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkRestrictsSuspension(
|
private fun checkRestrictsSuspension(
|
||||||
enclosingCallableDescriptor: CallableDescriptor,
|
enclosingCallableDescriptor: CallableDescriptor,
|
||||||
resolvedCall: ResolvedCall<*>,
|
resolvedCall: ResolvedCall<*>,
|
||||||
reportOn: PsiElement,
|
reportOn: PsiElement,
|
||||||
context: CallCheckerContext
|
context: CallCheckerContext
|
||||||
) {
|
) {
|
||||||
val enclosingSuspendReceiverValue = enclosingCallableDescriptor.extensionReceiverParameter?.value ?: return
|
val enclosingSuspendReceiverValue = enclosingCallableDescriptor.extensionReceiverParameter?.value ?: return
|
||||||
|
|
||||||
|
|||||||
+83
-68
@@ -50,7 +50,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal data class Constraint(
|
internal data class Constraint(
|
||||||
val kind: ConstraintKind, val subtype: KotlinType, val superType: KotlinType, val position: ConstraintPosition
|
val kind: ConstraintKind, val subtype: KotlinType, val superType: KotlinType, val position: ConstraintPosition
|
||||||
)
|
)
|
||||||
|
|
||||||
enum class ConstraintKind(val bound: TypeBounds.BoundKind) {
|
enum class ConstraintKind(val bound: TypeBounds.BoundKind) {
|
||||||
@@ -74,7 +74,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun registerTypeVariables(
|
override fun registerTypeVariables(
|
||||||
call: CallHandle, typeParameters: Collection<TypeParameterDescriptor>, external: Boolean
|
call: CallHandle, typeParameters: Collection<TypeParameterDescriptor>, external: Boolean
|
||||||
): TypeSubstitutor {
|
): TypeSubstitutor {
|
||||||
if (typeParameters.isEmpty()) return storeSubstitutor(call, TypeSubstitutor.EMPTY)
|
if (typeParameters.isEmpty()) return storeSubstitutor(call, TypeSubstitutor.EMPTY)
|
||||||
|
|
||||||
@@ -82,11 +82,10 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
|||||||
typeParameters.map {
|
typeParameters.map {
|
||||||
TypeVariable(call, it, it, true)
|
TypeVariable(call, it, it, true)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val freshTypeParameters = ArrayList<TypeParameterDescriptor>(typeParameters.size)
|
val freshTypeParameters = ArrayList<TypeParameterDescriptor>(typeParameters.size)
|
||||||
DescriptorSubstitutor.substituteTypeParameters(
|
DescriptorSubstitutor.substituteTypeParameters(
|
||||||
typeParameters.toList(), TypeSubstitution.EMPTY, typeParameters.first().containingDeclaration, freshTypeParameters
|
typeParameters.toList(), TypeSubstitution.EMPTY, typeParameters.first().containingDeclaration, freshTypeParameters
|
||||||
)
|
)
|
||||||
freshTypeParameters.zip(typeParameters).map {
|
freshTypeParameters.zip(typeParameters).map {
|
||||||
val (fresh, original) = it
|
val (fresh, original) = it
|
||||||
@@ -106,33 +105,44 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return storeSubstitutor(call, TypeSubstitutor.create(TypeConstructorSubstitution.createByParametersMap(
|
return storeSubstitutor(
|
||||||
typeParameters.zip(typeVariables.map { it.type }.defaultProjections()).toMap()
|
call, TypeSubstitutor.create(
|
||||||
)))
|
TypeConstructorSubstitution.createByParametersMap(
|
||||||
|
typeParameters.zip(typeVariables.map { it.type }.defaultProjections()).toMap()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun KotlinType.isProper() = !TypeUtils.contains(this) {
|
private fun KotlinType.isProper() = !TypeUtils.contains(this) { type ->
|
||||||
type -> type.constructor.declarationDescriptor.let { it is TypeParameterDescriptor && isMyTypeVariable(it) }
|
type.constructor.declarationDescriptor.let { it is TypeParameterDescriptor && isMyTypeVariable(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun getNestedTypeVariables(type: KotlinType): List<TypeVariable> =
|
internal fun getNestedTypeVariables(type: KotlinType): List<TypeVariable> =
|
||||||
type.getNestedTypeParameters().mapNotNull { getMyTypeVariable(it) }
|
type.getNestedTypeParameters().mapNotNull { getMyTypeVariable(it) }
|
||||||
|
|
||||||
override fun addSubtypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType?, constraintPosition: ConstraintPosition) {
|
override fun addSubtypeConstraint(constrainingType: KotlinType?, subjectType: KotlinType?, constraintPosition: ConstraintPosition) {
|
||||||
addConstraint(SUB_TYPE, constrainingType, subjectType, ConstraintContext(constraintPosition, initial = true, initialReduction = true))
|
addConstraint(
|
||||||
|
SUB_TYPE,
|
||||||
|
constrainingType,
|
||||||
|
subjectType,
|
||||||
|
ConstraintContext(constraintPosition, initial = true, initialReduction = true)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addConstraint(
|
fun addConstraint(
|
||||||
constraintKind: ConstraintKind,
|
constraintKind: ConstraintKind,
|
||||||
subType: KotlinType?,
|
subType: KotlinType?,
|
||||||
superType: KotlinType?,
|
superType: KotlinType?,
|
||||||
constraintContext: ConstraintContext
|
constraintContext: ConstraintContext
|
||||||
) {
|
) {
|
||||||
val constraintPosition = constraintContext.position
|
val constraintPosition = constraintContext.position
|
||||||
|
|
||||||
// when processing nested constraints, `derivedFrom` information should be reset
|
// when processing nested constraints, `derivedFrom` information should be reset
|
||||||
val newConstraintContext = ConstraintContext(constraintContext.position, derivedFrom = null, initial = false,
|
val newConstraintContext = ConstraintContext(
|
||||||
initialReduction = constraintContext.initialReduction)
|
constraintContext.position, derivedFrom = null, initial = false,
|
||||||
|
initialReduction = constraintContext.initialReduction
|
||||||
|
)
|
||||||
val typeCheckingProcedure = TypeCheckingProcedure(object : TypeCheckingProcedureCallbacks {
|
val typeCheckingProcedure = TypeCheckingProcedure(object : TypeCheckingProcedureCallbacks {
|
||||||
private var depth = 0
|
private var depth = 0
|
||||||
|
|
||||||
@@ -187,11 +197,11 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun doAddConstraint(
|
private fun doAddConstraint(
|
||||||
constraintKind: ConstraintKind,
|
constraintKind: ConstraintKind,
|
||||||
subType: KotlinType?,
|
subType: KotlinType?,
|
||||||
superType: KotlinType?,
|
superType: KotlinType?,
|
||||||
constraintContext: ConstraintContext,
|
constraintContext: ConstraintContext,
|
||||||
typeCheckingProcedure: TypeCheckingProcedure
|
typeCheckingProcedure: TypeCheckingProcedure
|
||||||
) {
|
) {
|
||||||
val constraintPosition = constraintContext.position
|
val constraintPosition = constraintContext.position
|
||||||
if (isErrorOrSpecialType(subType, constraintPosition) || isErrorOrSpecialType(superType, constraintPosition)) return
|
if (isErrorOrSpecialType(subType, constraintPosition) || isErrorOrSpecialType(superType, constraintPosition)) return
|
||||||
@@ -212,8 +222,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
createTypeForFunctionPlaceholder(subType, superType)
|
createTypeForFunctionPlaceholder(subType, superType)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
subType
|
subType
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,8 +239,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
|||||||
val superType2 = simplifyType(superType, constraintContext.initial)
|
val superType2 = simplifyType(superType, constraintContext.initial)
|
||||||
val result = if (constraintKind == EQUAL) {
|
val result = if (constraintKind == EQUAL) {
|
||||||
typeCheckingProcedure.equalTypes(subType2, superType2)
|
typeCheckingProcedure.equalTypes(subType2, superType2)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
typeCheckingProcedure.isSubtypeOf(subType2, superType)
|
typeCheckingProcedure.isSubtypeOf(subType2, superType)
|
||||||
}
|
}
|
||||||
if (!result) errors.add(newTypeInferenceOrParameterConstraintError(constraintPosition))
|
if (!result) errors.add(newTypeInferenceOrParameterConstraintError(constraintPosition))
|
||||||
@@ -245,22 +253,24 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun simplifyType(type: KotlinType, isInitialConstraint: Boolean): KotlinType =
|
private fun simplifyType(type: KotlinType, isInitialConstraint: Boolean): KotlinType =
|
||||||
if (mode == Mode.SPECIFICITY || !isInitialConstraint)
|
if (mode == Mode.SPECIFICITY || !isInitialConstraint)
|
||||||
type
|
type
|
||||||
else {
|
else {
|
||||||
// if subType is nullable and superType is not nullable, unsafe call or type mismatch error will be generated later,
|
// if subType is nullable and superType is not nullable, unsafe call or type mismatch error will be generated later,
|
||||||
// but constraint system should be solved anyway
|
// but constraint system should be solved anyway
|
||||||
TypeUtils.makeNotNullable(type)
|
TypeUtils.makeNotNullable(type)
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun addBound(
|
internal fun addBound(
|
||||||
typeVariable: TypeVariable,
|
typeVariable: TypeVariable,
|
||||||
constrainingType: KotlinType,
|
constrainingType: KotlinType,
|
||||||
kind: TypeBounds.BoundKind,
|
kind: TypeBounds.BoundKind,
|
||||||
constraintContext: ConstraintContext
|
constraintContext: ConstraintContext
|
||||||
) {
|
) {
|
||||||
val bound = Bound(typeVariable, constrainingType, kind, constraintContext.position,
|
val bound = Bound(
|
||||||
constrainingType.isProper(), constraintContext.derivedFrom ?: emptySet())
|
typeVariable, constrainingType, kind, constraintContext.position,
|
||||||
|
constrainingType.isProper(), constraintContext.derivedFrom ?: emptySet()
|
||||||
|
)
|
||||||
val typeBounds = getTypeBounds(typeVariable)
|
val typeBounds = getTypeBounds(typeVariable)
|
||||||
if (typeBounds.bounds.contains(bound)) return
|
if (typeBounds.bounds.contains(bound)) return
|
||||||
|
|
||||||
@@ -277,10 +287,10 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateTypeParameterBound(
|
private fun generateTypeParameterBound(
|
||||||
parameterType: KotlinType,
|
parameterType: KotlinType,
|
||||||
constrainingType: KotlinType,
|
constrainingType: KotlinType,
|
||||||
boundKind: TypeBounds.BoundKind,
|
boundKind: TypeBounds.BoundKind,
|
||||||
constraintContext: ConstraintContext
|
constraintContext: ConstraintContext
|
||||||
) {
|
) {
|
||||||
val typeVariable = getMyTypeVariable(parameterType)!!
|
val typeVariable = getMyTypeVariable(parameterType)!!
|
||||||
|
|
||||||
@@ -321,10 +331,10 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun generateTypeParameterCaptureConstraint(
|
private fun generateTypeParameterCaptureConstraint(
|
||||||
typeVariable: TypeVariable,
|
typeVariable: TypeVariable,
|
||||||
constrainingTypeProjection: TypeProjection,
|
constrainingTypeProjection: TypeProjection,
|
||||||
constraintContext: ConstraintContext,
|
constraintContext: ConstraintContext,
|
||||||
isTypeMarkedNullable: Boolean
|
isTypeMarkedNullable: Boolean
|
||||||
) {
|
) {
|
||||||
if (!typeVariable.originalTypeParameter.upperBounds.let { it.size == 1 && it.single().isDefaultBound() } &&
|
if (!typeVariable.originalTypeParameter.upperBounds.let { it.size == 1 && it.single().isDefaultBound() } &&
|
||||||
constrainingTypeProjection.projectionKind == Variance.IN_VARIANCE) {
|
constrainingTypeProjection.projectionKind == Variance.IN_VARIANCE) {
|
||||||
@@ -332,8 +342,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
|||||||
}
|
}
|
||||||
val typeProjection = if (isTypeMarkedNullable) {
|
val typeProjection = if (isTypeMarkedNullable) {
|
||||||
TypeProjectionImpl(constrainingTypeProjection.projectionKind, TypeUtils.makeNotNullable(constrainingTypeProjection.type))
|
TypeProjectionImpl(constrainingTypeProjection.projectionKind, TypeUtils.makeNotNullable(constrainingTypeProjection.type))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
constrainingTypeProjection
|
constrainingTypeProjection
|
||||||
}
|
}
|
||||||
val capturedType = createCapturedType(typeProjection)
|
val capturedType = createCapturedType(typeProjection)
|
||||||
@@ -341,24 +350,29 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun getTypeBounds(variable: TypeVariable): TypeBoundsImpl {
|
internal fun getTypeBounds(variable: TypeVariable): TypeBoundsImpl {
|
||||||
return allTypeParameterBounds[variable] ?:
|
return allTypeParameterBounds[variable]
|
||||||
throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $variable")
|
?: throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $variable")
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isMyTypeVariable(typeParameter: TypeParameterDescriptor) =
|
private fun isMyTypeVariable(typeParameter: TypeParameterDescriptor) =
|
||||||
getMyTypeVariable(typeParameter) != null
|
getMyTypeVariable(typeParameter) != null
|
||||||
|
|
||||||
internal fun isMyTypeVariable(type: KotlinType): Boolean =
|
internal fun isMyTypeVariable(type: KotlinType): Boolean =
|
||||||
getMyTypeVariable(type) != null
|
getMyTypeVariable(type) != null
|
||||||
|
|
||||||
internal fun getMyTypeVariable(type: KotlinType): TypeVariable? {
|
internal fun getMyTypeVariable(type: KotlinType): TypeVariable? {
|
||||||
return getMyTypeVariable(type.constructor.declarationDescriptor as? TypeParameterDescriptor ?: return null)
|
return getMyTypeVariable(type.constructor.declarationDescriptor as? TypeParameterDescriptor ?: return null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMyTypeVariable(typeParameter: TypeParameterDescriptor): TypeVariable? =
|
private fun getMyTypeVariable(typeParameter: TypeParameterDescriptor): TypeVariable? =
|
||||||
allTypeParameterBounds.keys.find { it.freshTypeParameter == typeParameter }
|
allTypeParameterBounds.keys.find { it.freshTypeParameter == typeParameter }
|
||||||
|
|
||||||
private fun storeInitialConstraint(constraintKind: ConstraintKind, subType: KotlinType, superType: KotlinType, position: ConstraintPosition) {
|
private fun storeInitialConstraint(
|
||||||
|
constraintKind: ConstraintKind,
|
||||||
|
subType: KotlinType,
|
||||||
|
superType: KotlinType,
|
||||||
|
position: ConstraintPosition
|
||||||
|
) {
|
||||||
initialConstraints.add(Constraint(constraintKind, subType, superType, position))
|
initialConstraints.add(Constraint(constraintKind, subType, superType, position))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,14 +395,14 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
|||||||
}
|
}
|
||||||
if (!Collections.disjoint(typeVariableSubstitutors.keys, other.typeVariableSubstitutors.keys)) {
|
if (!Collections.disjoint(typeVariableSubstitutors.keys, other.typeVariableSubstitutors.keys)) {
|
||||||
throw IllegalArgumentException(
|
throw IllegalArgumentException(
|
||||||
"Combining two constraint systems only makes sense when they were created for different calls. " +
|
"Combining two constraint systems only makes sense when they were created for different calls. " +
|
||||||
"Calls of the first system: ${typeVariableSubstitutors.keys}, second: ${other.typeVariableSubstitutors.keys}"
|
"Calls of the first system: ${typeVariableSubstitutors.keys}, second: ${other.typeVariableSubstitutors.keys}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
if (!Collections.disjoint(other.allTypeParameterBounds.keys, allTypeParameterBounds.keys)) {
|
if (!Collections.disjoint(other.allTypeParameterBounds.keys, allTypeParameterBounds.keys)) {
|
||||||
throw IllegalArgumentException(
|
throw IllegalArgumentException(
|
||||||
"Combining two constraint systems only makes sense when they have no common variables. " +
|
"Combining two constraint systems only makes sense when they have no common variables. " +
|
||||||
"First system variables: ${allTypeParameterBounds.keys}, second: ${other.allTypeParameterBounds.keys}"
|
"First system variables: ${allTypeParameterBounds.keys}, second: ${other.allTypeParameterBounds.keys}"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -415,10 +429,10 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
|||||||
var counter = 0
|
var counter = 0
|
||||||
|
|
||||||
override fun registerTypeVariables(typeParameters: Collection<TypeParameterDescriptor>) =
|
override fun registerTypeVariables(typeParameters: Collection<TypeParameterDescriptor>) =
|
||||||
registerTypeVariables(CallHandle.NONE, typeParameters)
|
registerTypeVariables(CallHandle.NONE, typeParameters)
|
||||||
|
|
||||||
override fun addSubtypeConstraint(subType: UnwrappedType, superType: UnwrappedType) =
|
override fun addSubtypeConstraint(subType: UnwrappedType, superType: UnwrappedType) =
|
||||||
addSubtypeConstraint(subType, superType, ConstraintPositionKind.VALUE_PARAMETER_POSITION.position(counter++))
|
addSubtypeConstraint(subType, superType, ConstraintPositionKind.VALUE_PARAMETER_POSITION.position(counter++))
|
||||||
|
|
||||||
override fun hasContradiction(): Boolean {
|
override fun hasContradiction(): Boolean {
|
||||||
fixVariables()
|
fixVariables()
|
||||||
@@ -429,8 +443,8 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal fun createTypeForFunctionPlaceholder(
|
internal fun createTypeForFunctionPlaceholder(
|
||||||
functionPlaceholder: KotlinType,
|
functionPlaceholder: KotlinType,
|
||||||
expectedType: KotlinType
|
expectedType: KotlinType
|
||||||
): KotlinType {
|
): KotlinType {
|
||||||
if (!functionPlaceholder.isFunctionPlaceholder) return functionPlaceholder
|
if (!functionPlaceholder.isFunctionPlaceholder) return functionPlaceholder
|
||||||
|
|
||||||
@@ -445,11 +459,12 @@ internal fun createTypeForFunctionPlaceholder(
|
|||||||
val result = arrayListOf<KotlinType>()
|
val result = arrayListOf<KotlinType>()
|
||||||
(1..functionArgumentsSize).forEach { result.add(DONT_CARE) }
|
(1..functionArgumentsSize).forEach { result.add(DONT_CARE) }
|
||||||
result
|
result
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
functionPlaceholderTypeConstructor.argumentTypes
|
functionPlaceholderTypeConstructor.argumentTypes
|
||||||
}
|
}
|
||||||
val receiverType = if (isExtension) DONT_CARE else null
|
val receiverType = if (isExtension) DONT_CARE else null
|
||||||
return createFunctionType(functionPlaceholder.builtIns, Annotations.EMPTY, receiverType, newArgumentTypes, null, DONT_CARE,
|
return createFunctionType(
|
||||||
suspendFunction = expectedType.isSuspendFunctionType)
|
functionPlaceholder.builtIns, Annotations.EMPTY, receiverType, newArgumentTypes, null, DONT_CARE,
|
||||||
|
suspendFunction = expectedType.isSuspendFunctionType
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+23
-24
@@ -33,11 +33,11 @@ import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
internal class ConstraintSystemImpl(
|
internal class ConstraintSystemImpl(
|
||||||
private val allTypeParameterBounds: Map<TypeVariable, TypeBoundsImpl>,
|
private val allTypeParameterBounds: Map<TypeVariable, TypeBoundsImpl>,
|
||||||
private val usedInBounds: Map<TypeVariable, MutableList<TypeBounds.Bound>>,
|
private val usedInBounds: Map<TypeVariable, MutableList<TypeBounds.Bound>>,
|
||||||
private val errors: List<ConstraintError>,
|
private val errors: List<ConstraintError>,
|
||||||
private val initialConstraints: List<ConstraintSystemBuilderImpl.Constraint>,
|
private val initialConstraints: List<ConstraintSystemBuilderImpl.Constraint>,
|
||||||
private val typeVariableSubstitutors: Map<CallHandle, TypeSubstitutor>
|
private val typeVariableSubstitutors: Map<CallHandle, TypeSubstitutor>
|
||||||
) : ConstraintSystem {
|
) : ConstraintSystem {
|
||||||
private val localTypeParameterBounds: Map<TypeVariable, TypeBoundsImpl>
|
private val localTypeParameterBounds: Map<TypeVariable, TypeBoundsImpl>
|
||||||
get() = allTypeParameterBounds.filterNot { it.key.isExternal }
|
get() = allTypeParameterBounds.filterNot { it.key.isExternal }
|
||||||
@@ -48,7 +48,7 @@ internal class ConstraintSystemImpl(
|
|||||||
override fun isSuccessful() = !hasContradiction() && !hasUnknownParameters() && satisfyInitialConstraints()
|
override fun isSuccessful() = !hasContradiction() && !hasUnknownParameters() && satisfyInitialConstraints()
|
||||||
|
|
||||||
override fun hasContradiction() = hasParameterConstraintError() || hasConflictingConstraints()
|
override fun hasContradiction() = hasParameterConstraintError() || hasConflictingConstraints()
|
||||||
|| hasCannotCaptureTypesError() || errors.any { it is TypeInferenceError }
|
|| hasCannotCaptureTypesError() || errors.any { it is TypeInferenceError }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All hacks were removed. This comment is left for information.
|
* All hacks were removed. This comment is left for information.
|
||||||
@@ -84,7 +84,7 @@ internal class ConstraintSystemImpl(
|
|||||||
override fun hasConflictingConstraints() = localTypeParameterBounds.values.any { it.values.size > 1 }
|
override fun hasConflictingConstraints() = localTypeParameterBounds.values.any { it.values.size > 1 }
|
||||||
|
|
||||||
override fun hasUnknownParameters() =
|
override fun hasUnknownParameters() =
|
||||||
localTypeParameterBounds.values.any { it.values.isEmpty() } || hasTypeParameterWithUnsatisfiedOnlyInputTypesError()
|
localTypeParameterBounds.values.any { it.values.isEmpty() } || hasTypeParameterWithUnsatisfiedOnlyInputTypesError()
|
||||||
|
|
||||||
override fun hasParameterConstraintError() = errors.any { it is ParameterConstraintError }
|
override fun hasParameterConstraintError() = errors.any { it is ParameterConstraintError }
|
||||||
|
|
||||||
@@ -101,26 +101,26 @@ internal class ConstraintSystemImpl(
|
|||||||
override fun hasTypeInferenceIncorporationError() = errors.any { it is TypeInferenceError } || !satisfyInitialConstraints()
|
override fun hasTypeInferenceIncorporationError() = errors.any { it is TypeInferenceError } || !satisfyInitialConstraints()
|
||||||
|
|
||||||
override fun hasTypeParameterWithUnsatisfiedOnlyInputTypesError() =
|
override fun hasTypeParameterWithUnsatisfiedOnlyInputTypesError() =
|
||||||
localTypeParameterBounds.values.any { it.typeVariable.hasOnlyInputTypesAnnotation() && it.value == null }
|
localTypeParameterBounds.values.any { it.typeVariable.hasOnlyInputTypesAnnotation() && it.value == null }
|
||||||
|
|
||||||
override val constraintErrors: List<ConstraintError>
|
override val constraintErrors: List<ConstraintError>
|
||||||
get() = errors
|
get() = errors
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getParameterToInferredValueMap(
|
private fun getParameterToInferredValueMap(
|
||||||
typeParameterBounds: Map<TypeVariable, TypeBoundsImpl>,
|
typeParameterBounds: Map<TypeVariable, TypeBoundsImpl>,
|
||||||
getDefaultType: (TypeVariable) -> KotlinType,
|
getDefaultType: (TypeVariable) -> KotlinType,
|
||||||
substituteOriginal: Boolean
|
substituteOriginal: Boolean
|
||||||
): Map<TypeConstructor, TypeProjection> {
|
): Map<TypeConstructor, TypeProjection> {
|
||||||
val substitutionContext = HashMap<TypeConstructor, TypeProjection>()
|
val substitutionContext = HashMap<TypeConstructor, TypeProjection>()
|
||||||
for ((variable, typeBounds) in typeParameterBounds) {
|
for ((variable, typeBounds) in typeParameterBounds) {
|
||||||
val value = typeBounds.value
|
val value = typeBounds.value
|
||||||
val typeConstructor =
|
val typeConstructor =
|
||||||
if (substituteOriginal) variable.originalTypeParameter.typeConstructor
|
if (substituteOriginal) variable.originalTypeParameter.typeConstructor
|
||||||
else variable.type.constructor
|
else variable.type.constructor
|
||||||
val type =
|
val type =
|
||||||
if (value != null && !TypeUtils.contains(value, DONT_CARE)) value
|
if (value != null && !TypeUtils.contains(value, DONT_CARE)) value
|
||||||
else getDefaultType(variable)
|
else getDefaultType(variable)
|
||||||
substitutionContext.put(typeConstructor, TypeProjectionImpl(type))
|
substitutionContext.put(typeConstructor, TypeProjectionImpl(type))
|
||||||
}
|
}
|
||||||
return substitutionContext
|
return substitutionContext
|
||||||
@@ -130,8 +130,8 @@ internal class ConstraintSystemImpl(
|
|||||||
get() = allTypeParameterBounds.keys
|
get() = allTypeParameterBounds.keys
|
||||||
|
|
||||||
override fun getTypeBounds(typeVariable: TypeVariable): TypeBoundsImpl {
|
override fun getTypeBounds(typeVariable: TypeVariable): TypeBoundsImpl {
|
||||||
return allTypeParameterBounds[typeVariable] ?:
|
return allTypeParameterBounds[typeVariable]
|
||||||
throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $typeVariable")
|
?: throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $typeVariable")
|
||||||
}
|
}
|
||||||
|
|
||||||
override val resultingSubstitutor: TypeSubstitutor
|
override val resultingSubstitutor: TypeSubstitutor
|
||||||
@@ -143,11 +143,11 @@ internal class ConstraintSystemImpl(
|
|||||||
private fun getSubstitutor(substituteOriginal: Boolean, getDefaultValue: (TypeVariable) -> KotlinType): TypeSubstitutor {
|
private fun getSubstitutor(substituteOriginal: Boolean, getDefaultValue: (TypeVariable) -> KotlinType): TypeSubstitutor {
|
||||||
val parameterToInferredValueMap = getParameterToInferredValueMap(allTypeParameterBounds, getDefaultValue, substituteOriginal)
|
val parameterToInferredValueMap = getParameterToInferredValueMap(allTypeParameterBounds, getDefaultValue, substituteOriginal)
|
||||||
return TypeSubstitutor.create(
|
return TypeSubstitutor.create(
|
||||||
SubstitutionWithCapturedTypeApproximation(
|
SubstitutionWithCapturedTypeApproximation(
|
||||||
SubstitutionFilteringInternalResolveAnnotations(
|
SubstitutionFilteringInternalResolveAnnotations(
|
||||||
TypeConstructorSubstitution.createByConstructorsMap(parameterToInferredValueMap)
|
TypeConstructorSubstitution.createByConstructorsMap(parameterToInferredValueMap)
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,8 +159,7 @@ internal class ConstraintSystemImpl(
|
|||||||
val substitutor = getSubstitutor(substituteOriginal = false) { ErrorUtils.createUninferredParameterType(it.originalTypeParameter) }
|
val substitutor = getSubstitutor(substituteOriginal = false) { ErrorUtils.createUninferredParameterType(it.originalTypeParameter) }
|
||||||
fun KotlinType.substitute(): KotlinType? = substitutor.substitute(this, Variance.INVARIANT)
|
fun KotlinType.substitute(): KotlinType? = substitutor.substitute(this, Variance.INVARIANT)
|
||||||
|
|
||||||
return initialConstraints.all {
|
return initialConstraints.all { (kind, subtype, superType, position) ->
|
||||||
(kind, subtype, superType, position) ->
|
|
||||||
val resultSubType = subtype.substitute()?.let {
|
val resultSubType = subtype.substitute()?.let {
|
||||||
// the call might be done via safe access, so we check for notNullable receiver type;
|
// the call might be done via safe access, so we check for notNullable receiver type;
|
||||||
// 'unsafe call' error is reported otherwise later
|
// 'unsafe call' error is reported otherwise later
|
||||||
@@ -181,7 +180,7 @@ internal class ConstraintSystemImpl(
|
|||||||
}
|
}
|
||||||
result.usedInBounds.putAll(usedInBounds.map {
|
result.usedInBounds.putAll(usedInBounds.map {
|
||||||
val (variable, bounds) = it
|
val (variable, bounds) = it
|
||||||
variable to bounds.filterTo(arrayListOf<TypeBounds.Bound>()) { filterConstraintPosition(it.position )}
|
variable to bounds.filterTo(arrayListOf<TypeBounds.Bound>()) { filterConstraintPosition(it.position) }
|
||||||
}.toMap())
|
}.toMap())
|
||||||
result.errors.addAll(errors.filter { filterConstraintPosition(it.constraintPosition) })
|
result.errors.addAll(errors.filter { filterConstraintPosition(it.constraintPosition) })
|
||||||
|
|
||||||
|
|||||||
+42
-36
@@ -55,12 +55,12 @@ import org.jetbrains.kotlin.types.typeUtil.contains
|
|||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class TypeTemplate(
|
class TypeTemplate(
|
||||||
val typeVariable: TypeVariable,
|
val typeVariable: TypeVariable,
|
||||||
val coroutineInferenceData: CoroutineInferenceData,
|
val coroutineInferenceData: CoroutineInferenceData,
|
||||||
nullable: Boolean = true
|
nullable: Boolean = true
|
||||||
) : FlexibleType(
|
) : FlexibleType(
|
||||||
typeVariable.originalTypeParameter.builtIns.nothingType,
|
typeVariable.originalTypeParameter.builtIns.nothingType,
|
||||||
typeVariable.originalTypeParameter.builtIns.anyType.makeNullableAsSpecified(nullable)
|
typeVariable.originalTypeParameter.builtIns.anyType.makeNullableAsSpecified(nullable)
|
||||||
) {
|
) {
|
||||||
override fun replaceAnnotations(newAnnotations: Annotations) = this
|
override fun replaceAnnotations(newAnnotations: Annotations) = this
|
||||||
|
|
||||||
@@ -79,9 +79,9 @@ class CoroutineInferenceData {
|
|||||||
private var hereIsBadCall = false
|
private var hereIsBadCall = false
|
||||||
|
|
||||||
fun getTypeTemplate(typeVariable: TypeVariable) =
|
fun getTypeTemplate(typeVariable: TypeVariable) =
|
||||||
typeTemplates.getOrPut(typeVariable) {
|
typeTemplates.getOrPut(typeVariable) {
|
||||||
TypeTemplate(typeVariable, this)
|
TypeTemplate(typeVariable, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun initSystem() {
|
fun initSystem() {
|
||||||
csBuilder.registerTypeVariables(CallHandle.NONE, typeTemplates.keys.map { it.freshTypeParameter })
|
csBuilder.registerTypeVariables(CallHandle.NONE, typeTemplates.keys.map { it.freshTypeParameter })
|
||||||
@@ -115,18 +115,18 @@ class CoroutineInferenceData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class CoroutineInferenceSupport(
|
class CoroutineInferenceSupport(
|
||||||
val argumentTypeResolver: ArgumentTypeResolver,
|
val argumentTypeResolver: ArgumentTypeResolver,
|
||||||
val expressionTypingServices: ExpressionTypingServices
|
val expressionTypingServices: ExpressionTypingServices
|
||||||
) {
|
) {
|
||||||
@set:Inject
|
@set:Inject
|
||||||
lateinit var callCompleter: CallCompleter
|
lateinit var callCompleter: CallCompleter
|
||||||
|
|
||||||
fun analyzeCoroutine(
|
fun analyzeCoroutine(
|
||||||
functionLiteral: KtFunction,
|
functionLiteral: KtFunction,
|
||||||
valueArgument: ValueArgument,
|
valueArgument: ValueArgument,
|
||||||
csBuilder: ConstraintSystem.Builder,
|
csBuilder: ConstraintSystem.Builder,
|
||||||
context: CallCandidateResolutionContext<*>,
|
context: CallCandidateResolutionContext<*>,
|
||||||
lambdaExpectedType: KotlinType
|
lambdaExpectedType: KotlinType
|
||||||
) {
|
) {
|
||||||
val argumentExpression = valueArgument.getArgumentExpression() ?: return
|
val argumentExpression = valueArgument.getArgumentExpression() ?: return
|
||||||
if (!lambdaExpectedType.isSuspendFunctionType) return
|
if (!lambdaExpectedType.isSuspendFunctionType) return
|
||||||
@@ -155,13 +155,16 @@ class CoroutineInferenceSupport(
|
|||||||
val approximationSubstitutor = object : DelegatedTypeSubstitution(constraintSystem.currentSubstitutor.substitution) {
|
val approximationSubstitutor = object : DelegatedTypeSubstitution(constraintSystem.currentSubstitutor.substitution) {
|
||||||
override fun approximateContravariantCapturedTypes() = true
|
override fun approximateContravariantCapturedTypes() = true
|
||||||
}
|
}
|
||||||
val approximatedLambdaType = approximationSubstitutor.buildSubstitutor().substitute(lambdaExpectedType, Variance.IN_VARIANCE) ?: return
|
val approximatedLambdaType =
|
||||||
|
approximationSubstitutor.buildSubstitutor().substitute(lambdaExpectedType, Variance.IN_VARIANCE) ?: return
|
||||||
|
|
||||||
val newExpectedType = createFunctionType(newReceiverType.builtIns, approximatedLambdaType.annotations, newReceiverType,
|
val newExpectedType = createFunctionType(
|
||||||
approximatedLambdaType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType),
|
newReceiverType.builtIns, approximatedLambdaType.annotations, newReceiverType,
|
||||||
parameterNames = null, // TODO: parameterNames
|
approximatedLambdaType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType),
|
||||||
returnType = approximatedLambdaType.getReturnTypeFromFunctionType(),
|
parameterNames = null, // TODO: parameterNames
|
||||||
suspendFunction = true)
|
returnType = approximatedLambdaType.getReturnTypeFromFunctionType(),
|
||||||
|
suspendFunction = true
|
||||||
|
)
|
||||||
|
|
||||||
if (hasUnknownFunctionParameter(newExpectedType)) return
|
if (hasUnknownFunctionParameter(newExpectedType)) return
|
||||||
|
|
||||||
@@ -169,20 +172,21 @@ class CoroutineInferenceSupport(
|
|||||||
|
|
||||||
// this trace shouldn't be committed
|
// this trace shouldn't be committed
|
||||||
val temporaryForCoroutine = TemporaryTraceAndCache.create(
|
val temporaryForCoroutine = TemporaryTraceAndCache.create(
|
||||||
context, "trace for type argument inference for coroutine", functionLiteral)
|
context, "trace for type argument inference for coroutine", functionLiteral
|
||||||
|
)
|
||||||
|
|
||||||
val newContext = context.replaceExpectedType(newExpectedType)
|
val newContext = context.replaceExpectedType(newExpectedType)
|
||||||
.replaceDataFlowInfo(context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument))
|
.replaceDataFlowInfo(context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument))
|
||||||
.replaceContextDependency(ContextDependency.INDEPENDENT).replaceTraceAndCache(temporaryForCoroutine)
|
.replaceContextDependency(ContextDependency.INDEPENDENT).replaceTraceAndCache(temporaryForCoroutine)
|
||||||
argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS)
|
argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS)
|
||||||
|
|
||||||
inferenceData.reportInferenceResult(csBuilder)
|
inferenceData.reportInferenceResult(csBuilder)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun checkCoroutineCalls(
|
fun checkCoroutineCalls(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
tracingStrategy: TracingStrategy,
|
tracingStrategy: TracingStrategy,
|
||||||
overloadResults: OverloadResolutionResultsImpl<*>
|
overloadResults: OverloadResolutionResultsImpl<*>
|
||||||
) {
|
) {
|
||||||
val inferenceData = overloadResults.getCoroutineInferenceData() ?: return
|
val inferenceData = overloadResults.getCoroutineInferenceData() ?: return
|
||||||
|
|
||||||
@@ -197,10 +201,9 @@ class CoroutineInferenceSupport(
|
|||||||
inferenceData.badCallHappened()
|
inferenceData.badCallHappened()
|
||||||
}
|
}
|
||||||
|
|
||||||
forceInferenceForArguments(context) {
|
forceInferenceForArguments(context) { valueArgument: ValueArgument, kotlinType: KotlinType ->
|
||||||
valueArgument: ValueArgument, kotlinType: KotlinType ->
|
|
||||||
val argumentMatch = resultingCall.getArgumentMapping(valueArgument) as? ArgumentMatch
|
val argumentMatch = resultingCall.getArgumentMapping(valueArgument) as? ArgumentMatch
|
||||||
?: return@forceInferenceForArguments
|
?: return@forceInferenceForArguments
|
||||||
|
|
||||||
with(NewKotlinTypeChecker) {
|
with(NewKotlinTypeChecker) {
|
||||||
val parameterType = getEffectiveExpectedType(argumentMatch.valueParameter, valueArgument, context)
|
val parameterType = getEffectiveExpectedType(argumentMatch.valueParameter, valueArgument, context)
|
||||||
@@ -237,7 +240,10 @@ class CoroutineInferenceSupport(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun forceInferenceForArguments(context: CallResolutionContext<*>, callback: (argument: ValueArgument, argumentType: KotlinType) -> Unit) {
|
private fun forceInferenceForArguments(
|
||||||
|
context: CallResolutionContext<*>,
|
||||||
|
callback: (argument: ValueArgument, argumentType: KotlinType) -> Unit
|
||||||
|
) {
|
||||||
val infoForArguments = context.dataFlowInfoForArguments
|
val infoForArguments = context.dataFlowInfoForArguments
|
||||||
val call = context.call
|
val call = context.call
|
||||||
val baseContext = context.replaceContextDependency(ContextDependency.INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE)
|
val baseContext = context.replaceContextDependency(ContextDependency.INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE)
|
||||||
@@ -250,8 +256,8 @@ class CoroutineInferenceSupport(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun getArgumentTypeInfo(
|
private fun getArgumentTypeInfo(
|
||||||
expression: KtExpression,
|
expression: KtExpression,
|
||||||
context: CallResolutionContext<*>
|
context: CallResolutionContext<*>
|
||||||
): KotlinTypeInfo {
|
): KotlinTypeInfo {
|
||||||
getFunctionLiteralArgumentIfAny(expression, context)?.let {
|
getFunctionLiteralArgumentIfAny(expression, context)?.let {
|
||||||
return argumentTypeResolver.getFunctionLiteralTypeInfo(expression, it, context, RESOLVE_FUNCTION_ARGUMENTS)
|
return argumentTypeResolver.getFunctionLiteralTypeInfo(expression, it, context, RESOLVE_FUNCTION_ARGUMENTS)
|
||||||
@@ -266,9 +272,9 @@ class CoroutineInferenceSupport(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun isCoroutineCallWithAdditionalInference(parameterDescriptor: ValueParameterDescriptor, argument: ValueArgument) =
|
fun isCoroutineCallWithAdditionalInference(parameterDescriptor: ValueParameterDescriptor, argument: ValueArgument) =
|
||||||
parameterDescriptor.hasSuspendFunctionType &&
|
parameterDescriptor.hasSuspendFunctionType &&
|
||||||
argument.getArgumentExpression() is KtLambdaExpression &&
|
argument.getArgumentExpression() is KtLambdaExpression &&
|
||||||
parameterDescriptor.type.let { it.isBuiltinFunctionalType && it.getReceiverTypeFromFunctionType() != null }
|
parameterDescriptor.type.let { it.isBuiltinFunctionalType && it.getReceiverTypeFromFunctionType() != null }
|
||||||
|
|
||||||
|
|
||||||
fun OverloadResolutionResultsImpl<*>.isResultWithCoroutineInference() = getCoroutineInferenceData() != null
|
fun OverloadResolutionResultsImpl<*>.isResultWithCoroutineInference() = getCoroutineInferenceData() != null
|
||||||
|
|||||||
@@ -23,32 +23,32 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.hasOnlyInputTypesAnnotation
|
|||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
|
|
||||||
class TypeVariable(
|
class TypeVariable(
|
||||||
val call: CallHandle,
|
val call: CallHandle,
|
||||||
internal val freshTypeParameter: TypeParameterDescriptor,
|
internal val freshTypeParameter: TypeParameterDescriptor,
|
||||||
val originalTypeParameter: TypeParameterDescriptor,
|
val originalTypeParameter: TypeParameterDescriptor,
|
||||||
val isExternal: Boolean
|
val isExternal: Boolean
|
||||||
) {
|
) {
|
||||||
val name: Name get() = originalTypeParameter.name
|
val name: Name get() = originalTypeParameter.name
|
||||||
|
|
||||||
val type: KotlinType get() = freshTypeParameter.defaultType
|
val type: KotlinType get() = freshTypeParameter.defaultType
|
||||||
|
|
||||||
fun hasOnlyInputTypesAnnotation(): Boolean =
|
fun hasOnlyInputTypesAnnotation(): Boolean =
|
||||||
originalTypeParameter.hasOnlyInputTypesAnnotation()
|
originalTypeParameter.hasOnlyInputTypesAnnotation()
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CallHandle {
|
interface CallHandle {
|
||||||
object NONE : CallHandle
|
object NONE : CallHandle
|
||||||
}
|
}
|
||||||
|
|
||||||
class CallBasedCallHandle(val call: Call): CallHandle {
|
class CallBasedCallHandle(val call: Call) : CallHandle {
|
||||||
override fun equals(other: Any?) =
|
override fun equals(other: Any?) =
|
||||||
other is CallBasedCallHandle && call === other.call
|
other is CallBasedCallHandle && call === other.call
|
||||||
|
|
||||||
override fun hashCode() =
|
override fun hashCode() =
|
||||||
System.identityHashCode(call)
|
System.identityHashCode(call)
|
||||||
|
|
||||||
override fun toString() =
|
override fun toString() =
|
||||||
call.toString()
|
call.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Call.toHandle(): CallHandle = CallBasedCallHandle(this)
|
fun Call.toHandle(): CallHandle = CallBasedCallHandle(this)
|
||||||
|
|||||||
+6
-5
@@ -32,11 +32,12 @@ import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypes
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
data class ConstraintContext(
|
data class ConstraintContext(
|
||||||
val position: ConstraintPosition,
|
val position: ConstraintPosition,
|
||||||
// see TypeBounds.Bound.derivedFrom
|
// see TypeBounds.Bound.derivedFrom
|
||||||
val derivedFrom: Set<TypeVariable>? = null,
|
val derivedFrom: Set<TypeVariable>? = null,
|
||||||
val initial: Boolean = false,
|
val initial: Boolean = false,
|
||||||
val initialReduction: Boolean = false)
|
val initialReduction: Boolean = false
|
||||||
|
)
|
||||||
|
|
||||||
fun ConstraintSystemBuilderImpl.incorporateBound(newBound: Bound) {
|
fun ConstraintSystemBuilderImpl.incorporateBound(newBound: Bound) {
|
||||||
val typeVariable = newBound.typeVariable
|
val typeVariable = newBound.typeVariable
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ interface ArgumentMapping {
|
|||||||
fun isError(): Boolean
|
fun isError(): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
object ArgumentUnmapped: ArgumentMapping {
|
object ArgumentUnmapped : ArgumentMapping {
|
||||||
override fun isError(): Boolean = true
|
override fun isError(): Boolean = true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ interface ArgumentMatch : ArgumentMapping {
|
|||||||
override fun isError(): Boolean = status.isError
|
override fun isError(): Boolean = status.isError
|
||||||
}
|
}
|
||||||
|
|
||||||
class ArgumentMatchImpl(override val valueParameter: ValueParameterDescriptor): ArgumentMatch {
|
class ArgumentMatchImpl(override val valueParameter: ValueParameterDescriptor) : ArgumentMatch {
|
||||||
private var _status: ArgumentMatchStatus? = null
|
private var _status: ArgumentMatchStatus? = null
|
||||||
|
|
||||||
override val status: ArgumentMatchStatus
|
override val status: ArgumentMatchStatus
|
||||||
@@ -64,5 +64,4 @@ class ArgumentMatchImpl(override val valueParameter: ValueParameterDescriptor):
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO: temporary hack until status.isSuccess is not always correct
|
//TODO: temporary hack until status.isSuccess is not always correct
|
||||||
fun ResolvedCall<*>.isReallySuccess(): Boolean
|
fun ResolvedCall<*>.isReallySuccess(): Boolean = status.isSuccess && !ErrorUtils.isError(resultingDescriptor)
|
||||||
= status.isSuccess && !ErrorUtils.isError(resultingDescriptor)
|
|
||||||
|
|||||||
+2
-2
@@ -32,8 +32,8 @@ interface VariableAsFunctionMutableResolvedCall : VariableAsFunctionResolvedCall
|
|||||||
}
|
}
|
||||||
|
|
||||||
class VariableAsFunctionResolvedCallImpl(
|
class VariableAsFunctionResolvedCallImpl(
|
||||||
override val functionCall: MutableResolvedCall<FunctionDescriptor>,
|
override val functionCall: MutableResolvedCall<FunctionDescriptor>,
|
||||||
override val variableCall: MutableResolvedCall<VariableDescriptor>
|
override val variableCall: MutableResolvedCall<VariableDescriptor>
|
||||||
) : VariableAsFunctionMutableResolvedCall, MutableResolvedCall<FunctionDescriptor> by functionCall {
|
) : VariableAsFunctionMutableResolvedCall, MutableResolvedCall<FunctionDescriptor> by functionCall {
|
||||||
|
|
||||||
override fun markCallAsCompleted() {
|
override fun markCallAsCompleted() {
|
||||||
|
|||||||
+5
-3
@@ -28,9 +28,11 @@ private val KotlinType.immanentNullability: Nullability
|
|||||||
* This class describes an arbitrary object which has some value in data flow analysis.
|
* This class describes an arbitrary object which has some value in data flow analysis.
|
||||||
* In general case it's some r-value.
|
* In general case it's some r-value.
|
||||||
*/
|
*/
|
||||||
class DataFlowValue(val identifierInfo: IdentifierInfo,
|
class DataFlowValue(
|
||||||
val type: KotlinType,
|
val identifierInfo: IdentifierInfo,
|
||||||
val immanentNullability: Nullability = type.immanentNullability) {
|
val type: KotlinType,
|
||||||
|
val immanentNullability: Nullability = type.immanentNullability
|
||||||
|
) {
|
||||||
|
|
||||||
val kind: Kind get() = identifierInfo.kind
|
val kind: Kind get() = identifierInfo.kind
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -379,7 +379,7 @@ object DataFlowValueFactory {
|
|||||||
|
|
||||||
// Local variable classification: STABLE or CAPTURED
|
// Local variable classification: STABLE or CAPTURED
|
||||||
val preliminaryVisitor = PreliminaryDeclarationVisitor.getVisitorByVariable(variableDescriptor, bindingContext)
|
val preliminaryVisitor = PreliminaryDeclarationVisitor.getVisitorByVariable(variableDescriptor, bindingContext)
|
||||||
// A case when we just analyse an expression alone: counts as captured
|
// A case when we just analyse an expression alone: counts as captured
|
||||||
?: return CAPTURED_VARIABLE
|
?: return CAPTURED_VARIABLE
|
||||||
|
|
||||||
// Analyze who writes variable
|
// Analyze who writes variable
|
||||||
|
|||||||
+87
-57
@@ -30,18 +30,18 @@ import org.jetbrains.kotlin.utils.newLinkedHashSetWithExpectedSize
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
internal class DelegatingDataFlowInfo private constructor(
|
internal class DelegatingDataFlowInfo private constructor(
|
||||||
private val parent: DataFlowInfo?,
|
private val parent: DataFlowInfo?,
|
||||||
private val nullabilityInfo: Map<DataFlowValue, Nullability>,
|
private val nullabilityInfo: Map<DataFlowValue, Nullability>,
|
||||||
// Also immutable
|
// Also immutable
|
||||||
private val typeInfo: SetMultimap<DataFlowValue, KotlinType>,
|
private val typeInfo: SetMultimap<DataFlowValue, KotlinType>,
|
||||||
/**
|
/**
|
||||||
* Value for which type info was cleared or reassigned at this point
|
* Value for which type info was cleared or reassigned at this point
|
||||||
* so parent type info should not be in use
|
* so parent type info should not be in use
|
||||||
*/
|
*/
|
||||||
private val valueWithGivenTypeInfo: DataFlowValue?
|
private val valueWithGivenTypeInfo: DataFlowValue?
|
||||||
) : DataFlowInfo {
|
) : DataFlowInfo {
|
||||||
|
|
||||||
constructor(): this(null, emptyMap(), newTypeInfo(), null)
|
constructor() : this(null, emptyMap(), newTypeInfo(), null)
|
||||||
|
|
||||||
override val completeNullabilityInfo: Map<DataFlowValue, Nullability>
|
override val completeNullabilityInfo: Map<DataFlowValue, Nullability>
|
||||||
get() {
|
get() {
|
||||||
@@ -80,23 +80,22 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
override fun getStableNullability(key: DataFlowValue) = getNullability(key, true)
|
override fun getStableNullability(key: DataFlowValue) = getNullability(key, true)
|
||||||
|
|
||||||
private fun getNullability(key: DataFlowValue, stableOnly: Boolean) =
|
private fun getNullability(key: DataFlowValue, stableOnly: Boolean) =
|
||||||
if (stableOnly && !key.isStable) {
|
if (stableOnly && !key.isStable) {
|
||||||
key.immanentNullability
|
key.immanentNullability
|
||||||
}
|
} else {
|
||||||
else {
|
nullabilityInfo[key] ?: parent?.getCollectedNullability(key) ?: key.immanentNullability
|
||||||
nullabilityInfo[key] ?: parent?.getCollectedNullability(key) ?: key.immanentNullability
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private fun putNullabilityAndTypeInfo(
|
private fun putNullabilityAndTypeInfo(
|
||||||
map: MutableMap<DataFlowValue, Nullability>,
|
map: MutableMap<DataFlowValue, Nullability>,
|
||||||
value: DataFlowValue,
|
value: DataFlowValue,
|
||||||
nullability: Nullability,
|
nullability: Nullability,
|
||||||
languageVersionSettings: LanguageVersionSettings,
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
typeInfo: SetMultimap<DataFlowValue, KotlinType>? = null,
|
typeInfo: SetMultimap<DataFlowValue, KotlinType>? = null,
|
||||||
affectReceiver: Boolean = true,
|
affectReceiver: Boolean = true,
|
||||||
// TODO: remove me in version 1.3! I'm very dirty hack!
|
// TODO: remove me in version 1.3! I'm very dirty hack!
|
||||||
// In normal circumstances this should be always true
|
// In normal circumstances this should be always true
|
||||||
recordUnstable: Boolean = true
|
recordUnstable: Boolean = true
|
||||||
): Boolean {
|
): Boolean {
|
||||||
if (value.isStable || recordUnstable) {
|
if (value.isStable || recordUnstable) {
|
||||||
map.put(value, nullability)
|
map.put(value, nullability)
|
||||||
@@ -110,8 +109,10 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
val receiverType = identifierInfo.receiverType
|
val receiverType = identifierInfo.receiverType
|
||||||
if (identifierInfo.safe && receiverType != null) {
|
if (identifierInfo.safe && receiverType != null) {
|
||||||
val receiverValue = DataFlowValue(identifierInfo.receiverInfo, receiverType)
|
val receiverValue = DataFlowValue(identifierInfo.receiverInfo, receiverType)
|
||||||
putNullabilityAndTypeInfo(map, receiverValue, nullability,
|
putNullabilityAndTypeInfo(
|
||||||
languageVersionSettings, typeInfo, recordUnstable = recordUnstable)
|
map, receiverValue, nullability,
|
||||||
|
languageVersionSettings, typeInfo, recordUnstable = recordUnstable
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is IdentifierInfo.SafeCast -> {
|
is IdentifierInfo.SafeCast -> {
|
||||||
@@ -121,16 +122,20 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
languageVersionSettings.supportsFeature(LanguageFeature.SafeCastCheckBoundSmartCasts)) {
|
languageVersionSettings.supportsFeature(LanguageFeature.SafeCastCheckBoundSmartCasts)) {
|
||||||
|
|
||||||
val subjectValue = DataFlowValue(identifierInfo.subjectInfo, subjectType)
|
val subjectValue = DataFlowValue(identifierInfo.subjectInfo, subjectType)
|
||||||
putNullabilityAndTypeInfo(map, subjectValue, nullability,
|
putNullabilityAndTypeInfo(
|
||||||
languageVersionSettings, typeInfo, recordUnstable = false)
|
map, subjectValue, nullability,
|
||||||
|
languageVersionSettings, typeInfo, recordUnstable = false
|
||||||
|
)
|
||||||
if (subjectValue.isStable) {
|
if (subjectValue.isStable) {
|
||||||
typeInfo?.put(subjectValue, targetType)
|
typeInfo?.put(subjectValue, targetType)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is IdentifierInfo.Variable -> identifierInfo.bound?.let {
|
is IdentifierInfo.Variable -> identifierInfo.bound?.let {
|
||||||
putNullabilityAndTypeInfo(map, it, nullability,
|
putNullabilityAndTypeInfo(
|
||||||
languageVersionSettings, typeInfo, recordUnstable = recordUnstable)
|
map, it, nullability,
|
||||||
|
languageVersionSettings, typeInfo, recordUnstable = recordUnstable
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,12 +144,12 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getCollectedTypes(key: DataFlowValue, languageVersionSettings: LanguageVersionSettings) =
|
override fun getCollectedTypes(key: DataFlowValue, languageVersionSettings: LanguageVersionSettings) =
|
||||||
getCollectedTypes(key, true, languageVersionSettings)
|
getCollectedTypes(key, true, languageVersionSettings)
|
||||||
|
|
||||||
private fun getCollectedTypes(
|
private fun getCollectedTypes(
|
||||||
key: DataFlowValue,
|
key: DataFlowValue,
|
||||||
enrichWithNotNull: Boolean,
|
enrichWithNotNull: Boolean,
|
||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
): Set<KotlinType> {
|
): Set<KotlinType> {
|
||||||
val types = collectTypesFromMeAndParents(key, languageVersionSettings)
|
val types = collectTypesFromMeAndParents(key, languageVersionSettings)
|
||||||
if (!enrichWithNotNull || getCollectedNullability(key).canBeNull()) {
|
if (!enrichWithNotNull || getCollectedNullability(key).canBeNull()) {
|
||||||
@@ -164,10 +169,10 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun getStableTypes(key: DataFlowValue, languageVersionSettings: LanguageVersionSettings) =
|
override fun getStableTypes(key: DataFlowValue, languageVersionSettings: LanguageVersionSettings) =
|
||||||
getStableTypes(key, true, languageVersionSettings)
|
getStableTypes(key, true, languageVersionSettings)
|
||||||
|
|
||||||
private fun getStableTypes(key: DataFlowValue, enrichWithNotNull: Boolean, languageVersionSettings: LanguageVersionSettings) =
|
private fun getStableTypes(key: DataFlowValue, enrichWithNotNull: Boolean, languageVersionSettings: LanguageVersionSettings) =
|
||||||
if (!key.isStable) LinkedHashSet() else getCollectedTypes(key, enrichWithNotNull, languageVersionSettings)
|
if (!key.isStable) LinkedHashSet() else getCollectedTypes(key, enrichWithNotNull, languageVersionSettings)
|
||||||
|
|
||||||
private fun KotlinType.canBeDefinitelyNotNullOrNotNull(settings: LanguageVersionSettings): Boolean {
|
private fun KotlinType.canBeDefinitelyNotNullOrNotNull(settings: LanguageVersionSettings): Boolean {
|
||||||
return if (settings.supportsFeature(LanguageFeature.NewInference))
|
return if (settings.supportsFeature(LanguageFeature.NewInference))
|
||||||
@@ -182,6 +187,7 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
else
|
else
|
||||||
TypeUtils.makeNotNullable(this)
|
TypeUtils.makeNotNullable(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Call this function to clear all data flow information about
|
* Call this function to clear all data flow information about
|
||||||
* the given data flow value.
|
* the given data flow value.
|
||||||
@@ -214,7 +220,7 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun equate(
|
override fun equate(
|
||||||
a: DataFlowValue, b: DataFlowValue, identityEquals: Boolean, languageVersionSettings: LanguageVersionSettings
|
a: DataFlowValue, b: DataFlowValue, identityEquals: Boolean, languageVersionSettings: LanguageVersionSettings
|
||||||
): DataFlowInfo {
|
): DataFlowInfo {
|
||||||
val resultNullabilityInfo = hashMapOf<DataFlowValue, Nullability>()
|
val resultNullabilityInfo = hashMapOf<DataFlowValue, Nullability>()
|
||||||
val nullabilityOfA = getStableNullability(a)
|
val nullabilityOfA = getStableNullability(a)
|
||||||
@@ -222,8 +228,20 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
|
|
||||||
val newTypeInfo = newTypeInfo()
|
val newTypeInfo = newTypeInfo()
|
||||||
var changed =
|
var changed =
|
||||||
putNullabilityAndTypeInfo(resultNullabilityInfo, a, nullabilityOfA.refine(nullabilityOfB), languageVersionSettings, newTypeInfo) or
|
putNullabilityAndTypeInfo(
|
||||||
putNullabilityAndTypeInfo(resultNullabilityInfo, b, nullabilityOfB.refine(nullabilityOfA), languageVersionSettings, newTypeInfo)
|
resultNullabilityInfo,
|
||||||
|
a,
|
||||||
|
nullabilityOfA.refine(nullabilityOfB),
|
||||||
|
languageVersionSettings,
|
||||||
|
newTypeInfo
|
||||||
|
) or
|
||||||
|
putNullabilityAndTypeInfo(
|
||||||
|
resultNullabilityInfo,
|
||||||
|
b,
|
||||||
|
nullabilityOfB.refine(nullabilityOfA),
|
||||||
|
languageVersionSettings,
|
||||||
|
newTypeInfo
|
||||||
|
)
|
||||||
|
|
||||||
// NB: == has no guarantees of type equality, see KT-11280 for the example
|
// NB: == has no guarantees of type equality, see KT-11280 for the example
|
||||||
if (identityEquals || !nullabilityOfA.canBeNonNull() || !nullabilityOfB.canBeNonNull()) {
|
if (identityEquals || !nullabilityOfA.canBeNonNull() || !nullabilityOfB.canBeNonNull()) {
|
||||||
@@ -252,8 +270,7 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
if (current is DelegatingDataFlowInfo) {
|
if (current is DelegatingDataFlowInfo) {
|
||||||
types.addAll(current.typeInfo.get(value))
|
types.addAll(current.typeInfo.get(value))
|
||||||
current = if (value == current.valueWithGivenTypeInfo) null else current.parent
|
current = if (value == current.valueWithGivenTypeInfo) null else current.parent
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
types.addAll(current.getCollectedTypes(value, languageVersionSettings))
|
types.addAll(current.getCollectedTypes(value, languageVersionSettings))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@@ -263,7 +280,7 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun disequate(
|
override fun disequate(
|
||||||
a: DataFlowValue, b: DataFlowValue, languageVersionSettings: LanguageVersionSettings
|
a: DataFlowValue, b: DataFlowValue, languageVersionSettings: LanguageVersionSettings
|
||||||
): DataFlowInfo {
|
): DataFlowInfo {
|
||||||
val resultNullabilityInfo = hashMapOf<DataFlowValue, Nullability>()
|
val resultNullabilityInfo = hashMapOf<DataFlowValue, Nullability>()
|
||||||
val nullabilityOfA = getStableNullability(a)
|
val nullabilityOfA = getStableNullability(a)
|
||||||
@@ -271,15 +288,27 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
|
|
||||||
val newTypeInfo = newTypeInfo()
|
val newTypeInfo = newTypeInfo()
|
||||||
val changed =
|
val changed =
|
||||||
putNullabilityAndTypeInfo(resultNullabilityInfo, a, nullabilityOfA.refine(nullabilityOfB.invert()), languageVersionSettings, newTypeInfo) or
|
putNullabilityAndTypeInfo(
|
||||||
putNullabilityAndTypeInfo(resultNullabilityInfo, b, nullabilityOfB.refine(nullabilityOfA.invert()), languageVersionSettings, newTypeInfo)
|
resultNullabilityInfo,
|
||||||
|
a,
|
||||||
|
nullabilityOfA.refine(nullabilityOfB.invert()),
|
||||||
|
languageVersionSettings,
|
||||||
|
newTypeInfo
|
||||||
|
) or
|
||||||
|
putNullabilityAndTypeInfo(
|
||||||
|
resultNullabilityInfo,
|
||||||
|
b,
|
||||||
|
nullabilityOfB.refine(nullabilityOfA.invert()),
|
||||||
|
languageVersionSettings,
|
||||||
|
newTypeInfo
|
||||||
|
)
|
||||||
|
|
||||||
return if (changed) create(this, resultNullabilityInfo, if (newTypeInfo.isEmpty) EMPTY_TYPE_INFO else newTypeInfo) else this
|
return if (changed) create(this, resultNullabilityInfo, if (newTypeInfo.isEmpty) EMPTY_TYPE_INFO else newTypeInfo) else this
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun establishSubtyping(
|
override fun establishSubtyping(
|
||||||
value: DataFlowValue, type: KotlinType, languageVersionSettings: LanguageVersionSettings
|
value: DataFlowValue, type: KotlinType, languageVersionSettings: LanguageVersionSettings
|
||||||
): DataFlowInfo {
|
): DataFlowInfo {
|
||||||
if (value.type == type) return this
|
if (value.type == type) return this
|
||||||
if (getCollectedTypes(value, languageVersionSettings).contains(type)) return this
|
if (getCollectedTypes(value, languageVersionSettings).contains(type)) return this
|
||||||
@@ -321,11 +350,11 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
private fun Set<KotlinType>.containsNothing() = any { KotlinBuiltIns.isNothing(it) }
|
private fun Set<KotlinType>.containsNothing() = any { KotlinBuiltIns.isNothing(it) }
|
||||||
|
|
||||||
private fun Set<KotlinType>.intersectConsideringNothing(other: Set<KotlinType>) =
|
private fun Set<KotlinType>.intersectConsideringNothing(other: Set<KotlinType>) =
|
||||||
when {
|
when {
|
||||||
other.containsNothing() -> this
|
other.containsNothing() -> this
|
||||||
this.containsNothing() -> other
|
this.containsNothing() -> other
|
||||||
else -> this.intersect(other)
|
else -> this.intersect(other)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun or(other: DataFlowInfo): DataFlowInfo {
|
override fun or(other: DataFlowInfo): DataFlowInfo {
|
||||||
if (other === DataFlowInfo.EMPTY) return DataFlowInfo.EMPTY
|
if (other === DataFlowInfo.EMPTY) return DataFlowInfo.EMPTY
|
||||||
@@ -358,15 +387,16 @@ internal class DelegatingDataFlowInfo private constructor(
|
|||||||
private val EMPTY_TYPE_INFO = newTypeInfo()
|
private val EMPTY_TYPE_INFO = newTypeInfo()
|
||||||
|
|
||||||
private fun containsAll(first: SetMultimap<DataFlowValue, KotlinType>, second: SetMultimap<DataFlowValue, KotlinType>) =
|
private fun containsAll(first: SetMultimap<DataFlowValue, KotlinType>, second: SetMultimap<DataFlowValue, KotlinType>) =
|
||||||
first.entries().containsAll(second.entries())
|
first.entries().containsAll(second.entries())
|
||||||
|
|
||||||
fun newTypeInfo(): SetMultimap<DataFlowValue, KotlinType> = LinkedHashMultimap.create<DataFlowValue, KotlinType>()
|
fun newTypeInfo(): SetMultimap<DataFlowValue, KotlinType> = LinkedHashMultimap.create<DataFlowValue, KotlinType>()
|
||||||
|
|
||||||
private fun create(parent: DataFlowInfo?,
|
private fun create(
|
||||||
nullabilityInfo: Map<DataFlowValue, Nullability>,
|
parent: DataFlowInfo?,
|
||||||
// NB: typeInfo must be mutable here!
|
nullabilityInfo: Map<DataFlowValue, Nullability>,
|
||||||
typeInfo: SetMultimap<DataFlowValue, KotlinType>,
|
// NB: typeInfo must be mutable here!
|
||||||
valueWithGivenTypeInfo: DataFlowValue? = null
|
typeInfo: SetMultimap<DataFlowValue, KotlinType>,
|
||||||
|
valueWithGivenTypeInfo: DataFlowValue? = null
|
||||||
): DataFlowInfo {
|
): DataFlowInfo {
|
||||||
val toDelete = newTypeInfo()
|
val toDelete = newTypeInfo()
|
||||||
for (value in typeInfo.keys()) {
|
for (value in typeInfo.keys()) {
|
||||||
|
|||||||
@@ -81,33 +81,32 @@ class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: Kotli
|
|||||||
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> {
|
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> {
|
||||||
return if (call.valueArgumentList == null && call.valueArguments.isEmpty()) {
|
return if (call.valueArgumentList == null && call.valueArguments.isEmpty()) {
|
||||||
listOf(createDynamicProperty(owner, name, call))
|
listOf(createDynamicProperty(owner, name, call))
|
||||||
}
|
} else listOf()
|
||||||
else listOf()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createDynamicProperty(owner: DeclarationDescriptor, name: Name, call: Call): PropertyDescriptorImpl {
|
private fun createDynamicProperty(owner: DeclarationDescriptor, name: Name, call: Call): PropertyDescriptorImpl {
|
||||||
val propertyDescriptor = PropertyDescriptorImpl.create(
|
val propertyDescriptor = PropertyDescriptorImpl.create(
|
||||||
owner,
|
owner,
|
||||||
Annotations.EMPTY,
|
Annotations.EMPTY,
|
||||||
Modality.FINAL,
|
Modality.FINAL,
|
||||||
Visibilities.PUBLIC,
|
Visibilities.PUBLIC,
|
||||||
true,
|
true,
|
||||||
name,
|
name,
|
||||||
CallableMemberDescriptor.Kind.DECLARATION,
|
CallableMemberDescriptor.Kind.DECLARATION,
|
||||||
SourceElement.NO_SOURCE,
|
SourceElement.NO_SOURCE,
|
||||||
/* lateInit = */ false,
|
/* lateInit = */ false,
|
||||||
/* isConst = */ false,
|
/* isConst = */ false,
|
||||||
/* isExpect = */ false,
|
/* isExpect = */ false,
|
||||||
/* isActual = */ false,
|
/* isActual = */ false,
|
||||||
/* isExternal = */ false,
|
/* isExternal = */ false,
|
||||||
/* isDelegated = */ false
|
/* isDelegated = */ false
|
||||||
)
|
)
|
||||||
propertyDescriptor.setType(
|
propertyDescriptor.setType(
|
||||||
dynamicType,
|
dynamicType,
|
||||||
createTypeParameters(propertyDescriptor, call),
|
createTypeParameters(propertyDescriptor, call),
|
||||||
createDynamicDispatchReceiverParameter(propertyDescriptor),
|
createDynamicDispatchReceiverParameter(propertyDescriptor),
|
||||||
null as KotlinType?
|
null as KotlinType?
|
||||||
)
|
)
|
||||||
|
|
||||||
val getter = DescriptorFactory.createDefaultGetter(propertyDescriptor, Annotations.EMPTY)
|
val getter = DescriptorFactory.createDefaultGetter(propertyDescriptor, Annotations.EMPTY)
|
||||||
@@ -121,20 +120,20 @@ class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: Kotli
|
|||||||
|
|
||||||
private fun createDynamicFunction(owner: DeclarationDescriptor, name: Name, call: Call): SimpleFunctionDescriptorImpl {
|
private fun createDynamicFunction(owner: DeclarationDescriptor, name: Name, call: Call): SimpleFunctionDescriptorImpl {
|
||||||
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
|
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||||
owner,
|
owner,
|
||||||
Annotations.EMPTY,
|
Annotations.EMPTY,
|
||||||
name,
|
name,
|
||||||
CallableMemberDescriptor.Kind.DECLARATION,
|
CallableMemberDescriptor.Kind.DECLARATION,
|
||||||
SourceElement.NO_SOURCE
|
SourceElement.NO_SOURCE
|
||||||
)
|
)
|
||||||
functionDescriptor.initialize(
|
functionDescriptor.initialize(
|
||||||
null,
|
null,
|
||||||
createDynamicDispatchReceiverParameter(functionDescriptor),
|
createDynamicDispatchReceiverParameter(functionDescriptor),
|
||||||
createTypeParameters(functionDescriptor, call),
|
createTypeParameters(functionDescriptor, call),
|
||||||
createValueParameters(functionDescriptor, call),
|
createValueParameters(functionDescriptor, call),
|
||||||
dynamicType,
|
dynamicType,
|
||||||
Modality.FINAL,
|
Modality.FINAL,
|
||||||
Visibilities.PUBLIC
|
Visibilities.PUBLIC
|
||||||
)
|
)
|
||||||
functionDescriptor.setHasSynthesizedParameterNames(true)
|
functionDescriptor.setHasSynthesizedParameterNames(true)
|
||||||
return functionDescriptor
|
return functionDescriptor
|
||||||
@@ -144,26 +143,27 @@ class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: Kotli
|
|||||||
return ReceiverParameterDescriptorImpl(owner, TransientReceiver(dynamicType))
|
return ReceiverParameterDescriptorImpl(owner, TransientReceiver(dynamicType))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createTypeParameters(owner: DeclarationDescriptor, call: Call): List<TypeParameterDescriptor> = call.typeArguments.indices.map {
|
private fun createTypeParameters(owner: DeclarationDescriptor, call: Call): List<TypeParameterDescriptor> =
|
||||||
index
|
call.typeArguments.indices.map { index
|
||||||
->
|
->
|
||||||
TypeParameterDescriptorImpl.createWithDefaultBound(
|
TypeParameterDescriptorImpl.createWithDefaultBound(
|
||||||
owner,
|
owner,
|
||||||
Annotations.EMPTY,
|
Annotations.EMPTY,
|
||||||
false,
|
false,
|
||||||
Variance.INVARIANT,
|
Variance.INVARIANT,
|
||||||
Name.identifier("T$index"),
|
Name.identifier("T$index"),
|
||||||
index
|
index
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createValueParameters(owner: FunctionDescriptor, call: Call): List<ValueParameterDescriptor> {
|
private fun createValueParameters(owner: FunctionDescriptor, call: Call): List<ValueParameterDescriptor> {
|
||||||
val parameters = ArrayList<ValueParameterDescriptor>()
|
val parameters = ArrayList<ValueParameterDescriptor>()
|
||||||
|
|
||||||
fun addParameter(arg : ValueArgument, outType: KotlinType, varargElementType: KotlinType?) {
|
fun addParameter(arg: ValueArgument, outType: KotlinType, varargElementType: KotlinType?) {
|
||||||
val index = parameters.size
|
val index = parameters.size
|
||||||
|
|
||||||
parameters.add(ValueParameterDescriptorImpl(
|
parameters.add(
|
||||||
|
ValueParameterDescriptorImpl(
|
||||||
owner,
|
owner,
|
||||||
null,
|
null,
|
||||||
index,
|
index,
|
||||||
@@ -175,7 +175,8 @@ class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: Kotli
|
|||||||
/* isNoinline = */ false,
|
/* isNoinline = */ false,
|
||||||
varargElementType,
|
varargElementType,
|
||||||
SourceElement.NO_SOURCE
|
SourceElement.NO_SOURCE
|
||||||
))
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getFunctionType(funLiteralExpr: KtLambdaExpression): KotlinType {
|
fun getFunctionType(funLiteralExpr: KtLambdaExpression): KotlinType {
|
||||||
|
|||||||
+42
-37
@@ -55,14 +55,14 @@ import org.jetbrains.kotlin.utils.addIfNotNull
|
|||||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||||
|
|
||||||
class KotlinResolutionCallbacksImpl(
|
class KotlinResolutionCallbacksImpl(
|
||||||
topLevelCallContext: BasicCallResolutionContext,
|
topLevelCallContext: BasicCallResolutionContext,
|
||||||
val expressionTypingServices: ExpressionTypingServices,
|
val expressionTypingServices: ExpressionTypingServices,
|
||||||
val typeApproximator: TypeApproximator,
|
val typeApproximator: TypeApproximator,
|
||||||
val argumentTypeResolver: ArgumentTypeResolver,
|
val argumentTypeResolver: ArgumentTypeResolver,
|
||||||
val languageVersionSettings: LanguageVersionSettings,
|
val languageVersionSettings: LanguageVersionSettings,
|
||||||
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||||
val constantExpressionEvaluator: ConstantExpressionEvaluator
|
val constantExpressionEvaluator: ConstantExpressionEvaluator
|
||||||
): KotlinResolutionCallbacks {
|
) : KotlinResolutionCallbacks {
|
||||||
val trace: BindingTrace = topLevelCallContext.trace
|
val trace: BindingTrace = topLevelCallContext.trace
|
||||||
|
|
||||||
class LambdaInfo(val expectedType: UnwrappedType, val contextDependency: ContextDependency) {
|
class LambdaInfo(val expectedType: UnwrappedType, val contextDependency: ContextDependency) {
|
||||||
@@ -75,35 +75,42 @@ class KotlinResolutionCallbacksImpl(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun analyzeAndGetLambdaReturnArguments(
|
override fun analyzeAndGetLambdaReturnArguments(
|
||||||
lambdaArgument: LambdaKotlinCallArgument,
|
lambdaArgument: LambdaKotlinCallArgument,
|
||||||
isSuspend: Boolean,
|
isSuspend: Boolean,
|
||||||
receiverType: UnwrappedType?,
|
receiverType: UnwrappedType?,
|
||||||
parameters: List<UnwrappedType>,
|
parameters: List<UnwrappedType>,
|
||||||
expectedReturnType: UnwrappedType?
|
expectedReturnType: UnwrappedType?
|
||||||
): List<SimpleKotlinCallArgument> {
|
): List<SimpleKotlinCallArgument> {
|
||||||
val psiCallArgument = lambdaArgument.psiCallArgument as PSIFunctionKotlinCallArgument
|
val psiCallArgument = lambdaArgument.psiCallArgument as PSIFunctionKotlinCallArgument
|
||||||
val outerCallContext = psiCallArgument.outerCallContext
|
val outerCallContext = psiCallArgument.outerCallContext
|
||||||
|
|
||||||
fun createCallArgument(ktExpression: KtExpression, typeInfo: KotlinTypeInfo) =
|
fun createCallArgument(ktExpression: KtExpression, typeInfo: KotlinTypeInfo) =
|
||||||
createSimplePSICallArgument(trace.bindingContext, outerCallContext.statementFilter, outerCallContext.scope.ownerDescriptor,
|
createSimplePSICallArgument(
|
||||||
CallMaker.makeExternalValueArgument(ktExpression), DataFlowInfo.EMPTY, typeInfo, languageVersionSettings)
|
trace.bindingContext, outerCallContext.statementFilter, outerCallContext.scope.ownerDescriptor,
|
||||||
|
CallMaker.makeExternalValueArgument(ktExpression), DataFlowInfo.EMPTY, typeInfo, languageVersionSettings
|
||||||
|
)
|
||||||
|
|
||||||
val lambdaInfo = LambdaInfo(expectedReturnType ?: TypeUtils.NO_EXPECTED_TYPE,
|
val lambdaInfo = LambdaInfo(
|
||||||
if (expectedReturnType == null) ContextDependency.DEPENDENT else ContextDependency.INDEPENDENT)
|
expectedReturnType ?: TypeUtils.NO_EXPECTED_TYPE,
|
||||||
|
if (expectedReturnType == null) ContextDependency.DEPENDENT else ContextDependency.INDEPENDENT
|
||||||
|
)
|
||||||
|
|
||||||
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, lambdaInfo)
|
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, lambdaInfo)
|
||||||
|
|
||||||
val builtIns = outerCallContext.scope.ownerDescriptor.builtIns
|
val builtIns = outerCallContext.scope.ownerDescriptor.builtIns
|
||||||
val expectedType = createFunctionType(builtIns, Annotations.EMPTY, receiverType, parameters, null,
|
val expectedType = createFunctionType(
|
||||||
lambdaInfo.expectedType, isSuspend)
|
builtIns, Annotations.EMPTY, receiverType, parameters, null,
|
||||||
|
lambdaInfo.expectedType, isSuspend
|
||||||
|
)
|
||||||
|
|
||||||
val approximatesExpectedType = typeApproximator.approximateToSubType(expectedType, TypeApproximatorConfiguration.LocalDeclaration) ?: expectedType
|
val approximatesExpectedType =
|
||||||
|
typeApproximator.approximateToSubType(expectedType, TypeApproximatorConfiguration.LocalDeclaration) ?: expectedType
|
||||||
|
|
||||||
val actualContext = outerCallContext
|
val actualContext = outerCallContext
|
||||||
.replaceBindingTrace(trace)
|
.replaceBindingTrace(trace)
|
||||||
.replaceContextDependency(lambdaInfo.contextDependency)
|
.replaceContextDependency(lambdaInfo.contextDependency)
|
||||||
.replaceExpectedType(approximatesExpectedType)
|
.replaceExpectedType(approximatesExpectedType)
|
||||||
.replaceDataFlowInfo(psiCallArgument.lambdaInitialDataFlowInfo)
|
.replaceDataFlowInfo(psiCallArgument.lambdaInitialDataFlowInfo)
|
||||||
|
|
||||||
val functionTypeInfo = expressionTypingServices.getTypeInfo(psiCallArgument.expression, actualContext)
|
val functionTypeInfo = expressionTypingServices.getTypeInfo(psiCallArgument.expression, actualContext)
|
||||||
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, LambdaInfo.STUB_EMPTY)
|
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, LambdaInfo.STUB_EMPTY)
|
||||||
@@ -113,11 +120,10 @@ class KotlinResolutionCallbacksImpl(
|
|||||||
val returnedExpression = expression.returnedExpression
|
val returnedExpression = expression.returnedExpression
|
||||||
if (returnedExpression != null) {
|
if (returnedExpression != null) {
|
||||||
createCallArgument(
|
createCallArgument(
|
||||||
returnedExpression,
|
returnedExpression,
|
||||||
typeInfo ?: throw AssertionError("typeInfo should be non-null for return with expression")
|
typeInfo ?: throw AssertionError("typeInfo should be non-null for return with expression")
|
||||||
)
|
)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
hasReturnWithoutExpression = true
|
hasReturnWithoutExpression = true
|
||||||
EmptyLabeledReturn(expression, builtIns)
|
EmptyLabeledReturn(expression, builtIns)
|
||||||
}
|
}
|
||||||
@@ -141,8 +147,7 @@ class KotlinResolutionCallbacksImpl(
|
|||||||
val lastExpression: KtExpression?
|
val lastExpression: KtExpression?
|
||||||
if (psiCallArgument is LambdaKotlinCallArgumentImpl) {
|
if (psiCallArgument is LambdaKotlinCallArgumentImpl) {
|
||||||
lastExpression = psiCallArgument.ktLambdaExpression.bodyExpression?.statements?.lastOrNull()
|
lastExpression = psiCallArgument.ktLambdaExpression.bodyExpression?.statements?.lastOrNull()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
lastExpression = (psiCallArgument as FunctionExpressionImpl).ktFunction.bodyExpression?.lastBlockStatementOrThis()
|
lastExpression = (psiCallArgument as FunctionExpressionImpl).ktFunction.bodyExpression?.lastBlockStatementOrThis()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -159,11 +164,11 @@ class KotlinResolutionCallbacksImpl(
|
|||||||
val expression = psiKotlinCall.psiCall.callElement.safeAs<KtExpression>() ?: return null
|
val expression = psiKotlinCall.psiCall.callElement.safeAs<KtExpression>() ?: return null
|
||||||
|
|
||||||
return transformToReceiverWithSmartCastInfo(
|
return transformToReceiverWithSmartCastInfo(
|
||||||
resolvedAtom.candidateDescriptor,
|
resolvedAtom.candidateDescriptor,
|
||||||
trace.bindingContext,
|
trace.bindingContext,
|
||||||
psiKotlinCall.resultDataFlowInfo,
|
psiKotlinCall.resultDataFlowInfo,
|
||||||
ExpressionReceiver.create(expression, returnType, trace.bindingContext),
|
ExpressionReceiver.create(expression, returnType, trace.bindingContext),
|
||||||
languageVersionSettings
|
languageVersionSettings
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,8 +184,8 @@ class KotlinResolutionCallbacksImpl(
|
|||||||
val expression = findCommonParent(callElement, resolvedAtom.atom.psiKotlinCall.explicitReceiver)
|
val expression = findCommonParent(callElement, resolvedAtom.atom.psiKotlinCall.explicitReceiver)
|
||||||
|
|
||||||
val temporaryBindingTrace = TemporaryBindingTrace.create(
|
val temporaryBindingTrace = TemporaryBindingTrace.create(
|
||||||
trace,
|
trace,
|
||||||
"Trace to check if some expression is constant, we have to avoid writing probably wrong COMPILE_TIME_VALUE slice"
|
"Trace to check if some expression is constant, we have to avoid writing probably wrong COMPILE_TIME_VALUE slice"
|
||||||
)
|
)
|
||||||
return constantExpressionEvaluator.evaluateExpression(expression, temporaryBindingTrace, expectedType) != null
|
return constantExpressionEvaluator.evaluateExpression(expression, temporaryBindingTrace, expectedType) != null
|
||||||
}
|
}
|
||||||
|
|||||||
+158
-121
@@ -61,39 +61,45 @@ import java.lang.IllegalStateException
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class NewResolutionOldInference(
|
class NewResolutionOldInference(
|
||||||
private val candidateResolver: CandidateResolver,
|
private val candidateResolver: CandidateResolver,
|
||||||
private val towerResolver: TowerResolver,
|
private val towerResolver: TowerResolver,
|
||||||
private val resolutionResultsHandler: ResolutionResultsHandler,
|
private val resolutionResultsHandler: ResolutionResultsHandler,
|
||||||
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
|
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
|
||||||
private val syntheticScopes: SyntheticScopes,
|
private val syntheticScopes: SyntheticScopes,
|
||||||
private val languageVersionSettings: LanguageVersionSettings,
|
private val languageVersionSettings: LanguageVersionSettings,
|
||||||
private val coroutineInferenceSupport: CoroutineInferenceSupport,
|
private val coroutineInferenceSupport: CoroutineInferenceSupport,
|
||||||
private val deprecationResolver: DeprecationResolver
|
private val deprecationResolver: DeprecationResolver
|
||||||
) {
|
) {
|
||||||
sealed class ResolutionKind<D : CallableDescriptor>(val kotlinCallKind: KotlinCallKind = KotlinCallKind.UNSUPPORTED) {
|
sealed class ResolutionKind<D : CallableDescriptor>(val kotlinCallKind: KotlinCallKind = KotlinCallKind.UNSUPPORTED) {
|
||||||
abstract internal fun createTowerProcessor(
|
abstract internal fun createTowerProcessor(
|
||||||
outer: NewResolutionOldInference,
|
outer: NewResolutionOldInference,
|
||||||
name: Name,
|
name: Name,
|
||||||
tracing: TracingStrategy,
|
tracing: TracingStrategy,
|
||||||
scopeTower: ImplicitScopeTower,
|
scopeTower: ImplicitScopeTower,
|
||||||
explicitReceiver: DetailedReceiver?,
|
explicitReceiver: DetailedReceiver?,
|
||||||
context: BasicCallResolutionContext
|
context: BasicCallResolutionContext
|
||||||
): ScopeTowerProcessor<MyCandidate>
|
): ScopeTowerProcessor<MyCandidate>
|
||||||
|
|
||||||
object Function : ResolutionKind<FunctionDescriptor>(KotlinCallKind.FUNCTION) {
|
object Function : ResolutionKind<FunctionDescriptor>(KotlinCallKind.FUNCTION) {
|
||||||
override fun createTowerProcessor(
|
override fun createTowerProcessor(
|
||||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||||
): ScopeTowerProcessor<MyCandidate> {
|
): ScopeTowerProcessor<MyCandidate> {
|
||||||
val functionFactory = outer.CandidateFactoryImpl(name, context, tracing)
|
val functionFactory = outer.CandidateFactoryImpl(name, context, tracing)
|
||||||
return createFunctionProcessor(scopeTower, name, functionFactory, outer.CandidateFactoryProviderForInvokeImpl(functionFactory), explicitReceiver)
|
return createFunctionProcessor(
|
||||||
|
scopeTower,
|
||||||
|
name,
|
||||||
|
functionFactory,
|
||||||
|
outer.CandidateFactoryProviderForInvokeImpl(functionFactory),
|
||||||
|
explicitReceiver
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object Variable : ResolutionKind<VariableDescriptor>(KotlinCallKind.VARIABLE) {
|
object Variable : ResolutionKind<VariableDescriptor>(KotlinCallKind.VARIABLE) {
|
||||||
override fun createTowerProcessor(
|
override fun createTowerProcessor(
|
||||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||||
): ScopeTowerProcessor<MyCandidate> {
|
): ScopeTowerProcessor<MyCandidate> {
|
||||||
val variableFactory = outer.CandidateFactoryImpl(name, context, tracing)
|
val variableFactory = outer.CandidateFactoryImpl(name, context, tracing)
|
||||||
return createVariableAndObjectProcessor(scopeTower, name, variableFactory, explicitReceiver)
|
return createVariableAndObjectProcessor(scopeTower, name, variableFactory, explicitReceiver)
|
||||||
@@ -102,22 +108,22 @@ class NewResolutionOldInference(
|
|||||||
|
|
||||||
object CallableReference : ResolutionKind<CallableDescriptor>() {
|
object CallableReference : ResolutionKind<CallableDescriptor>() {
|
||||||
override fun createTowerProcessor(
|
override fun createTowerProcessor(
|
||||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||||
): ScopeTowerProcessor<MyCandidate> {
|
): ScopeTowerProcessor<MyCandidate> {
|
||||||
val functionFactory = outer.CandidateFactoryImpl(name, context, tracing)
|
val functionFactory = outer.CandidateFactoryImpl(name, context, tracing)
|
||||||
val variableFactory = outer.CandidateFactoryImpl(name, context, tracing)
|
val variableFactory = outer.CandidateFactoryImpl(name, context, tracing)
|
||||||
return PrioritizedCompositeScopeTowerProcessor(
|
return PrioritizedCompositeScopeTowerProcessor(
|
||||||
createSimpleFunctionProcessor(scopeTower, name, functionFactory, explicitReceiver, classValueReceiver = false),
|
createSimpleFunctionProcessor(scopeTower, name, functionFactory, explicitReceiver, classValueReceiver = false),
|
||||||
createVariableProcessor(scopeTower, name, variableFactory, explicitReceiver, classValueReceiver = false)
|
createVariableProcessor(scopeTower, name, variableFactory, explicitReceiver, classValueReceiver = false)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object Invoke : ResolutionKind<FunctionDescriptor>() {
|
object Invoke : ResolutionKind<FunctionDescriptor>() {
|
||||||
override fun createTowerProcessor(
|
override fun createTowerProcessor(
|
||||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||||
): ScopeTowerProcessor<MyCandidate> {
|
): ScopeTowerProcessor<MyCandidate> {
|
||||||
val functionFactory = outer.CandidateFactoryImpl(name, context, tracing)
|
val functionFactory = outer.CandidateFactoryImpl(name, context, tracing)
|
||||||
// todo
|
// todo
|
||||||
@@ -125,7 +131,12 @@ class NewResolutionOldInference(
|
|||||||
"Call should be CallForImplicitInvoke, but it is: ${context.call}"
|
"Call should be CallForImplicitInvoke, but it is: ${context.call}"
|
||||||
}
|
}
|
||||||
return createProcessorWithReceiverValueOrEmpty(explicitReceiver) {
|
return createProcessorWithReceiverValueOrEmpty(explicitReceiver) {
|
||||||
createCallTowerProcessorForExplicitInvoke(scopeTower, functionFactory, context.transformToReceiverWithSmartCastInfo(call.dispatchReceiver), it)
|
createCallTowerProcessorForExplicitInvoke(
|
||||||
|
scopeTower,
|
||||||
|
functionFactory,
|
||||||
|
context.transformToReceiverWithSmartCastInfo(call.dispatchReceiver),
|
||||||
|
it
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,8 +144,8 @@ class NewResolutionOldInference(
|
|||||||
|
|
||||||
class GivenCandidates<D : CallableDescriptor> : ResolutionKind<D>() {
|
class GivenCandidates<D : CallableDescriptor> : ResolutionKind<D>() {
|
||||||
override fun createTowerProcessor(
|
override fun createTowerProcessor(
|
||||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||||
): ScopeTowerProcessor<MyCandidate> {
|
): ScopeTowerProcessor<MyCandidate> {
|
||||||
throw IllegalStateException("Should be not called")
|
throw IllegalStateException("Should be not called")
|
||||||
}
|
}
|
||||||
@@ -142,16 +153,15 @@ class NewResolutionOldInference(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <D : CallableDescriptor> runResolution(
|
fun <D : CallableDescriptor> runResolution(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
name: Name,
|
name: Name,
|
||||||
kind: ResolutionKind<D>,
|
kind: ResolutionKind<D>,
|
||||||
tracing: TracingStrategy
|
tracing: TracingStrategy
|
||||||
): OverloadResolutionResultsImpl<D> {
|
): OverloadResolutionResultsImpl<D> {
|
||||||
val explicitReceiver = context.call.explicitReceiver
|
val explicitReceiver = context.call.explicitReceiver
|
||||||
val detailedReceiver = if (explicitReceiver is QualifierReceiver?) {
|
val detailedReceiver = if (explicitReceiver is QualifierReceiver?) {
|
||||||
explicitReceiver
|
explicitReceiver
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
context.transformToReceiverWithSmartCastInfo(explicitReceiver as ReceiverValue)
|
context.transformToReceiverWithSmartCastInfo(explicitReceiver as ReceiverValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -171,15 +181,22 @@ class NewResolutionOldInference(
|
|||||||
return allCandidatesResult(towerResolver.collectAllCandidates(scopeTower, processor, nameToResolve))
|
return allCandidatesResult(towerResolver.collectAllCandidates(scopeTower, processor, nameToResolve))
|
||||||
}
|
}
|
||||||
|
|
||||||
var candidates = towerResolver.runResolve(scopeTower, processor, useOrder = kind != ResolutionKind.CallableReference, name = nameToResolve)
|
var candidates =
|
||||||
|
towerResolver.runResolve(scopeTower, processor, useOrder = kind != ResolutionKind.CallableReference, name = nameToResolve)
|
||||||
|
|
||||||
// Temporary hack to resolve 'rem' as 'mod' if the first is do not present
|
// Temporary hack to resolve 'rem' as 'mod' if the first is do not present
|
||||||
val emptyOrInapplicableCandidates = candidates.isEmpty() ||
|
val emptyOrInapplicableCandidates = candidates.isEmpty() ||
|
||||||
candidates.all { it.resultingApplicability.isInapplicable }
|
candidates.all { it.resultingApplicability.isInapplicable }
|
||||||
if (isBinaryRemOperator && shouldUseOperatorRem && emptyOrInapplicableCandidates) {
|
if (isBinaryRemOperator && shouldUseOperatorRem && emptyOrInapplicableCandidates) {
|
||||||
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name]
|
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name]
|
||||||
val processorForDeprecatedName = kind.createTowerProcessor(this, deprecatedName!!, tracing, scopeTower, detailedReceiver, context)
|
val processorForDeprecatedName =
|
||||||
candidates = towerResolver.runResolve(scopeTower, processorForDeprecatedName, useOrder = kind != ResolutionKind.CallableReference, name = deprecatedName)
|
kind.createTowerProcessor(this, deprecatedName!!, tracing, scopeTower, detailedReceiver, context)
|
||||||
|
candidates = towerResolver.runResolve(
|
||||||
|
scopeTower,
|
||||||
|
processorForDeprecatedName,
|
||||||
|
useOrder = kind != ResolutionKind.CallableReference,
|
||||||
|
name = deprecatedName
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (candidates.isEmpty()) {
|
if (candidates.isEmpty()) {
|
||||||
@@ -194,9 +211,9 @@ class NewResolutionOldInference(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun <D : CallableDescriptor> runResolutionForGivenCandidates(
|
fun <D : CallableDescriptor> runResolutionForGivenCandidates(
|
||||||
basicCallContext: BasicCallResolutionContext,
|
basicCallContext: BasicCallResolutionContext,
|
||||||
tracing: TracingStrategy,
|
tracing: TracingStrategy,
|
||||||
candidates: Collection<ResolutionCandidate<D>>
|
candidates: Collection<ResolutionCandidate<D>>
|
||||||
): OverloadResolutionResultsImpl<D> {
|
): OverloadResolutionResultsImpl<D> {
|
||||||
val resolvedCandidates = candidates.map { candidate ->
|
val resolvedCandidates = candidates.map { candidate ->
|
||||||
val candidateTrace = TemporaryBindingTrace.create(basicCallContext.trace, "Context for resolve candidate")
|
val candidateTrace = TemporaryBindingTrace.create(basicCallContext.trace, "Context for resolve candidate")
|
||||||
@@ -207,8 +224,8 @@ class NewResolutionOldInference(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val callCandidateResolutionContext = CallCandidateResolutionContext.create(
|
val callCandidateResolutionContext = CallCandidateResolutionContext.create(
|
||||||
resolvedCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
|
resolvedCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
|
||||||
CandidateResolveMode.EXIT_ON_FIRST_ERROR
|
CandidateResolveMode.EXIT_ON_FIRST_ERROR
|
||||||
)
|
)
|
||||||
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
|
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
|
||||||
|
|
||||||
@@ -219,27 +236,31 @@ class NewResolutionOldInference(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (basicCallContext.collectAllCandidates) {
|
if (basicCallContext.collectAllCandidates) {
|
||||||
val allCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates),
|
val allCandidates = towerResolver.runWithEmptyTowerData(
|
||||||
TowerResolver.AllCandidatesCollector(), useOrder = false)
|
KnownResultProcessor(resolvedCandidates),
|
||||||
|
TowerResolver.AllCandidatesCollector(), useOrder = false
|
||||||
|
)
|
||||||
return allCandidatesResult(allCandidates)
|
return allCandidatesResult(allCandidates)
|
||||||
}
|
}
|
||||||
|
|
||||||
val processedCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates),
|
val processedCandidates = towerResolver.runWithEmptyTowerData(
|
||||||
TowerResolver.SuccessfulResultCollector(), useOrder = true)
|
KnownResultProcessor(resolvedCandidates),
|
||||||
|
TowerResolver.SuccessfulResultCollector(), useOrder = true
|
||||||
|
)
|
||||||
|
|
||||||
return convertToOverloadResults(processedCandidates, tracing, basicCallContext, languageVersionSettings)
|
return convertToOverloadResults(processedCandidates, tracing, basicCallContext, languageVersionSettings)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <D: CallableDescriptor> allCandidatesResult(allCandidates: Collection<MyCandidate>)
|
private fun <D : CallableDescriptor> allCandidatesResult(allCandidates: Collection<MyCandidate>) =
|
||||||
= OverloadResolutionResultsImpl.nameNotFound<D>().apply {
|
OverloadResolutionResultsImpl.nameNotFound<D>().apply {
|
||||||
this.allCandidates = allCandidates.map { it.resolvedCall as MutableResolvedCall<D> }
|
this.allCandidates = allCandidates.map { it.resolvedCall as MutableResolvedCall<D> }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> convertToOverloadResults(
|
private fun <D : CallableDescriptor> convertToOverloadResults(
|
||||||
candidates: Collection<MyCandidate>,
|
candidates: Collection<MyCandidate>,
|
||||||
tracing: TracingStrategy,
|
tracing: TracingStrategy,
|
||||||
basicCallContext: BasicCallResolutionContext,
|
basicCallContext: BasicCallResolutionContext,
|
||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
): OverloadResolutionResultsImpl<D> {
|
): OverloadResolutionResultsImpl<D> {
|
||||||
val resolvedCalls = candidates.map {
|
val resolvedCalls = candidates.map {
|
||||||
val (diagnostics, resolvedCall) = it
|
val (diagnostics, resolvedCall) = it
|
||||||
@@ -260,8 +281,17 @@ class NewResolutionOldInference(
|
|||||||
if (resolvedCall.status.possibleTransformToSuccess()) {
|
if (resolvedCall.status.possibleTransformToSuccess()) {
|
||||||
for (error in diagnostics) {
|
for (error in diagnostics) {
|
||||||
when (error) {
|
when (error) {
|
||||||
is UnsupportedInnerClassCall -> resolvedCall.trace.report(Errors.UNSUPPORTED.on(resolvedCall.call.callElement, error.message))
|
is UnsupportedInnerClassCall -> resolvedCall.trace.report(
|
||||||
is NestedClassViaInstanceReference -> tracing.nestedClassAccessViaInstanceReference(resolvedCall.trace, error.classDescriptor, resolvedCall.explicitReceiverKind)
|
Errors.UNSUPPORTED.on(
|
||||||
|
resolvedCall.call.callElement,
|
||||||
|
error.message
|
||||||
|
)
|
||||||
|
)
|
||||||
|
is NestedClassViaInstanceReference -> tracing.nestedClassAccessViaInstanceReference(
|
||||||
|
resolvedCall.trace,
|
||||||
|
error.classDescriptor,
|
||||||
|
resolvedCall.explicitReceiverKind
|
||||||
|
)
|
||||||
is ErrorDescriptorDiagnostic -> {
|
is ErrorDescriptorDiagnostic -> {
|
||||||
// todo
|
// todo
|
||||||
// return@map null
|
// return@map null
|
||||||
@@ -278,11 +308,11 @@ class NewResolutionOldInference(
|
|||||||
|
|
||||||
// true if we found something
|
// true if we found something
|
||||||
private fun reportAdditionalDiagnosticIfNoCandidates(
|
private fun reportAdditionalDiagnosticIfNoCandidates(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
name: Name,
|
name: Name,
|
||||||
kind: ResolutionKind<*>,
|
kind: ResolutionKind<*>,
|
||||||
scopeTower: ImplicitScopeTower,
|
scopeTower: ImplicitScopeTower,
|
||||||
detailedReceiver: DetailedReceiver?
|
detailedReceiver: DetailedReceiver?
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val reference = context.call.calleeExpression as? KtReferenceExpression ?: return false
|
val reference = context.call.calleeExpression as? KtReferenceExpression ?: return false
|
||||||
|
|
||||||
@@ -301,17 +331,17 @@ class NewResolutionOldInference(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class ImplicitScopeTowerImpl(
|
private class ImplicitScopeTowerImpl(
|
||||||
val resolutionContext: ResolutionContext<*>,
|
val resolutionContext: ResolutionContext<*>,
|
||||||
override val dynamicScope: MemberScope,
|
override val dynamicScope: MemberScope,
|
||||||
override val syntheticScopes: SyntheticScopes,
|
override val syntheticScopes: SyntheticScopes,
|
||||||
override val location: LookupLocation
|
override val location: LookupLocation
|
||||||
): ImplicitScopeTower {
|
) : ImplicitScopeTower {
|
||||||
private val cache = HashMap<ReceiverValue, ReceiverValueWithSmartCastInfo>()
|
private val cache = HashMap<ReceiverValue, ReceiverValueWithSmartCastInfo>()
|
||||||
|
|
||||||
override fun getImplicitReceiver(scope: LexicalScope): ReceiverValueWithSmartCastInfo? =
|
override fun getImplicitReceiver(scope: LexicalScope): ReceiverValueWithSmartCastInfo? =
|
||||||
scope.implicitReceiver?.value?.let {
|
scope.implicitReceiver?.value?.let {
|
||||||
cache.getOrPut(it) { resolutionContext.transformToReceiverWithSmartCastInfo(it) }
|
cache.getOrPut(it) { resolutionContext.transformToReceiverWithSmartCastInfo(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
override val lexicalScope: LexicalScope get() = resolutionContext.scope
|
override val lexicalScope: LexicalScope get() = resolutionContext.scope
|
||||||
|
|
||||||
@@ -322,12 +352,12 @@ class NewResolutionOldInference(
|
|||||||
}
|
}
|
||||||
|
|
||||||
internal class MyCandidate(
|
internal class MyCandidate(
|
||||||
// Diagnostics that are already computed
|
// Diagnostics that are already computed
|
||||||
// if resultingApplicability is successful they must be the same as `diagnostics`,
|
// if resultingApplicability is successful they must be the same as `diagnostics`,
|
||||||
// otherwise they might be a bit different but result remains unsuccessful
|
// otherwise they might be a bit different but result remains unsuccessful
|
||||||
val eagerDiagnostics: List<KotlinCallDiagnostic>,
|
val eagerDiagnostics: List<KotlinCallDiagnostic>,
|
||||||
val resolvedCall: MutableResolvedCall<*>,
|
val resolvedCall: MutableResolvedCall<*>,
|
||||||
finalDiagnosticsComputation: (() -> List<KotlinCallDiagnostic>)? = null
|
finalDiagnosticsComputation: (() -> List<KotlinCallDiagnostic>)? = null
|
||||||
) : Candidate {
|
) : Candidate {
|
||||||
val diagnostics: List<KotlinCallDiagnostic> by lazy(LazyThreadSafetyMode.NONE) {
|
val diagnostics: List<KotlinCallDiagnostic> by lazy(LazyThreadSafetyMode.NONE) {
|
||||||
finalDiagnosticsComputation?.invoke() ?: eagerDiagnostics
|
finalDiagnosticsComputation?.invoke() ?: eagerDiagnostics
|
||||||
@@ -344,22 +374,22 @@ class NewResolutionOldInference(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inner class CandidateFactoryImpl(
|
private inner class CandidateFactoryImpl(
|
||||||
val name: Name,
|
val name: Name,
|
||||||
val basicCallContext: BasicCallResolutionContext,
|
val basicCallContext: BasicCallResolutionContext,
|
||||||
val tracing: TracingStrategy
|
val tracing: TracingStrategy
|
||||||
) : CandidateFactory<MyCandidate> {
|
) : CandidateFactory<MyCandidate> {
|
||||||
override fun createCandidate(
|
override fun createCandidate(
|
||||||
towerCandidate: CandidateWithBoundDispatchReceiver,
|
towerCandidate: CandidateWithBoundDispatchReceiver,
|
||||||
explicitReceiverKind: ExplicitReceiverKind,
|
explicitReceiverKind: ExplicitReceiverKind,
|
||||||
extensionReceiver: ReceiverValueWithSmartCastInfo?
|
extensionReceiver: ReceiverValueWithSmartCastInfo?
|
||||||
): MyCandidate {
|
): MyCandidate {
|
||||||
|
|
||||||
val candidateTrace = TemporaryBindingTrace.create(basicCallContext.trace, "Context for resolve candidate")
|
val candidateTrace = TemporaryBindingTrace.create(basicCallContext.trace, "Context for resolve candidate")
|
||||||
val candidateCall = ResolvedCallImpl(
|
val candidateCall = ResolvedCallImpl(
|
||||||
basicCallContext.call, towerCandidate.descriptor,
|
basicCallContext.call, towerCandidate.descriptor,
|
||||||
towerCandidate.dispatchReceiver?.receiverValue, extensionReceiver?.receiverValue,
|
towerCandidate.dispatchReceiver?.receiverValue, extensionReceiver?.receiverValue,
|
||||||
explicitReceiverKind, null, candidateTrace, tracing,
|
explicitReceiverKind, null, candidateTrace, tracing,
|
||||||
basicCallContext.dataFlowInfoForArguments // todo may be we should create new mutable info for arguments
|
basicCallContext.dataFlowInfoForArguments // todo may be we should create new mutable info for arguments
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -385,8 +415,8 @@ class NewResolutionOldInference(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val callCandidateResolutionContext = CallCandidateResolutionContext.create(
|
val callCandidateResolutionContext = CallCandidateResolutionContext.create(
|
||||||
candidateCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
|
candidateCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
|
||||||
CandidateResolveMode.EXIT_ON_FIRST_ERROR
|
CandidateResolveMode.EXIT_ON_FIRST_ERROR
|
||||||
)
|
)
|
||||||
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
|
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
|
||||||
|
|
||||||
@@ -398,14 +428,14 @@ class NewResolutionOldInference(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createDiagnosticsForCandidate(
|
private fun createDiagnosticsForCandidate(
|
||||||
towerCandidate: CandidateWithBoundDispatchReceiver,
|
towerCandidate: CandidateWithBoundDispatchReceiver,
|
||||||
candidateCall: ResolvedCallImpl<CallableDescriptor>
|
candidateCall: ResolvedCallImpl<CallableDescriptor>
|
||||||
): List<ResolutionDiagnostic> =
|
): List<ResolutionDiagnostic> =
|
||||||
mutableListOf<ResolutionDiagnostic>().apply {
|
mutableListOf<ResolutionDiagnostic>().apply {
|
||||||
addAll(towerCandidate.diagnostics)
|
addAll(towerCandidate.diagnostics)
|
||||||
addAll(checkInfixAndOperator(basicCallContext.call, towerCandidate.descriptor))
|
addAll(checkInfixAndOperator(basicCallContext.call, towerCandidate.descriptor))
|
||||||
addIfNotNull(createPreviousResolveError(candidateCall.status))
|
addIfNotNull(createPreviousResolveError(candidateCall.status))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkInfixAndOperator(call: Call, descriptor: CallableDescriptor): List<ResolutionDiagnostic> {
|
private fun checkInfixAndOperator(call: Call, descriptor: CallableDescriptor): List<ResolutionDiagnostic> {
|
||||||
if (descriptor !is FunctionDescriptor || ErrorUtils.isError(descriptor)) return emptyList()
|
if (descriptor !is FunctionDescriptor || ErrorUtils.isError(descriptor)) return emptyList()
|
||||||
@@ -421,16 +451,16 @@ class NewResolutionOldInference(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inner class CandidateFactoryProviderForInvokeImpl(
|
private inner class CandidateFactoryProviderForInvokeImpl(
|
||||||
val functionContext: CandidateFactoryImpl
|
val functionContext: CandidateFactoryImpl
|
||||||
) : CandidateFactoryProviderForInvoke<MyCandidate> {
|
) : CandidateFactoryProviderForInvoke<MyCandidate> {
|
||||||
|
|
||||||
override fun transformCandidate(
|
override fun transformCandidate(
|
||||||
variable: MyCandidate,
|
variable: MyCandidate,
|
||||||
invoke: MyCandidate
|
invoke: MyCandidate
|
||||||
): MyCandidate {
|
): MyCandidate {
|
||||||
val resolvedCallImpl = VariableAsFunctionResolvedCallImpl(
|
val resolvedCallImpl = VariableAsFunctionResolvedCallImpl(
|
||||||
invoke.resolvedCall as MutableResolvedCall<FunctionDescriptor>,
|
invoke.resolvedCall as MutableResolvedCall<FunctionDescriptor>,
|
||||||
variable.resolvedCall as MutableResolvedCall<VariableDescriptor>
|
variable.resolvedCall as MutableResolvedCall<VariableDescriptor>
|
||||||
)
|
)
|
||||||
assert(variable.resultingApplicability.isSuccess) {
|
assert(variable.resultingApplicability.isSuccess) {
|
||||||
"Variable call must be success: $variable"
|
"Variable call must be success: $variable"
|
||||||
@@ -445,16 +475,20 @@ class NewResolutionOldInference(
|
|||||||
val newCall = CallTransformer.stripCallArguments(functionContext.basicCallContext.call).let {
|
val newCall = CallTransformer.stripCallArguments(functionContext.basicCallContext.call).let {
|
||||||
if (stripExplicitReceiver) CallTransformer.stripReceiver(it) else it
|
if (stripExplicitReceiver) CallTransformer.stripReceiver(it) else it
|
||||||
}
|
}
|
||||||
return CandidateFactoryImpl(functionContext.name, functionContext.basicCallContext.replaceCall(newCall), functionContext.tracing)
|
return CandidateFactoryImpl(
|
||||||
|
functionContext.name,
|
||||||
|
functionContext.basicCallContext.replaceCall(newCall),
|
||||||
|
functionContext.tracing
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun factoryForInvoke(
|
override fun factoryForInvoke(
|
||||||
variable: MyCandidate,
|
variable: MyCandidate,
|
||||||
useExplicitReceiver: Boolean
|
useExplicitReceiver: Boolean
|
||||||
): Pair<ReceiverValueWithSmartCastInfo, CandidateFactory<MyCandidate>>? {
|
): Pair<ReceiverValueWithSmartCastInfo, CandidateFactory<MyCandidate>>? {
|
||||||
assert(variable.resolvedCall.status.possibleTransformToSuccess()) {
|
assert(variable.resolvedCall.status.possibleTransformToSuccess()) {
|
||||||
"Incorrect status: ${variable.resolvedCall.status} for variable call: ${variable.resolvedCall} " +
|
"Incorrect status: ${variable.resolvedCall.status} for variable call: ${variable.resolvedCall} " +
|
||||||
"and descriptor: ${variable.resolvedCall.candidateDescriptor}"
|
"and descriptor: ${variable.resolvedCall.candidateDescriptor}"
|
||||||
}
|
}
|
||||||
val calleeExpression = variable.resolvedCall.call.calleeExpression
|
val calleeExpression = variable.resolvedCall.call.calleeExpression
|
||||||
val variableDescriptor = variable.resolvedCall.resultingDescriptor as VariableDescriptor
|
val variableDescriptor = variable.resolvedCall.resultingDescriptor as VariableDescriptor
|
||||||
@@ -467,19 +501,22 @@ class NewResolutionOldInference(
|
|||||||
return null // todo: create special check that there is no invoke on variable
|
return null // todo: create special check that there is no invoke on variable
|
||||||
}
|
}
|
||||||
val basicCallContext = functionContext.basicCallContext
|
val basicCallContext = functionContext.basicCallContext
|
||||||
val variableReceiver = ExpressionReceiver.create(calleeExpression!!,
|
val variableReceiver = ExpressionReceiver.create(
|
||||||
variableType,
|
calleeExpression!!,
|
||||||
basicCallContext.trace.bindingContext)
|
variableType,
|
||||||
|
basicCallContext.trace.bindingContext
|
||||||
|
)
|
||||||
// used for smartCasts, see: DataFlowValueFactory.getIdForSimpleNameExpression
|
// used for smartCasts, see: DataFlowValueFactory.getIdForSimpleNameExpression
|
||||||
functionContext.tracing.bindReference(variable.resolvedCall.trace, variable.resolvedCall)
|
functionContext.tracing.bindReference(variable.resolvedCall.trace, variable.resolvedCall)
|
||||||
// todo hacks
|
// todo hacks
|
||||||
val functionCall = CallTransformer.CallForImplicitInvoke(
|
val functionCall = CallTransformer.CallForImplicitInvoke(
|
||||||
basicCallContext.call.explicitReceiver?.takeIf { useExplicitReceiver },
|
basicCallContext.call.explicitReceiver?.takeIf { useExplicitReceiver },
|
||||||
variableReceiver, basicCallContext.call, true)
|
variableReceiver, basicCallContext.call, true
|
||||||
|
)
|
||||||
val tracingForInvoke = TracingStrategyForInvoke(calleeExpression, functionCall, variableReceiver.type)
|
val tracingForInvoke = TracingStrategyForInvoke(calleeExpression, functionCall, variableReceiver.type)
|
||||||
val basicCallResolutionContext = basicCallContext.replaceBindingTrace(variable.resolvedCall.trace)
|
val basicCallResolutionContext = basicCallContext.replaceBindingTrace(variable.resolvedCall.trace)
|
||||||
.replaceCall(functionCall)
|
.replaceCall(functionCall)
|
||||||
.replaceContextDependency(ContextDependency.DEPENDENT) // todo
|
.replaceContextDependency(ContextDependency.DEPENDENT) // todo
|
||||||
|
|
||||||
val newContext = CandidateFactoryImpl(OperatorNameConventions.INVOKE, basicCallResolutionContext, tracingForInvoke)
|
val newContext = CandidateFactoryImpl(OperatorNameConventions.INVOKE, basicCallResolutionContext, tracingForInvoke)
|
||||||
|
|
||||||
@@ -491,25 +528,25 @@ class NewResolutionOldInference(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun ResolutionContext<*>.transformToReceiverWithSmartCastInfo(receiver: ReceiverValue) =
|
fun ResolutionContext<*>.transformToReceiverWithSmartCastInfo(receiver: ReceiverValue) =
|
||||||
transformToReceiverWithSmartCastInfo(scope.ownerDescriptor, trace.bindingContext, dataFlowInfo, receiver, languageVersionSettings)
|
transformToReceiverWithSmartCastInfo(scope.ownerDescriptor, trace.bindingContext, dataFlowInfo, receiver, languageVersionSettings)
|
||||||
|
|
||||||
fun transformToReceiverWithSmartCastInfo(
|
fun transformToReceiverWithSmartCastInfo(
|
||||||
containingDescriptor: DeclarationDescriptor,
|
containingDescriptor: DeclarationDescriptor,
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
dataFlowInfo: DataFlowInfo,
|
dataFlowInfo: DataFlowInfo,
|
||||||
receiver: ReceiverValue,
|
receiver: ReceiverValue,
|
||||||
languageVersionSettings: LanguageVersionSettings
|
languageVersionSettings: LanguageVersionSettings
|
||||||
): ReceiverValueWithSmartCastInfo {
|
): ReceiverValueWithSmartCastInfo {
|
||||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, bindingContext, containingDescriptor)
|
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, bindingContext, containingDescriptor)
|
||||||
return ReceiverValueWithSmartCastInfo(
|
return ReceiverValueWithSmartCastInfo(
|
||||||
receiver,
|
receiver,
|
||||||
dataFlowInfo.getCollectedTypes(dataFlowValue, languageVersionSettings),
|
dataFlowInfo.getCollectedTypes(dataFlowValue, languageVersionSettings),
|
||||||
dataFlowValue.isStable
|
dataFlowValue.isStable
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Deprecated("Temporary error")
|
@Deprecated("Temporary error")
|
||||||
internal class PreviousResolutionError(candidateLevel: ResolutionCandidateApplicability): ResolutionDiagnostic(candidateLevel)
|
internal class PreviousResolutionError(candidateLevel: ResolutionCandidateApplicability) : ResolutionDiagnostic(candidateLevel)
|
||||||
|
|
||||||
@Deprecated("Temporary error")
|
@Deprecated("Temporary error")
|
||||||
internal fun createPreviousResolveError(status: ResolutionStatus): PreviousResolutionError? {
|
internal fun createPreviousResolveError(status: ResolutionStatus): PreviousResolutionError? {
|
||||||
|
|||||||
+197
-158
@@ -60,28 +60,28 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
class PSICallResolver(
|
class PSICallResolver(
|
||||||
private val typeResolver: TypeResolver,
|
private val typeResolver: TypeResolver,
|
||||||
private val expressionTypingServices: ExpressionTypingServices,
|
private val expressionTypingServices: ExpressionTypingServices,
|
||||||
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||||
private val languageVersionSettings: LanguageVersionSettings,
|
private val languageVersionSettings: LanguageVersionSettings,
|
||||||
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
|
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
|
||||||
private val syntheticScopes: SyntheticScopes,
|
private val syntheticScopes: SyntheticScopes,
|
||||||
private val callComponents: KotlinCallComponents,
|
private val callComponents: KotlinCallComponents,
|
||||||
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||||
private val kotlinCallResolver: KotlinCallResolver,
|
private val kotlinCallResolver: KotlinCallResolver,
|
||||||
private val typeApproximator: TypeApproximator,
|
private val typeApproximator: TypeApproximator,
|
||||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||||
private val effectSystem: EffectSystem,
|
private val effectSystem: EffectSystem,
|
||||||
private val constantExpressionEvaluator: ConstantExpressionEvaluator
|
private val constantExpressionEvaluator: ConstantExpressionEvaluator
|
||||||
) {
|
) {
|
||||||
private val GIVEN_CANDIDATES_NAME = Name.special("<given candidates>")
|
private val GIVEN_CANDIDATES_NAME = Name.special("<given candidates>")
|
||||||
|
|
||||||
fun <D : CallableDescriptor> runResolutionAndInference(
|
fun <D : CallableDescriptor> runResolutionAndInference(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
name: Name,
|
name: Name,
|
||||||
resolutionKind: NewResolutionOldInference.ResolutionKind<D>,
|
resolutionKind: NewResolutionOldInference.ResolutionKind<D>,
|
||||||
tracingStrategy: TracingStrategy
|
tracingStrategy: TracingStrategy
|
||||||
) : OverloadResolutionResults<D> {
|
): OverloadResolutionResults<D> {
|
||||||
val isBinaryRemOperator = isBinaryRemOperator(context.call)
|
val isBinaryRemOperator = isBinaryRemOperator(context.call)
|
||||||
val refinedName = refineNameForRemOperator(isBinaryRemOperator, name)
|
val refinedName = refineNameForRemOperator(isBinaryRemOperator, name)
|
||||||
|
|
||||||
@@ -93,7 +93,8 @@ class PSICallResolver(
|
|||||||
|
|
||||||
val expectedType = calculateExpectedType(context)
|
val expectedType = calculateExpectedType(context)
|
||||||
var result = kotlinCallResolver.resolveCall(
|
var result = kotlinCallResolver.resolveCall(
|
||||||
scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke, context.collectAllCandidates)
|
scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke, context.collectAllCandidates
|
||||||
|
)
|
||||||
|
|
||||||
val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)
|
val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)
|
||||||
if (isBinaryRemOperator && shouldUseOperatorRem && (result.isEmpty() || result.areAllInapplicable())) {
|
if (isBinaryRemOperator && shouldUseOperatorRem && (result.isEmpty() || result.areAllInapplicable())) {
|
||||||
@@ -109,42 +110,48 @@ class PSICallResolver(
|
|||||||
|
|
||||||
// actually, `D` is at least FunctionDescriptor, but right now because of CallResolver it isn't possible change upper bound for `D`
|
// actually, `D` is at least FunctionDescriptor, but right now because of CallResolver it isn't possible change upper bound for `D`
|
||||||
fun <D : CallableDescriptor> runResolutionAndInferenceForGivenCandidates(
|
fun <D : CallableDescriptor> runResolutionAndInferenceForGivenCandidates(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
resolutionCandidates: Collection<ResolutionCandidate<D>>,
|
resolutionCandidates: Collection<ResolutionCandidate<D>>,
|
||||||
tracingStrategy: TracingStrategy
|
tracingStrategy: TracingStrategy
|
||||||
): OverloadResolutionResults<D> {
|
): OverloadResolutionResults<D> {
|
||||||
val dispatchReceiver = resolutionCandidates.firstNotNullResult { it.dispatchReceiver }
|
val dispatchReceiver = resolutionCandidates.firstNotNullResult { it.dispatchReceiver }
|
||||||
|
|
||||||
val kotlinCall = toKotlinCall(context, KotlinCallKind.FUNCTION, context.call, GIVEN_CANDIDATES_NAME, tracingStrategy, dispatchReceiver)
|
val kotlinCall =
|
||||||
|
toKotlinCall(context, KotlinCallKind.FUNCTION, context.call, GIVEN_CANDIDATES_NAME, tracingStrategy, dispatchReceiver)
|
||||||
val scopeTower = ASTScopeTower(context)
|
val scopeTower = ASTScopeTower(context)
|
||||||
val resolutionCallbacks = createResolutionCallbacks(context)
|
val resolutionCallbacks = createResolutionCallbacks(context)
|
||||||
|
|
||||||
val givenCandidates = resolutionCandidates.map {
|
val givenCandidates = resolutionCandidates.map {
|
||||||
GivenCandidate(it.descriptor as FunctionDescriptor,
|
GivenCandidate(
|
||||||
it.dispatchReceiver?.let { context.transformToReceiverWithSmartCastInfo(it) },
|
it.descriptor as FunctionDescriptor,
|
||||||
it.knownTypeParametersResultingSubstitutor)
|
it.dispatchReceiver?.let { context.transformToReceiverWithSmartCastInfo(it) },
|
||||||
|
it.knownTypeParametersResultingSubstitutor
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val result = kotlinCallResolver.resolveGivenCandidates(
|
val result = kotlinCallResolver.resolveGivenCandidates(
|
||||||
scopeTower, resolutionCallbacks, kotlinCall, calculateExpectedType(context), givenCandidates, context.collectAllCandidates)
|
scopeTower, resolutionCallbacks, kotlinCall, calculateExpectedType(context), givenCandidates, context.collectAllCandidates
|
||||||
|
)
|
||||||
return convertToOverloadResolutionResults(context, result, tracingStrategy)
|
return convertToOverloadResolutionResults(context, result, tracingStrategy)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> resolveToDeprecatedMod(
|
private fun <D : CallableDescriptor> resolveToDeprecatedMod(
|
||||||
remOperatorName: Name,
|
remOperatorName: Name,
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
resolutionKind: NewResolutionOldInference.ResolutionKind<D>,
|
resolutionKind: NewResolutionOldInference.ResolutionKind<D>,
|
||||||
tracingStrategy: TracingStrategy,
|
tracingStrategy: TracingStrategy,
|
||||||
scopeTower: ImplicitScopeTower,
|
scopeTower: ImplicitScopeTower,
|
||||||
resolutionCallbacks: KotlinResolutionCallbacksImpl,
|
resolutionCallbacks: KotlinResolutionCallbacksImpl,
|
||||||
expectedType: UnwrappedType?
|
expectedType: UnwrappedType?
|
||||||
): CallResolutionResult {
|
): CallResolutionResult {
|
||||||
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!!
|
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!!
|
||||||
val callWithDeprecatedName = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, deprecatedName, tracingStrategy)
|
val callWithDeprecatedName = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, deprecatedName, tracingStrategy)
|
||||||
val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, scopeTower, callWithDeprecatedName)
|
val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, scopeTower, callWithDeprecatedName)
|
||||||
return kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, callWithDeprecatedName, expectedType,
|
return kotlinCallResolver.resolveCall(
|
||||||
refinedProviderForInvokeFactory, context.collectAllCandidates)
|
scopeTower, resolutionCallbacks, callWithDeprecatedName, expectedType,
|
||||||
|
refinedProviderForInvokeFactory, context.collectAllCandidates
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun refineNameForRemOperator(isBinaryRemOperator: Boolean, name: Name): Name {
|
private fun refineNameForRemOperator(isBinaryRemOperator: Boolean, name: Name): Name {
|
||||||
@@ -153,9 +160,11 @@ class PSICallResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createResolutionCallbacks(context: BasicCallResolutionContext) =
|
private fun createResolutionCallbacks(context: BasicCallResolutionContext) =
|
||||||
KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator,
|
KotlinResolutionCallbacksImpl(
|
||||||
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer,
|
context, expressionTypingServices, typeApproximator,
|
||||||
constantExpressionEvaluator)
|
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer,
|
||||||
|
constantExpressionEvaluator
|
||||||
|
)
|
||||||
|
|
||||||
private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? {
|
private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? {
|
||||||
val expectedType = context.expectedType.unwrap()
|
val expectedType = context.expectedType.unwrap()
|
||||||
@@ -165,16 +174,15 @@ class PSICallResolver(
|
|||||||
"Should have no expected type, got: $expectedType"
|
"Should have no expected type, got: $expectedType"
|
||||||
}
|
}
|
||||||
null
|
null
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (expectedType.isError) TypeUtils.NO_EXPECTED_TYPE else expectedType
|
if (expectedType.isError) TypeUtils.NO_EXPECTED_TYPE else expectedType
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <D : CallableDescriptor> convertToOverloadResolutionResults(
|
private fun <D : CallableDescriptor> convertToOverloadResolutionResults(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
result: CallResolutionResult,
|
result: CallResolutionResult,
|
||||||
tracingStrategy: TracingStrategy
|
tracingStrategy: TracingStrategy
|
||||||
): OverloadResolutionResults<D> {
|
): OverloadResolutionResults<D> {
|
||||||
if (result.type == CallResolutionResult.Type.ALL_CANDIDATES) {
|
if (result.type == CallResolutionResult.Type.ALL_CANDIDATES) {
|
||||||
val resolvedCalls = result.allCandidates?.map {
|
val resolvedCalls = result.allCandidates?.map {
|
||||||
@@ -197,28 +205,26 @@ class PSICallResolver(
|
|||||||
if (it.candidates.areAllFailed()) {
|
if (it.candidates.areAllFailed()) {
|
||||||
tracingStrategy.noneApplicable(trace, resolvedCalls)
|
tracingStrategy.noneApplicable(trace, resolvedCalls)
|
||||||
tracingStrategy.recordAmbiguity(trace, resolvedCalls)
|
tracingStrategy.recordAmbiguity(trace, resolvedCalls)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
tracingStrategy.recordAmbiguity(trace, resolvedCalls)
|
tracingStrategy.recordAmbiguity(trace, resolvedCalls)
|
||||||
if (resolvedCalls.first().status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) {
|
if (resolvedCalls.first().status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) {
|
||||||
tracingStrategy.cannotCompleteResolve(trace, resolvedCalls)
|
tracingStrategy.cannotCompleteResolve(trace, resolvedCalls)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
tracingStrategy.ambiguity(trace, resolvedCalls)
|
tracingStrategy.ambiguity(trace, resolvedCalls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ManyCandidates(resolvedCalls)
|
return ManyCandidates(resolvedCalls)
|
||||||
}
|
}
|
||||||
|
|
||||||
val isInapplicableReceiver = getResultApplicability(result.diagnostics) == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER
|
val isInapplicableReceiver =
|
||||||
|
getResultApplicability(result.diagnostics) == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER
|
||||||
|
|
||||||
val resolvedCall = if (isInapplicableReceiver) {
|
val resolvedCall = if (isInapplicableReceiver) {
|
||||||
val singleCandidate = result.resultCallAtom ?: error("Should be not null for result: $result")
|
val singleCandidate = result.resultCallAtom ?: error("Should be not null for result: $result")
|
||||||
kotlinToResolvedCallTransformer.onlyTransform<D>(singleCandidate, result.diagnostics).also {
|
kotlinToResolvedCallTransformer.onlyTransform<D>(singleCandidate, result.diagnostics).also {
|
||||||
tracingStrategy.unresolvedReferenceWrongReceiver(trace, listOf(it))
|
tracingStrategy.unresolvedReferenceWrongReceiver(trace, listOf(it))
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
kotlinToResolvedCallTransformer.transformAndReport<D>(result, context)
|
kotlinToResolvedCallTransformer.transformAndReport<D>(result, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -246,12 +252,12 @@ class PSICallResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun CallResolutionResult.isEmpty(): Boolean =
|
private fun CallResolutionResult.isEmpty(): Boolean =
|
||||||
diagnostics.firstIsInstanceOrNull<NoneCandidatesCallDiagnostic>() != null
|
diagnostics.firstIsInstanceOrNull<NoneCandidatesCallDiagnostic>() != null
|
||||||
|
|
||||||
private fun Collection<KotlinResolutionCandidate>.areAllFailed() =
|
private fun Collection<KotlinResolutionCandidate>.areAllFailed() =
|
||||||
all {
|
all {
|
||||||
!it.resultingApplicability.isSuccess
|
!it.resultingApplicability.isSuccess
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CallResolutionResult.areAllInapplicable(): Boolean {
|
private fun CallResolutionResult.areAllInapplicable(): Boolean {
|
||||||
val manyCandidates = diagnostics.firstIsInstanceOrNull<ManyCandidatesCallDiagnostic>()?.candidates
|
val manyCandidates = diagnostics.firstIsInstanceOrNull<ManyCandidatesCallDiagnostic>()?.candidates
|
||||||
@@ -261,16 +267,16 @@ class PSICallResolver(
|
|||||||
|
|
||||||
val applicability = getResultApplicability(diagnostics)
|
val applicability = getResultApplicability(diagnostics)
|
||||||
return applicability == ResolutionCandidateApplicability.INAPPLICABLE ||
|
return applicability == ResolutionCandidateApplicability.INAPPLICABLE ||
|
||||||
applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER ||
|
applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER ||
|
||||||
applicability == ResolutionCandidateApplicability.HIDDEN
|
applicability == ResolutionCandidateApplicability.HIDDEN
|
||||||
}
|
}
|
||||||
|
|
||||||
// true if we found something
|
// true if we found something
|
||||||
private fun reportAdditionalDiagnosticIfNoCandidates(
|
private fun reportAdditionalDiagnosticIfNoCandidates(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
scopeTower: ImplicitScopeTower,
|
scopeTower: ImplicitScopeTower,
|
||||||
kind: KotlinCallKind,
|
kind: KotlinCallKind,
|
||||||
kotlinCall: KotlinCall
|
kotlinCall: KotlinCall
|
||||||
): Boolean {
|
): Boolean {
|
||||||
val reference = context.call.calleeExpression as? KtReferenceExpression ?: return false
|
val reference = context.call.calleeExpression as? KtReferenceExpression ?: return false
|
||||||
|
|
||||||
@@ -285,7 +291,14 @@ class PSICallResolver(
|
|||||||
for (candidate in errorCandidates) {
|
for (candidate in errorCandidates) {
|
||||||
if (candidate is ErrorCandidate.Classifier) {
|
if (candidate is ErrorCandidate.Classifier) {
|
||||||
context.trace.record(BindingContext.REFERENCE_TARGET, reference, candidate.descriptor)
|
context.trace.record(BindingContext.REFERENCE_TARGET, reference, candidate.descriptor)
|
||||||
context.trace.report(Errors.RESOLUTION_TO_CLASSIFIER.on(reference, candidate.descriptor, candidate.kind, candidate.errorMessage))
|
context.trace.report(
|
||||||
|
Errors.RESOLUTION_TO_CLASSIFIER.on(
|
||||||
|
reference,
|
||||||
|
candidate.descriptor,
|
||||||
|
candidate.kind,
|
||||||
|
candidate.errorMessage
|
||||||
|
)
|
||||||
|
)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -294,10 +307,11 @@ class PSICallResolver(
|
|||||||
|
|
||||||
|
|
||||||
private inner class ASTScopeTower(
|
private inner class ASTScopeTower(
|
||||||
val context: BasicCallResolutionContext
|
val context: BasicCallResolutionContext
|
||||||
): ImplicitScopeTower {
|
) : ImplicitScopeTower {
|
||||||
// todo may be for invoke for case variable + invoke we should create separate dynamicScope(by newCall for invoke)
|
// todo may be for invoke for case variable + invoke we should create separate dynamicScope(by newCall for invoke)
|
||||||
override val dynamicScope: MemberScope = dynamicCallableDescriptors.createDynamicDescriptorScope(context.call, context.scope.ownerDescriptor)
|
override val dynamicScope: MemberScope =
|
||||||
|
dynamicCallableDescriptors.createDynamicDescriptorScope(context.call, context.scope.ownerDescriptor)
|
||||||
// same for location
|
// same for location
|
||||||
override val location: LookupLocation = context.call.createLookupLocation()
|
override val location: LookupLocation = context.call.createLookupLocation()
|
||||||
|
|
||||||
@@ -317,9 +331,9 @@ class PSICallResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private inner class FactoryProviderForInvoke(
|
private inner class FactoryProviderForInvoke(
|
||||||
val context: BasicCallResolutionContext,
|
val context: BasicCallResolutionContext,
|
||||||
val scopeTower: ImplicitScopeTower,
|
val scopeTower: ImplicitScopeTower,
|
||||||
val kotlinCall: PSIKotlinCallImpl
|
val kotlinCall: PSIKotlinCallImpl
|
||||||
) : CandidateFactoryProviderForInvoke<KotlinResolutionCandidate> {
|
) : CandidateFactoryProviderForInvoke<KotlinResolutionCandidate> {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
@@ -327,8 +341,8 @@ class PSICallResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun transformCandidate(
|
override fun transformCandidate(
|
||||||
variable: KotlinResolutionCandidate,
|
variable: KotlinResolutionCandidate,
|
||||||
invoke: KotlinResolutionCandidate
|
invoke: KotlinResolutionCandidate
|
||||||
) = invoke
|
) = invoke
|
||||||
|
|
||||||
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<KotlinResolutionCandidate> {
|
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<KotlinResolutionCandidate> {
|
||||||
@@ -343,15 +357,14 @@ class PSICallResolver(
|
|||||||
|
|
||||||
assert(variable.isSuccessful) {
|
assert(variable.isSuccessful) {
|
||||||
"Variable call should be successful: $variable " +
|
"Variable call should be successful: $variable " +
|
||||||
"Descriptor: ${variable.resolvedCall.candidateDescriptor}"
|
"Descriptor: ${variable.resolvedCall.candidateDescriptor}"
|
||||||
}
|
}
|
||||||
val variableCallArgument = createReceiverCallArgument(variable)
|
val variableCallArgument = createReceiverCallArgument(variable)
|
||||||
|
|
||||||
val explicitReceiver = kotlinCall.explicitReceiver
|
val explicitReceiver = kotlinCall.explicitReceiver
|
||||||
val callForInvoke = if (useExplicitReceiver && explicitReceiver != null) {
|
val callForInvoke = if (useExplicitReceiver && explicitReceiver != null) {
|
||||||
PSIKotlinCallForInvoke(kotlinCall, variable, explicitReceiver, variableCallArgument)
|
PSIKotlinCallForInvoke(kotlinCall, variable, explicitReceiver, variableCallArgument)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
PSIKotlinCallForInvoke(kotlinCall, variable, variableCallArgument, null)
|
PSIKotlinCallForInvoke(kotlinCall, variable, variableCallArgument, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -369,22 +382,32 @@ class PSICallResolver(
|
|||||||
variable.forceResolution()
|
variable.forceResolution()
|
||||||
val variableReceiver = createReceiverValueWithSmartCastInfo(variable)
|
val variableReceiver = createReceiverValueWithSmartCastInfo(variable)
|
||||||
if (variableReceiver.possibleTypes.isNotEmpty()) {
|
if (variableReceiver.possibleTypes.isNotEmpty()) {
|
||||||
return ReceiverExpressionKotlinCallArgument(createReceiverValueWithSmartCastInfo(variable), isVariableReceiverForInvoke = true)
|
return ReceiverExpressionKotlinCallArgument(
|
||||||
|
createReceiverValueWithSmartCastInfo(variable),
|
||||||
|
isVariableReceiverForInvoke = true
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val psiKotlinCall = variable.resolvedCall.atom.psiKotlinCall
|
val psiKotlinCall = variable.resolvedCall.atom.psiKotlinCall
|
||||||
|
|
||||||
val variableResult = CallResolutionResult(CallResolutionResult.Type.PARTIAL, variable.resolvedCall, listOf(), variable.getSystem().asReadOnlyStorage())
|
val variableResult = CallResolutionResult(
|
||||||
return SubKotlinCallArgumentImpl(CallMaker.makeExternalValueArgument((variableReceiver.receiverValue as ExpressionReceiver).expression),
|
CallResolutionResult.Type.PARTIAL,
|
||||||
psiKotlinCall.resultDataFlowInfo, psiKotlinCall.resultDataFlowInfo, variableReceiver,
|
variable.resolvedCall,
|
||||||
variableResult)
|
listOf(),
|
||||||
|
variable.getSystem().asReadOnlyStorage()
|
||||||
|
)
|
||||||
|
return SubKotlinCallArgumentImpl(
|
||||||
|
CallMaker.makeExternalValueArgument((variableReceiver.receiverValue as ExpressionReceiver).expression),
|
||||||
|
psiKotlinCall.resultDataFlowInfo, psiKotlinCall.resultDataFlowInfo, variableReceiver,
|
||||||
|
variableResult
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// todo: decrease hacks count
|
// todo: decrease hacks count
|
||||||
private fun createReceiverValueWithSmartCastInfo(variable: KotlinResolutionCandidate): ReceiverValueWithSmartCastInfo {
|
private fun createReceiverValueWithSmartCastInfo(variable: KotlinResolutionCandidate): ReceiverValueWithSmartCastInfo {
|
||||||
val callForVariable = variable.resolvedCall.atom as PSIKotlinCallForVariable
|
val callForVariable = variable.resolvedCall.atom as PSIKotlinCallForVariable
|
||||||
val calleeExpression = callForVariable.baseCall.psiCall.calleeExpression as? KtReferenceExpression ?:
|
val calleeExpression = callForVariable.baseCall.psiCall.calleeExpression as? KtReferenceExpression
|
||||||
error("Unexpected call : ${callForVariable.baseCall.psiCall}")
|
?: error("Unexpected call : ${callForVariable.baseCall.psiCall}")
|
||||||
|
|
||||||
val temporaryTrace = TemporaryBindingTrace.create(context.trace, "Context for resolve candidate")
|
val temporaryTrace = TemporaryBindingTrace.create(context.trace, "Context for resolve candidate")
|
||||||
|
|
||||||
@@ -392,31 +415,32 @@ class PSICallResolver(
|
|||||||
val variableReceiver = ExpressionReceiver.create(calleeExpression, type, temporaryTrace.bindingContext)
|
val variableReceiver = ExpressionReceiver.create(calleeExpression, type, temporaryTrace.bindingContext)
|
||||||
|
|
||||||
temporaryTrace.record(BindingContext.REFERENCE_TARGET, calleeExpression, variable.resolvedCall.candidateDescriptor)
|
temporaryTrace.record(BindingContext.REFERENCE_TARGET, calleeExpression, variable.resolvedCall.candidateDescriptor)
|
||||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(variableReceiver, temporaryTrace.bindingContext, context.scope.ownerDescriptor)
|
val dataFlowValue =
|
||||||
|
DataFlowValueFactory.createDataFlowValue(variableReceiver, temporaryTrace.bindingContext, context.scope.ownerDescriptor)
|
||||||
return ReceiverValueWithSmartCastInfo(
|
return ReceiverValueWithSmartCastInfo(
|
||||||
variableReceiver,
|
variableReceiver,
|
||||||
context.dataFlowInfo.getCollectedTypes(dataFlowValue, context.languageVersionSettings),
|
context.dataFlowInfo.getCollectedTypes(dataFlowValue, context.languageVersionSettings),
|
||||||
dataFlowValue.isStable
|
dataFlowValue.isStable
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private fun toKotlinCall(
|
private fun toKotlinCall(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
kotlinCallKind: KotlinCallKind,
|
kotlinCallKind: KotlinCallKind,
|
||||||
oldCall: Call,
|
oldCall: Call,
|
||||||
name: Name,
|
name: Name,
|
||||||
tracingStrategy: TracingStrategy,
|
tracingStrategy: TracingStrategy,
|
||||||
forcedExplicitReceiver: Receiver? = null
|
forcedExplicitReceiver: Receiver? = null
|
||||||
): PSIKotlinCallImpl {
|
): PSIKotlinCallImpl {
|
||||||
val resolvedExplicitReceiver = resolveExplicitReceiver(context, forcedExplicitReceiver?: oldCall.explicitReceiver, oldCall.isSafeCall())
|
val resolvedExplicitReceiver =
|
||||||
|
resolveExplicitReceiver(context, forcedExplicitReceiver ?: oldCall.explicitReceiver, oldCall.isSafeCall())
|
||||||
val resolvedTypeArguments = resolveTypeArguments(context, oldCall.typeArguments)
|
val resolvedTypeArguments = resolveTypeArguments(context, oldCall.typeArguments)
|
||||||
|
|
||||||
val argumentsInParenthesis = if (oldCall.callType != Call.CallType.ARRAY_SET_METHOD && oldCall.functionLiteralArguments.isEmpty()) {
|
val argumentsInParenthesis = if (oldCall.callType != Call.CallType.ARRAY_SET_METHOD && oldCall.functionLiteralArguments.isEmpty()) {
|
||||||
oldCall.valueArguments
|
oldCall.valueArguments
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
oldCall.valueArguments.dropLast(1)
|
oldCall.valueArguments.dropLast(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -428,8 +452,7 @@ class PSICallResolver(
|
|||||||
"Unexpected lambda parameters for call $oldCall"
|
"Unexpected lambda parameters for call $oldCall"
|
||||||
}
|
}
|
||||||
oldCall.valueArguments.last()
|
oldCall.valueArguments.last()
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (externalLambdaArguments.size > 2) {
|
if (externalLambdaArguments.size > 2) {
|
||||||
externalLambdaArguments.drop(1).forEach {
|
externalLambdaArguments.drop(1).forEach {
|
||||||
context.trace.report(Errors.MANY_LAMBDA_EXPRESSION_ARGUMENTS.on(it.getLambdaExpression()))
|
context.trace.report(Errors.MANY_LAMBDA_EXPRESSION_ARGUMENTS.on(it.getLambdaExpression()))
|
||||||
@@ -440,10 +463,10 @@ class PSICallResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val dataFlowInfoAfterArgumentsInParenthesis =
|
val dataFlowInfoAfterArgumentsInParenthesis =
|
||||||
if (externalArgument != null && resolvedArgumentsInParenthesis.isNotEmpty())
|
if (externalArgument != null && resolvedArgumentsInParenthesis.isNotEmpty())
|
||||||
resolvedArgumentsInParenthesis.last().psiCallArgument.dataFlowInfoAfterThisArgument
|
resolvedArgumentsInParenthesis.last().psiCallArgument.dataFlowInfoAfterThisArgument
|
||||||
else
|
else
|
||||||
context.dataFlowInfoForArguments.resultInfo
|
context.dataFlowInfoForArguments.resultInfo
|
||||||
|
|
||||||
val astExternalArgument = externalArgument?.let { resolveValueArgument(context, dataFlowInfoAfterArgumentsInParenthesis, it) }
|
val astExternalArgument = externalArgument?.let { resolveValueArgument(context, dataFlowInfoAfterArgumentsInParenthesis, it) }
|
||||||
val resultDataFlowInfo = astExternalArgument?.dataFlowInfoAfterThisArgument ?: dataFlowInfoAfterArgumentsInParenthesis
|
val resultDataFlowInfo = astExternalArgument?.dataFlowInfoAfterThisArgument ?: dataFlowInfoAfterArgumentsInParenthesis
|
||||||
@@ -451,39 +474,47 @@ class PSICallResolver(
|
|||||||
resolvedArgumentsInParenthesis.forEach { it.setResultDataFlowInfoIfRelevant(resultDataFlowInfo) }
|
resolvedArgumentsInParenthesis.forEach { it.setResultDataFlowInfoIfRelevant(resultDataFlowInfo) }
|
||||||
astExternalArgument?.setResultDataFlowInfoIfRelevant(resultDataFlowInfo)
|
astExternalArgument?.setResultDataFlowInfoIfRelevant(resultDataFlowInfo)
|
||||||
|
|
||||||
return PSIKotlinCallImpl(kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, name, resolvedTypeArguments, resolvedArgumentsInParenthesis,
|
return PSIKotlinCallImpl(
|
||||||
astExternalArgument, context.dataFlowInfo, resultDataFlowInfo, context.dataFlowInfoForArguments)
|
kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, name, resolvedTypeArguments, resolvedArgumentsInParenthesis,
|
||||||
|
astExternalArgument, context.dataFlowInfo, resultDataFlowInfo, context.dataFlowInfoForArguments
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveExplicitReceiver(context: BasicCallResolutionContext, oldReceiver: Receiver?, isSafeCall: Boolean): ReceiverKotlinCallArgument? =
|
private fun resolveExplicitReceiver(
|
||||||
when(oldReceiver) {
|
context: BasicCallResolutionContext,
|
||||||
null -> null
|
oldReceiver: Receiver?,
|
||||||
is QualifierReceiver -> QualifierReceiverKotlinCallArgument(oldReceiver) // todo report warning if isSafeCall
|
isSafeCall: Boolean
|
||||||
is ReceiverValue -> {
|
): ReceiverKotlinCallArgument? =
|
||||||
val detailedReceiver = context.transformToReceiverWithSmartCastInfo(oldReceiver)
|
when (oldReceiver) {
|
||||||
|
null -> null
|
||||||
|
is QualifierReceiver -> QualifierReceiverKotlinCallArgument(oldReceiver) // todo report warning if isSafeCall
|
||||||
|
is ReceiverValue -> {
|
||||||
|
val detailedReceiver = context.transformToReceiverWithSmartCastInfo(oldReceiver)
|
||||||
|
|
||||||
var subCallArgument: ReceiverKotlinCallArgument? = null
|
var subCallArgument: ReceiverKotlinCallArgument? = null
|
||||||
if (oldReceiver is ExpressionReceiver) {
|
if (oldReceiver is ExpressionReceiver) {
|
||||||
val ktExpression = KtPsiUtil.getLastElementDeparenthesized(oldReceiver.expression, context.statementFilter)
|
val ktExpression = KtPsiUtil.getLastElementDeparenthesized(oldReceiver.expression, context.statementFilter)
|
||||||
|
|
||||||
val bindingContext = context.trace.bindingContext
|
val bindingContext = context.trace.bindingContext
|
||||||
val call = bindingContext[BindingContext.DELEGATE_EXPRESSION_TO_PROVIDE_DELEGATE_CALL, ktExpression]
|
val call = bindingContext[BindingContext.DELEGATE_EXPRESSION_TO_PROVIDE_DELEGATE_CALL, ktExpression]
|
||||||
?: ktExpression?.getCall(bindingContext)
|
?: ktExpression?.getCall(bindingContext)
|
||||||
|
|
||||||
val onlyResolvedCall = call?.let {
|
val onlyResolvedCall = call?.let {
|
||||||
bindingContext.get(BindingContext.ONLY_RESOLVED_CALL, it)
|
bindingContext.get(BindingContext.ONLY_RESOLVED_CALL, it)
|
||||||
}
|
|
||||||
if (onlyResolvedCall != null) {
|
|
||||||
subCallArgument = SubKotlinCallArgumentImpl(CallMaker.makeExternalValueArgument(oldReceiver.expression),
|
|
||||||
context.dataFlowInfo, context.dataFlowInfo, detailedReceiver, onlyResolvedCall)
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
if (onlyResolvedCall != null) {
|
||||||
|
subCallArgument = SubKotlinCallArgumentImpl(
|
||||||
|
CallMaker.makeExternalValueArgument(oldReceiver.expression),
|
||||||
|
context.dataFlowInfo, context.dataFlowInfo, detailedReceiver, onlyResolvedCall
|
||||||
|
)
|
||||||
|
|
||||||
subCallArgument ?: ReceiverExpressionKotlinCallArgument(detailedReceiver, isSafeCall)
|
}
|
||||||
}
|
}
|
||||||
else -> error("Incorrect receiver: $oldReceiver")
|
|
||||||
|
subCallArgument ?: ReceiverExpressionKotlinCallArgument(detailedReceiver, isSafeCall)
|
||||||
}
|
}
|
||||||
|
else -> error("Incorrect receiver: $oldReceiver")
|
||||||
|
}
|
||||||
|
|
||||||
private fun resolveType(context: BasicCallResolutionContext, typeReference: KtTypeReference?): UnwrappedType? {
|
private fun resolveType(context: BasicCallResolutionContext, typeReference: KtTypeReference?): UnwrappedType? {
|
||||||
if (typeReference == null) return null
|
if (typeReference == null) return null
|
||||||
@@ -494,18 +525,19 @@ class PSICallResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveTypeArguments(context: BasicCallResolutionContext, typeArguments: List<KtTypeProjection>): List<TypeArgument> =
|
private fun resolveTypeArguments(context: BasicCallResolutionContext, typeArguments: List<KtTypeProjection>): List<TypeArgument> =
|
||||||
typeArguments.map { projection ->
|
typeArguments.map { projection ->
|
||||||
if (projection.projectionKind != KtProjectionKind.NONE) {
|
if (projection.projectionKind != KtProjectionKind.NONE) {
|
||||||
context.trace.report(Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection))
|
context.trace.report(Errors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT.on(projection))
|
||||||
}
|
|
||||||
ModifierCheckerCore.check(projection, context.trace, null, languageVersionSettings)
|
|
||||||
|
|
||||||
resolveType(context, projection.typeReference)?.let { SimpleTypeArgumentImpl(projection.typeReference!!, it) } ?: TypeArgumentPlaceholder
|
|
||||||
}
|
}
|
||||||
|
ModifierCheckerCore.check(projection, context.trace, null, languageVersionSettings)
|
||||||
|
|
||||||
|
resolveType(context, projection.typeReference)?.let { SimpleTypeArgumentImpl(projection.typeReference!!, it) }
|
||||||
|
?: TypeArgumentPlaceholder
|
||||||
|
}
|
||||||
|
|
||||||
private fun resolveArgumentsInParenthesis(
|
private fun resolveArgumentsInParenthesis(
|
||||||
context: BasicCallResolutionContext,
|
context: BasicCallResolutionContext,
|
||||||
arguments: List<ValueArgument>
|
arguments: List<ValueArgument>
|
||||||
): List<KotlinCallArgument> {
|
): List<KotlinCallArgument> {
|
||||||
val dataFlowInfoForArguments = context.dataFlowInfoForArguments
|
val dataFlowInfoForArguments = context.dataFlowInfoForArguments
|
||||||
return arguments.map { argument ->
|
return arguments.map { argument ->
|
||||||
@@ -516,9 +548,9 @@ class PSICallResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun resolveValueArgument(
|
private fun resolveValueArgument(
|
||||||
outerCallContext: BasicCallResolutionContext,
|
outerCallContext: BasicCallResolutionContext,
|
||||||
startDataFlowInfo: DataFlowInfo,
|
startDataFlowInfo: DataFlowInfo,
|
||||||
valueArgument: ValueArgument
|
valueArgument: ValueArgument
|
||||||
): PSIKotlinCallArgument {
|
): PSIKotlinCallArgument {
|
||||||
val builtIns = outerCallContext.scope.ownerDescriptor.builtIns
|
val builtIns = outerCallContext.scope.ownerDescriptor.builtIns
|
||||||
val parseErrorArgument = ParseErrorKotlinCallArgument(valueArgument, startDataFlowInfo, builtIns)
|
val parseErrorArgument = ParseErrorKotlinCallArgument(valueArgument, startDataFlowInfo, builtIns)
|
||||||
@@ -534,17 +566,21 @@ class PSICallResolver(
|
|||||||
|
|
||||||
if (ktExpression is KtCollectionLiteralExpression) {
|
if (ktExpression is KtCollectionLiteralExpression) {
|
||||||
return CollectionLiteralKotlinCallArgumentImpl(
|
return CollectionLiteralKotlinCallArgumentImpl(
|
||||||
valueArgument, argumentName, startDataFlowInfo, startDataFlowInfo, ktExpression, outerCallContext)
|
valueArgument, argumentName, startDataFlowInfo, startDataFlowInfo, ktExpression, outerCallContext
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val context = outerCallContext.replaceContextDependency(ContextDependency.DEPENDENT)
|
val context = outerCallContext.replaceContextDependency(ContextDependency.DEPENDENT)
|
||||||
.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceDataFlowInfo(startDataFlowInfo)
|
.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceDataFlowInfo(startDataFlowInfo)
|
||||||
|
|
||||||
if (ktExpression is KtCallableReferenceExpression) {
|
if (ktExpression is KtCallableReferenceExpression) {
|
||||||
checkNoSpread(outerCallContext, valueArgument)
|
checkNoSpread(outerCallContext, valueArgument)
|
||||||
|
|
||||||
val expressionTypingContext = ExpressionTypingContext.newContext(context)
|
val expressionTypingContext = ExpressionTypingContext.newContext(context)
|
||||||
val lhsResult = if (ktExpression.isEmptyLHS) null else doubleColonExpressionResolver.resolveDoubleColonLHS(ktExpression, expressionTypingContext)
|
val lhsResult = if (ktExpression.isEmptyLHS) null else doubleColonExpressionResolver.resolveDoubleColonLHS(
|
||||||
|
ktExpression,
|
||||||
|
expressionTypingContext
|
||||||
|
)
|
||||||
val newDataFlowInfo = (lhsResult as? DoubleColonLHS.Expression)?.dataFlowInfo ?: startDataFlowInfo
|
val newDataFlowInfo = (lhsResult as? DoubleColonLHS.Expression)?.dataFlowInfo ?: startDataFlowInfo
|
||||||
val name = ktExpression.callableReference.getReferencedNameAsName()
|
val name = ktExpression.callableReference.getReferencedNameAsName()
|
||||||
|
|
||||||
@@ -556,12 +592,10 @@ class PSICallResolver(
|
|||||||
val calleeExpression = ktExpression.receiverExpression?.getCalleeExpressionIfAny()
|
val calleeExpression = ktExpression.receiverExpression?.getCalleeExpressionIfAny()
|
||||||
if (calleeExpression is KtSimpleNameExpression && classifier is ClassDescriptor) {
|
if (calleeExpression is KtSimpleNameExpression && classifier is ClassDescriptor) {
|
||||||
LHSResult.Object(ClassQualifier(calleeExpression, classifier))
|
LHSResult.Object(ClassQualifier(calleeExpression, classifier))
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
LHSResult.Error
|
LHSResult.Error
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
val fakeArgument = FakeValueArgumentForLeftCallableReference(ktExpression)
|
val fakeArgument = FakeValueArgumentForLeftCallableReference(ktExpression)
|
||||||
|
|
||||||
val kotlinCallArgument = createSimplePSICallArgument(context, fakeArgument, lhsResult.typeInfo)
|
val kotlinCallArgument = createSimplePSICallArgument(context, fakeArgument, lhsResult.typeInfo)
|
||||||
@@ -573,15 +607,16 @@ class PSICallResolver(
|
|||||||
val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, qualifiedExpression)
|
val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, qualifiedExpression)
|
||||||
if (qualifier is ClassQualifier) {
|
if (qualifier is ClassQualifier) {
|
||||||
LHSResult.Type(qualifier, lhsResult.type.unwrap())
|
LHSResult.Type(qualifier, lhsResult.type.unwrap())
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
LHSResult.Error
|
LHSResult.Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return CallableReferenceKotlinCallArgumentImpl(ASTScopeTower(context), valueArgument, startDataFlowInfo, newDataFlowInfo,
|
return CallableReferenceKotlinCallArgumentImpl(
|
||||||
ktExpression, argumentName, lhsNewResult, name)
|
ASTScopeTower(context), valueArgument, startDataFlowInfo, newDataFlowInfo,
|
||||||
|
ktExpression, argumentName, lhsNewResult, name
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// argumentExpression instead of ktExpression is hack -- type info should be stored also for parenthesized expression
|
// argumentExpression instead of ktExpression is hack -- type info should be stored also for parenthesized expression
|
||||||
@@ -590,29 +625,33 @@ class PSICallResolver(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun processFunctionalExpression(
|
private fun processFunctionalExpression(
|
||||||
outerCallContext: BasicCallResolutionContext,
|
outerCallContext: BasicCallResolutionContext,
|
||||||
argumentExpression: KtExpression,
|
argumentExpression: KtExpression,
|
||||||
startDataFlowInfo: DataFlowInfo,
|
startDataFlowInfo: DataFlowInfo,
|
||||||
valueArgument: ValueArgument,
|
valueArgument: ValueArgument,
|
||||||
argumentName: Name?,
|
argumentName: Name?,
|
||||||
builtIns: KotlinBuiltIns
|
builtIns: KotlinBuiltIns
|
||||||
): PSIKotlinCallArgument? {
|
): PSIKotlinCallArgument? {
|
||||||
val expression = ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, outerCallContext) ?: return null
|
val expression = ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, outerCallContext) ?: return null
|
||||||
val postponedExpression = if (expression is KtFunctionLiteral) expression.getParentOfType<KtLambdaExpression>(true) else expression
|
val postponedExpression = if (expression is KtFunctionLiteral) expression.getParentOfType<KtLambdaExpression>(true) else expression
|
||||||
|
|
||||||
val lambdaArgument: PSIKotlinCallArgument? = when (postponedExpression) {
|
val lambdaArgument: PSIKotlinCallArgument? = when (postponedExpression) {
|
||||||
is KtLambdaExpression ->
|
is KtLambdaExpression ->
|
||||||
LambdaKotlinCallArgumentImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, postponedExpression,
|
LambdaKotlinCallArgumentImpl(
|
||||||
argumentExpression, resolveParametersTypes(outerCallContext, postponedExpression.functionLiteral))
|
outerCallContext, valueArgument, startDataFlowInfo, argumentName, postponedExpression,
|
||||||
|
argumentExpression, resolveParametersTypes(outerCallContext, postponedExpression.functionLiteral)
|
||||||
|
)
|
||||||
|
|
||||||
is KtNamedFunction -> {
|
is KtNamedFunction -> {
|
||||||
val receiverType = resolveType(outerCallContext, postponedExpression.receiverTypeReference)
|
val receiverType = resolveType(outerCallContext, postponedExpression.receiverTypeReference)
|
||||||
val parametersTypes = resolveParametersTypes(outerCallContext, postponedExpression) ?: emptyArray()
|
val parametersTypes = resolveParametersTypes(outerCallContext, postponedExpression) ?: emptyArray()
|
||||||
val returnType = resolveType(outerCallContext, postponedExpression.typeReference) ?:
|
val returnType = resolveType(outerCallContext, postponedExpression.typeReference)
|
||||||
if (postponedExpression.hasBlockBody()) builtIns.unitType else null
|
?: if (postponedExpression.hasBlockBody()) builtIns.unitType else null
|
||||||
|
|
||||||
FunctionExpressionImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName,
|
FunctionExpressionImpl(
|
||||||
argumentExpression, postponedExpression, receiverType, parametersTypes, returnType)
|
outerCallContext, valueArgument, startDataFlowInfo, argumentName,
|
||||||
|
argumentExpression, postponedExpression, receiverType, parametersTypes, returnType
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
else -> return null
|
else -> return null
|
||||||
|
|||||||
+64
-39
@@ -47,16 +47,16 @@ import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
|||||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||||
|
|
||||||
class ResolvedAtomCompleter(
|
class ResolvedAtomCompleter(
|
||||||
private val resultSubstitutor: NewTypeSubstitutor,
|
private val resultSubstitutor: NewTypeSubstitutor,
|
||||||
private val trace: BindingTrace,
|
private val trace: BindingTrace,
|
||||||
private val topLevelCallContext: BasicCallResolutionContext,
|
private val topLevelCallContext: BasicCallResolutionContext,
|
||||||
|
|
||||||
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||||
private val expressionTypingServices: ExpressionTypingServices,
|
private val expressionTypingServices: ExpressionTypingServices,
|
||||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||||
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||||
languageVersionSettings: LanguageVersionSettings,
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
deprecationResolver: DeprecationResolver
|
deprecationResolver: DeprecationResolver
|
||||||
) {
|
) {
|
||||||
private val callCheckerContext = CallCheckerContext(topLevelCallContext, languageVersionSettings, deprecationResolver)
|
private val callCheckerContext = CallCheckerContext(topLevelCallContext, languageVersionSettings, deprecationResolver)
|
||||||
|
|
||||||
@@ -79,7 +79,12 @@ class ResolvedAtomCompleter(
|
|||||||
fun completeResolvedCall(resolvedCallAtom: ResolvedCallAtom, diagnostics: Collection<KotlinCallDiagnostic>): ResolvedCall<*>? {
|
fun completeResolvedCall(resolvedCallAtom: ResolvedCallAtom, diagnostics: Collection<KotlinCallDiagnostic>): ResolvedCall<*>? {
|
||||||
if (resolvedCallAtom.atom.psiKotlinCall is PSIKotlinCallForVariable) return null
|
if (resolvedCallAtom.atom.psiKotlinCall is PSIKotlinCallForVariable) return null
|
||||||
|
|
||||||
val resolvedCall = kotlinToResolvedCallTransformer.transformToResolvedCall<CallableDescriptor>(resolvedCallAtom, trace, resultSubstitutor, diagnostics)
|
val resolvedCall = kotlinToResolvedCallTransformer.transformToResolvedCall<CallableDescriptor>(
|
||||||
|
resolvedCallAtom,
|
||||||
|
trace,
|
||||||
|
resultSubstitutor,
|
||||||
|
diagnostics
|
||||||
|
)
|
||||||
kotlinToResolvedCallTransformer.bindAndReport(topLevelCallContext, trace, resolvedCall, diagnostics)
|
kotlinToResolvedCallTransformer.bindAndReport(topLevelCallContext, trace, resolvedCall, diagnostics)
|
||||||
kotlinToResolvedCallTransformer.runCallCheckers(resolvedCall, callCheckerContext)
|
kotlinToResolvedCallTransformer.runCallCheckers(resolvedCall, callCheckerContext)
|
||||||
|
|
||||||
@@ -90,20 +95,20 @@ class ResolvedAtomCompleter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun completeLambda(lambda: ResolvedLambdaAtom) {
|
private fun completeLambda(lambda: ResolvedLambdaAtom) {
|
||||||
val returnType = resultSubstitutor.safeSubstitute(lambda.returnType)
|
val returnType = resultSubstitutor.safeSubstitute(lambda.returnType)
|
||||||
|
|
||||||
updateTraceForLambdaReturnType(lambda, trace, returnType)
|
updateTraceForLambdaReturnType(lambda, trace, returnType)
|
||||||
|
|
||||||
for (lambdaResult in lambda.resultArguments) {
|
for (lambdaResult in lambda.resultArguments) {
|
||||||
val resultValueArgument = lambdaResult as? PSIKotlinCallArgument ?: continue
|
val resultValueArgument = lambdaResult as? PSIKotlinCallArgument ?: continue
|
||||||
val newContext =
|
val newContext =
|
||||||
topLevelCallContext.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument)
|
topLevelCallContext.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument)
|
||||||
.replaceExpectedType(returnType)
|
.replaceExpectedType(returnType)
|
||||||
.replaceBindingTrace(trace)
|
.replaceBindingTrace(trace)
|
||||||
|
|
||||||
val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue
|
val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue
|
||||||
kotlinToResolvedCallTransformer.updateRecordedType(argumentExpression, newContext, true)
|
kotlinToResolvedCallTransformer.updateRecordedType(argumentExpression, newContext, true)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateTraceForLambdaReturnType(lambda: ResolvedLambdaAtom, trace: BindingTrace, returnType: UnwrappedType) {
|
private fun updateTraceForLambdaReturnType(lambda: ResolvedLambdaAtom, trace: BindingTrace, returnType: UnwrappedType) {
|
||||||
@@ -123,8 +128,8 @@ class ResolvedAtomCompleter(
|
|||||||
else -> throw AssertionError("Unexpected psiCallArgument for resolved lambda argument: $psiCallArgument")
|
else -> throw AssertionError("Unexpected psiCallArgument for resolved lambda argument: $psiCallArgument")
|
||||||
}
|
}
|
||||||
|
|
||||||
val functionDescriptor = trace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? FunctionDescriptorImpl ?:
|
val functionDescriptor = trace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? FunctionDescriptorImpl
|
||||||
throw AssertionError("No function descriptor for resolved lambda argument")
|
?: throw AssertionError("No function descriptor for resolved lambda argument")
|
||||||
functionDescriptor.setReturnType(returnType)
|
functionDescriptor.setReturnType(returnType)
|
||||||
|
|
||||||
val existingLambdaType = trace.getType(ktArgumentExpression) ?: throw AssertionError("No type for resolved lambda argument")
|
val existingLambdaType = trace.getType(ktArgumentExpression) ?: throw AssertionError("No type for resolved lambda argument")
|
||||||
@@ -132,26 +137,31 @@ class ResolvedAtomCompleter(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun completeCallableReference(
|
private fun completeCallableReference(
|
||||||
resolvedAtom: ResolvedCallableReferenceAtom
|
resolvedAtom: ResolvedCallableReferenceAtom
|
||||||
) {
|
) {
|
||||||
val callableCandidate = resolvedAtom.candidate
|
val callableCandidate = resolvedAtom.candidate
|
||||||
if (callableCandidate == null) {
|
if (callableCandidate == null) {
|
||||||
// todo report meanfull diagnostic here
|
// todo report meanfull diagnostic here
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val resultTypeParameters = callableCandidate.freshSubstitutor!!.freshVariables.map { resultSubstitutor.safeSubstitute(it.defaultType) }
|
val resultTypeParameters =
|
||||||
|
callableCandidate.freshSubstitutor!!.freshVariables.map { resultSubstitutor.safeSubstitute(it.defaultType) }
|
||||||
|
|
||||||
|
|
||||||
val psiCallArgument = resolvedAtom.atom.psiCallArgument as CallableReferenceKotlinCallArgumentImpl
|
val psiCallArgument = resolvedAtom.atom.psiCallArgument as CallableReferenceKotlinCallArgumentImpl
|
||||||
val callableReferenceExpression = psiCallArgument.ktCallableReferenceExpression
|
val callableReferenceExpression = psiCallArgument.ktCallableReferenceExpression
|
||||||
val resultSubstitutor = IndexedParametersSubstitution(callableCandidate.candidate.typeParameters, resultTypeParameters.map { it.asTypeProjection() }).buildSubstitutor()
|
val resultSubstitutor = IndexedParametersSubstitution(
|
||||||
|
callableCandidate.candidate.typeParameters,
|
||||||
|
resultTypeParameters.map { it.asTypeProjection() }).buildSubstitutor()
|
||||||
|
|
||||||
|
|
||||||
// write down type for callable reference expression
|
// write down type for callable reference expression
|
||||||
val resultType = resultSubstitutor.safeSubstitute(callableCandidate.reflectionCandidateType, Variance.INVARIANT)
|
val resultType = resultSubstitutor.safeSubstitute(callableCandidate.reflectionCandidateType, Variance.INVARIANT)
|
||||||
argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(trace, expressionTypingServices.statementFilter,
|
argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(
|
||||||
resultType,
|
trace, expressionTypingServices.statementFilter,
|
||||||
callableReferenceExpression)
|
resultType,
|
||||||
|
callableReferenceExpression
|
||||||
|
)
|
||||||
val reference = callableReferenceExpression.callableReference
|
val reference = callableReferenceExpression.callableReference
|
||||||
|
|
||||||
val explicitCallableReceiver = when (callableCandidate.explicitReceiverKind) {
|
val explicitCallableReceiver = when (callableCandidate.explicitReceiverKind) {
|
||||||
@@ -166,9 +176,11 @@ class ResolvedAtomCompleter(
|
|||||||
val tracing = TracingStrategyImpl.create(reference, psiCall)
|
val tracing = TracingStrategyImpl.create(reference, psiCall)
|
||||||
val temporaryTrace = TemporaryBindingTrace.create(trace, "callable reference fake call")
|
val temporaryTrace = TemporaryBindingTrace.create(trace, "callable reference fake call")
|
||||||
|
|
||||||
val resolvedCall = ResolvedCallImpl(psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue,
|
val resolvedCall = ResolvedCallImpl(
|
||||||
callableCandidate.extensionReceiver?.receiver?.receiverValue, callableCandidate.explicitReceiverKind,
|
psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue,
|
||||||
null, temporaryTrace, tracing, MutableDataFlowInfoForArguments.WithoutArgumentsCheck(DataFlowInfo.EMPTY))
|
callableCandidate.extensionReceiver?.receiver?.receiverValue, callableCandidate.explicitReceiverKind,
|
||||||
|
null, temporaryTrace, tracing, MutableDataFlowInfoForArguments.WithoutArgumentsCheck(DataFlowInfo.EMPTY)
|
||||||
|
)
|
||||||
resolvedCall.setResultingSubstitutor(resultSubstitutor)
|
resolvedCall.setResultingSubstitutor(resultSubstitutor)
|
||||||
|
|
||||||
tracing.bindCall(trace, psiCall)
|
tracing.bindCall(trace, psiCall)
|
||||||
@@ -179,27 +191,40 @@ class ResolvedAtomCompleter(
|
|||||||
resolvedCall.markCallAsCompleted()
|
resolvedCall.markCallAsCompleted()
|
||||||
|
|
||||||
when (callableCandidate.candidate) {
|
when (callableCandidate.candidate) {
|
||||||
is FunctionDescriptor -> doubleColonExpressionResolver.bindFunctionReference(callableReferenceExpression, resultType, topLevelCallContext)
|
is FunctionDescriptor -> doubleColonExpressionResolver.bindFunctionReference(
|
||||||
is PropertyDescriptor -> doubleColonExpressionResolver.bindPropertyReference(callableReferenceExpression, resultType, topLevelCallContext)
|
callableReferenceExpression,
|
||||||
|
resultType,
|
||||||
|
topLevelCallContext
|
||||||
|
)
|
||||||
|
is PropertyDescriptor -> doubleColonExpressionResolver.bindPropertyReference(
|
||||||
|
callableReferenceExpression,
|
||||||
|
resultType,
|
||||||
|
topLevelCallContext
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: probably we should also record key 'DATA_FLOW_INFO_BEFORE', see ExpressionTypingVisitorDispatcher.getTypeInfo
|
// TODO: probably we should also record key 'DATA_FLOW_INFO_BEFORE', see ExpressionTypingVisitorDispatcher.getTypeInfo
|
||||||
trace.recordType(callableReferenceExpression, resultType)
|
trace.recordType(callableReferenceExpression, resultType)
|
||||||
trace.record(BindingContext.PROCESSED, callableReferenceExpression)
|
trace.record(BindingContext.PROCESSED, callableReferenceExpression)
|
||||||
|
|
||||||
doubleColonExpressionResolver.checkReferenceIsToAllowedMember(callableCandidate.candidate, topLevelCallContext.trace, callableReferenceExpression)
|
doubleColonExpressionResolver.checkReferenceIsToAllowedMember(
|
||||||
|
callableCandidate.candidate,
|
||||||
|
topLevelCallContext.trace,
|
||||||
|
callableReferenceExpression
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun completeCollectionLiteralCalls(collectionLiteralArgument: ResolvedCollectionLiteralAtom) {
|
private fun completeCollectionLiteralCalls(collectionLiteralArgument: ResolvedCollectionLiteralAtom) {
|
||||||
val psiCallArgument = collectionLiteralArgument.atom.psiCallArgument as CollectionLiteralKotlinCallArgumentImpl
|
val psiCallArgument = collectionLiteralArgument.atom.psiCallArgument as CollectionLiteralKotlinCallArgumentImpl
|
||||||
val context = psiCallArgument.outerCallContext
|
val context = psiCallArgument.outerCallContext
|
||||||
|
|
||||||
val expectedType = collectionLiteralArgument.expectedType?.let { resultSubstitutor.safeSubstitute(it) } ?: TypeUtils.NO_EXPECTED_TYPE
|
val expectedType =
|
||||||
|
collectionLiteralArgument.expectedType?.let { resultSubstitutor.safeSubstitute(it) } ?: TypeUtils.NO_EXPECTED_TYPE
|
||||||
|
|
||||||
val actualContext = context
|
val actualContext = context
|
||||||
.replaceBindingTrace(trace)
|
.replaceBindingTrace(trace)
|
||||||
.replaceExpectedType(expectedType)
|
.replaceExpectedType(expectedType)
|
||||||
.replaceContextDependency(ContextDependency.INDEPENDENT)
|
.replaceContextDependency(ContextDependency.INDEPENDENT)
|
||||||
|
|
||||||
expressionTypingServices.getTypeInfo(psiCallArgument.collectionLiteralExpression, actualContext)
|
expressionTypingServices.getTypeInfo(psiCallArgument.collectionLiteralExpression, actualContext)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ fun <D : CallableDescriptor> ResolvedCall<D>.hasUnmappedParameters(): Boolean {
|
|||||||
return !parameterToArgumentMap.keys.containsAll(resultingDescriptor.valueParameters)
|
return !parameterToArgumentMap.keys.containsAll(resultingDescriptor.valueParameters)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun <D : CallableDescriptor> ResolvedCall<D>.allArgumentsMapped()
|
fun <D : CallableDescriptor> ResolvedCall<D>.allArgumentsMapped() =
|
||||||
= call.valueArguments.all { argument -> getArgumentMapping(argument) is ArgumentMatch }
|
call.valueArguments.all { argument -> getArgumentMapping(argument) is ArgumentMatch }
|
||||||
|
|
||||||
fun <D : CallableDescriptor> ResolvedCall<D>.hasTypeMismatchErrorOnParameter(parameter: ValueParameterDescriptor): Boolean {
|
fun <D : CallableDescriptor> ResolvedCall<D>.hasTypeMismatchErrorOnParameter(parameter: ValueParameterDescriptor): Boolean {
|
||||||
val resolvedValueArgument = valueArguments[parameter]
|
val resolvedValueArgument = valueArguments[parameter]
|
||||||
@@ -73,9 +73,9 @@ fun <D : CallableDescriptor> ResolvedCall<D>.usesDefaultArguments(): Boolean {
|
|||||||
|
|
||||||
// call
|
// call
|
||||||
|
|
||||||
fun <C: ResolutionContext<C>> Call.hasUnresolvedArguments(context: ResolutionContext<C>): Boolean {
|
fun <C : ResolutionContext<C>> Call.hasUnresolvedArguments(context: ResolutionContext<C>): Boolean {
|
||||||
val arguments = valueArguments.map { it.getArgumentExpression() }
|
val arguments = valueArguments.map { it.getArgumentExpression() }
|
||||||
return arguments.any (fun (argument: KtExpression?): Boolean {
|
return arguments.any(fun(argument: KtExpression?): Boolean {
|
||||||
if (argument == null || ArgumentTypeResolver.isFunctionLiteralOrCallableReference(argument, context)) return false
|
if (argument == null || ArgumentTypeResolver.isFunctionLiteralOrCallableReference(argument, context)) return false
|
||||||
|
|
||||||
val resolvedCall = argument.getResolvedCall(context.trace.bindingContext) as MutableResolvedCall<*>?
|
val resolvedCall = argument.getResolvedCall(context.trace.bindingContext) as MutableResolvedCall<*>?
|
||||||
@@ -91,12 +91,11 @@ fun Call.getValueArgumentsInParentheses(): List<ValueArgument> = valueArguments.
|
|||||||
fun KtCallElement.getValueArgumentsInParentheses(): List<ValueArgument> = valueArguments.filterArgsInParentheses()
|
fun KtCallElement.getValueArgumentsInParentheses(): List<ValueArgument> = valueArguments.filterArgsInParentheses()
|
||||||
|
|
||||||
fun Call.getValueArgumentListOrElement(): KtElement =
|
fun Call.getValueArgumentListOrElement(): KtElement =
|
||||||
if (this is CallTransformer.CallForImplicitInvoke) {
|
if (this is CallTransformer.CallForImplicitInvoke) {
|
||||||
outerCall.getValueArgumentListOrElement()
|
outerCall.getValueArgumentListOrElement()
|
||||||
}
|
} else {
|
||||||
else {
|
valueArgumentList ?: calleeExpression ?: callElement
|
||||||
valueArgumentList ?: calleeExpression ?: callElement
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
private fun List<ValueArgument?>.filterArgsInParentheses() = filter { it !is KtLambdaArgument } as List<ValueArgument>
|
private fun List<ValueArgument?>.filterArgsInParentheses() = filter { it !is KtLambdaArgument } as List<ValueArgument>
|
||||||
@@ -111,6 +110,7 @@ fun Call.getValueArgumentForExpression(expression: KtExpression): ValueArgument?
|
|||||||
else -> null
|
else -> null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun KtElement.isParenthesizedExpression() = generateSequence(this) { it.deparenthesizeStructurally() }.any { it == expression }
|
fun KtElement.isParenthesizedExpression() = generateSequence(this) { it.deparenthesizeStructurally() }.any { it == expression }
|
||||||
return valueArguments.firstOrNull { it?.getArgumentExpression()?.isParenthesizedExpression() ?: false }
|
return valueArguments.firstOrNull { it?.getArgumentExpression()?.isParenthesizedExpression() ?: false }
|
||||||
}
|
}
|
||||||
@@ -156,8 +156,9 @@ fun KtElement.getCall(context: BindingContext): Call? {
|
|||||||
|
|
||||||
fun KtElement.getParentCall(context: BindingContext, strict: Boolean = true): Call? {
|
fun KtElement.getParentCall(context: BindingContext, strict: Boolean = true): Call? {
|
||||||
val callExpressionTypes = arrayOf<Class<out KtElement>?>(
|
val callExpressionTypes = arrayOf<Class<out KtElement>?>(
|
||||||
KtSimpleNameExpression::class.java, KtCallElement::class.java, KtBinaryExpression::class.java,
|
KtSimpleNameExpression::class.java, KtCallElement::class.java, KtBinaryExpression::class.java,
|
||||||
KtUnaryExpression::class.java, KtArrayAccessExpression::class.java)
|
KtUnaryExpression::class.java, KtArrayAccessExpression::class.java
|
||||||
|
)
|
||||||
|
|
||||||
val parent = if (strict) {
|
val parent = if (strict) {
|
||||||
PsiTreeUtil.getParentOfType(this, *callExpressionTypes)
|
PsiTreeUtil.getParentOfType(this, *callExpressionTypes)
|
||||||
@@ -248,20 +249,19 @@ fun Call.isSafeCall(): Boolean {
|
|||||||
fun Call.isCallableReference(): Boolean {
|
fun Call.isCallableReference(): Boolean {
|
||||||
val callElement = callElement
|
val callElement = callElement
|
||||||
return callElement is KtNameReferenceExpression &&
|
return callElement is KtNameReferenceExpression &&
|
||||||
(callElement.parent as? KtCallableReferenceExpression)?.callableReference == callElement
|
(callElement.parent as? KtCallableReferenceExpression)?.callableReference == callElement
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Call.createLookupLocation(): KotlinLookupLocation {
|
fun Call.createLookupLocation(): KotlinLookupLocation {
|
||||||
val calleeExpression = calleeExpression
|
val calleeExpression = calleeExpression
|
||||||
val element =
|
val element =
|
||||||
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
|
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
|
||||||
else callElement
|
else callElement
|
||||||
return KotlinLookupLocation(element)
|
return KotlinLookupLocation(element)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun ResolvedCall<*>.getFirstArgumentExpression(): KtExpression? =
|
fun ResolvedCall<*>.getFirstArgumentExpression(): KtExpression? =
|
||||||
valueArgumentsByIndex?.run { get(0).arguments[0].getArgumentExpression() }
|
valueArgumentsByIndex?.run { get(0).arguments[0].getArgumentExpression() }
|
||||||
|
|
||||||
fun ResolvedCall<*>.getReceiverExpression(): KtExpression? =
|
fun ResolvedCall<*>.getReceiverExpression(): KtExpression? =
|
||||||
extensionReceiver.safeAs<ExpressionReceiver>()?.expression ?:
|
extensionReceiver.safeAs<ExpressionReceiver>()?.expression ?: dispatchReceiver.safeAs<ExpressionReceiver>()?.expression
|
||||||
dispatchReceiver.safeAs<ExpressionReceiver>()?.expression
|
|
||||||
+5
-5
@@ -26,11 +26,11 @@ import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility
|
|||||||
|
|
||||||
object ApiVersionClassifierUsageChecker : ClassifierUsageChecker {
|
object ApiVersionClassifierUsageChecker : ClassifierUsageChecker {
|
||||||
override fun check(
|
override fun check(
|
||||||
targetDescriptor: ClassifierDescriptor,
|
targetDescriptor: ClassifierDescriptor,
|
||||||
trace: BindingTrace,
|
trace: BindingTrace,
|
||||||
element: PsiElement,
|
element: PsiElement,
|
||||||
languageVersionSettings: LanguageVersionSettings,
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
deprecationResolver: DeprecationResolver
|
deprecationResolver: DeprecationResolver
|
||||||
) {
|
) {
|
||||||
targetDescriptor.checkSinceKotlinVersionAccessibility(languageVersionSettings) { version ->
|
targetDescriptor.checkSinceKotlinVersionAccessibility(languageVersionSettings) { version ->
|
||||||
trace.report(Errors.API_NOT_AVAILABLE.on(element, version.versionString, languageVersionSettings.apiVersion.versionString))
|
trace.report(Errors.API_NOT_AVAILABLE.on(element, version.versionString, languageVersionSettings.apiVersion.versionString))
|
||||||
|
|||||||
+10
-8
@@ -29,10 +29,10 @@ import org.jetbrains.kotlin.types.isError
|
|||||||
|
|
||||||
object ConstModifierChecker : SimpleDeclarationChecker {
|
object ConstModifierChecker : SimpleDeclarationChecker {
|
||||||
override fun check(
|
override fun check(
|
||||||
declaration: KtDeclaration,
|
declaration: KtDeclaration,
|
||||||
descriptor: DeclarationDescriptor,
|
descriptor: DeclarationDescriptor,
|
||||||
diagnosticHolder: DiagnosticSink,
|
diagnosticHolder: DiagnosticSink,
|
||||||
bindingContext: BindingContext
|
bindingContext: BindingContext
|
||||||
) {
|
) {
|
||||||
if (descriptor !is VariableDescriptor || !declaration.hasModifier(KtTokens.CONST_KEYWORD)) return
|
if (descriptor !is VariableDescriptor || !declaration.hasModifier(KtTokens.CONST_KEYWORD)) return
|
||||||
|
|
||||||
@@ -45,11 +45,13 @@ object ConstModifierChecker : SimpleDeclarationChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun canBeConst(declaration: KtDeclaration, constModifierPsiElement: PsiElement, descriptor: VariableDescriptor): Boolean =
|
fun canBeConst(declaration: KtDeclaration, constModifierPsiElement: PsiElement, descriptor: VariableDescriptor): Boolean =
|
||||||
checkCanBeConst(declaration, constModifierPsiElement, descriptor).canBeConst
|
checkCanBeConst(declaration, constModifierPsiElement, descriptor).canBeConst
|
||||||
|
|
||||||
private fun checkCanBeConst(declaration: KtDeclaration,
|
private fun checkCanBeConst(
|
||||||
constModifierPsiElement: PsiElement,
|
declaration: KtDeclaration,
|
||||||
descriptor: VariableDescriptor): ConstApplicability {
|
constModifierPsiElement: PsiElement,
|
||||||
|
descriptor: VariableDescriptor
|
||||||
|
): ConstApplicability {
|
||||||
if (descriptor.isVar) {
|
if (descriptor.isVar) {
|
||||||
return Errors.WRONG_MODIFIER_TARGET.on(constModifierPsiElement, KtTokens.CONST_KEYWORD, "vars").nonApplicable()
|
return Errors.WRONG_MODIFIER_TARGET.on(constModifierPsiElement, KtTokens.CONST_KEYWORD, "vars").nonApplicable()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,12 +34,12 @@ import org.jetbrains.kotlin.resolve.OverridingUtil
|
|||||||
|
|
||||||
class DelegationChecker : DeclarationChecker {
|
class DelegationChecker : DeclarationChecker {
|
||||||
override fun check(
|
override fun check(
|
||||||
declaration: KtDeclaration,
|
declaration: KtDeclaration,
|
||||||
descriptor: DeclarationDescriptor,
|
descriptor: DeclarationDescriptor,
|
||||||
diagnosticHolder: DiagnosticSink,
|
diagnosticHolder: DiagnosticSink,
|
||||||
bindingContext: BindingContext,
|
bindingContext: BindingContext,
|
||||||
languageVersionSettings: LanguageVersionSettings,
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
expectActualTracker: ExpectActualTracker
|
expectActualTracker: ExpectActualTracker
|
||||||
) {
|
) {
|
||||||
if (descriptor !is ClassDescriptor) return
|
if (descriptor !is ClassDescriptor) return
|
||||||
if (declaration !is KtClassOrObject) return
|
if (declaration !is KtClassOrObject) return
|
||||||
@@ -57,21 +57,27 @@ class DelegationChecker : DeclarationChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun checkDescriptor(
|
private fun checkDescriptor(
|
||||||
classDeclaration: KtClassOrObject,
|
classDeclaration: KtClassOrObject,
|
||||||
delegatedDescriptor: CallableMemberDescriptor,
|
delegatedDescriptor: CallableMemberDescriptor,
|
||||||
delegatedToDescriptor: CallableMemberDescriptor,
|
delegatedToDescriptor: CallableMemberDescriptor,
|
||||||
diagnosticHolder: DiagnosticSink
|
diagnosticHolder: DiagnosticSink
|
||||||
) {
|
) {
|
||||||
val reachableFromDelegated =
|
val reachableFromDelegated =
|
||||||
OverridingUtil.filterOutOverridden(
|
OverridingUtil.filterOutOverridden(
|
||||||
DescriptorUtils.getAllOverriddenDescriptors(delegatedDescriptor).filter { it.kind.isReal }.toSet()
|
DescriptorUtils.getAllOverriddenDescriptors(delegatedDescriptor).filter { it.kind.isReal }.toSet()
|
||||||
) - DescriptorUtils.unwrapFakeOverride(delegatedToDescriptor).original
|
) - DescriptorUtils.unwrapFakeOverride(delegatedToDescriptor).original
|
||||||
|
|
||||||
val nonAbstractReachable = reachableFromDelegated.filter { it.modality == Modality.OPEN }
|
val nonAbstractReachable = reachableFromDelegated.filter { it.modality == Modality.OPEN }
|
||||||
|
|
||||||
if (nonAbstractReachable.isNotEmpty()) {
|
if (nonAbstractReachable.isNotEmpty()) {
|
||||||
/*In case of MANY_IMPL_MEMBER_NOT_IMPLEMENTED error there could be several elements otherwise only one*/
|
/*In case of MANY_IMPL_MEMBER_NOT_IMPLEMENTED error there could be several elements otherwise only one*/
|
||||||
diagnosticHolder.report(DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE.on(classDeclaration, delegatedDescriptor, nonAbstractReachable))
|
diagnosticHolder.report(
|
||||||
|
DELEGATED_MEMBER_HIDES_SUPERTYPE_OVERRIDE.on(
|
||||||
|
classDeclaration,
|
||||||
|
delegatedDescriptor,
|
||||||
|
nonAbstractReachable
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user