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
|
||||
|
||||
class ResolverForModule(
|
||||
val packageFragmentProvider: PackageFragmentProvider,
|
||||
val componentProvider: ComponentProvider
|
||||
val packageFragmentProvider: PackageFragmentProvider,
|
||||
val componentProvider: ComponentProvider
|
||||
)
|
||||
|
||||
abstract class ResolverForProject<M : ModuleInfo> {
|
||||
@@ -70,34 +70,36 @@ class EmptyResolverForProject<M : ModuleInfo> : ResolverForProject<M>() {
|
||||
get() = "Empty resolver"
|
||||
|
||||
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 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>(
|
||||
private val debugName: String,
|
||||
private val projectContext: ProjectContext,
|
||||
modules: Collection<M>,
|
||||
private val analyzerFacade: (M) -> AnalyzerFacade,
|
||||
private val modulesContent: (M) -> ModuleContent,
|
||||
private val platformParameters: PlatformAnalysisParameters,
|
||||
private val targetEnvironment: TargetEnvironment = CompilerEnvironment,
|
||||
private val builtIns: KotlinBuiltIns = DefaultBuiltIns.Instance,
|
||||
private val delegateResolver: ResolverForProject<M> = EmptyResolverForProject(),
|
||||
private val packagePartProviderFactory: (M, ModuleContent) -> PackagePartProvider = { _, _ -> PackagePartProvider.Empty },
|
||||
private val firstDependency: M? = null,
|
||||
private val modulePlatforms: (M) -> MultiTargetPlatform?,
|
||||
private val packageOracleFactory: PackageOracleFactory = PackageOracleFactory.OptimisticFactory,
|
||||
private val languageSettingsProvider: LanguageSettingsProvider = LanguageSettingsProvider.Default,
|
||||
private val invalidateOnOOCB: Boolean = true
|
||||
private val debugName: String,
|
||||
private val projectContext: ProjectContext,
|
||||
modules: Collection<M>,
|
||||
private val analyzerFacade: (M) -> AnalyzerFacade,
|
||||
private val modulesContent: (M) -> ModuleContent,
|
||||
private val platformParameters: PlatformAnalysisParameters,
|
||||
private val targetEnvironment: TargetEnvironment = CompilerEnvironment,
|
||||
private val builtIns: KotlinBuiltIns = DefaultBuiltIns.Instance,
|
||||
private val delegateResolver: ResolverForProject<M> = EmptyResolverForProject(),
|
||||
private val packagePartProviderFactory: (M, ModuleContent) -> PackagePartProvider = { _, _ -> PackagePartProvider.Empty },
|
||||
private val firstDependency: M? = null,
|
||||
private val modulePlatforms: (M) -> MultiTargetPlatform?,
|
||||
private val packageOracleFactory: PackageOracleFactory = PackageOracleFactory.OptimisticFactory,
|
||||
private val languageSettingsProvider: LanguageSettingsProvider = LanguageSettingsProvider.Default,
|
||||
private val invalidateOnOOCB: Boolean = true
|
||||
) : ResolverForProject<M>() {
|
||||
|
||||
private class ModuleData(
|
||||
val moduleDescriptor: ModuleDescriptorImpl,
|
||||
val modificationTracker: ModificationTracker?,
|
||||
val modificationCount: Long?
|
||||
val moduleDescriptor: ModuleDescriptorImpl,
|
||||
val modificationTracker: ModificationTracker?,
|
||||
val modificationCount: Long?
|
||||
) {
|
||||
fun isOutOfDate(): Boolean {
|
||||
val currentModCount = modificationTracker?.modificationCount
|
||||
@@ -117,16 +119,22 @@ class ResolverForProjectImpl<M : ModuleInfo>(
|
||||
}
|
||||
|
||||
private fun setupModuleDescriptor(module: M, moduleDescriptor: ModuleDescriptorImpl) {
|
||||
moduleDescriptor.setDependencies(LazyModuleDependencies(
|
||||
moduleDescriptor.setDependencies(
|
||||
LazyModuleDependencies(
|
||||
projectContext.storageManager,
|
||||
module,
|
||||
firstDependency,
|
||||
this))
|
||||
this
|
||||
)
|
||||
)
|
||||
|
||||
val content = modulesContent(module)
|
||||
moduleDescriptor.initialize(
|
||||
DelegatingPackageFragmentProvider(this, moduleDescriptor, content,
|
||||
packageOracleFactory.createOracle(module)))
|
||||
DelegatingPackageFragmentProvider(
|
||||
this, moduleDescriptor, content,
|
||||
packageOracleFactory.createOracle(module)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private val resolverByModuleDescriptor = mutableMapOf<ModuleDescriptor, ResolverForModule>()
|
||||
@@ -153,16 +161,17 @@ class ResolverForProjectImpl<M : ModuleInfo>(
|
||||
ResolverForModuleComputationTracker.getInstance(projectContext.project)?.onResolverComputed(module)
|
||||
|
||||
analyzerFacade(module).createResolverForModule(
|
||||
module, descriptor as ModuleDescriptorImpl, projectContext.withModule(descriptor), modulesContent(module),
|
||||
platformParameters, targetEnvironment, this@ResolverForProjectImpl,
|
||||
languageSettingsProvider,
|
||||
packagePartProviderFactory(module, modulesContent(module)))
|
||||
module, descriptor as ModuleDescriptorImpl, projectContext.withModule(descriptor), modulesContent(module),
|
||||
platformParameters, targetEnvironment, this@ResolverForProjectImpl,
|
||||
languageSettingsProvider,
|
||||
packagePartProviderFactory(module, modulesContent(module))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun isResolverForModuleDescriptorComputed(descriptor: ModuleDescriptor) =
|
||||
descriptor in resolverByModuleDescriptor
|
||||
descriptor in resolverByModuleDescriptor
|
||||
|
||||
override fun descriptorForModule(moduleInfo: M): ModuleDescriptorImpl {
|
||||
if (!isCorrectModuleInfo(moduleInfo)) {
|
||||
@@ -172,7 +181,7 @@ class ResolverForProjectImpl<M : 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 {
|
||||
if (module in modules) {
|
||||
@@ -204,19 +213,21 @@ class ResolverForProjectImpl<M : ModuleInfo>(
|
||||
}
|
||||
|
||||
private fun createModuleDescriptor(module: M): ModuleData {
|
||||
val moduleDescriptor = ModuleDescriptorImpl(module.name,
|
||||
projectContext.storageManager, builtIns, modulePlatforms(module), module.capabilities)
|
||||
val moduleDescriptor = ModuleDescriptorImpl(
|
||||
module.name,
|
||||
projectContext.storageManager, builtIns, modulePlatforms(module), module.capabilities
|
||||
)
|
||||
moduleInfoByDescriptor[moduleDescriptor] = module
|
||||
setupModuleDescriptor(module, moduleDescriptor)
|
||||
val modificationTracker = (module as? TrackableModuleInfo)?.createModificationTracker() ?:
|
||||
(PsiModificationTracker.SERVICE.getInstance(projectContext.project).outOfCodeBlockModificationTracker.takeIf { invalidateOnOOCB })
|
||||
val modificationTracker = (module as? TrackableModuleInfo)?.createModificationTracker()
|
||||
?: (PsiModificationTracker.SERVICE.getInstance(projectContext.project).outOfCodeBlockModificationTracker.takeIf { invalidateOnOOCB })
|
||||
return ModuleData(moduleDescriptor, modificationTracker, modificationTracker?.modificationCount)
|
||||
}
|
||||
}
|
||||
|
||||
data class ModuleContent(
|
||||
val syntheticFiles: Collection<KtFile>,
|
||||
val moduleContentScope: GlobalSearchScope
|
||||
val syntheticFiles: Collection<KtFile>,
|
||||
val moduleContentScope: GlobalSearchScope
|
||||
)
|
||||
|
||||
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
|
||||
// additional members dependent on the JDK
|
||||
fun dependencyOnBuiltIns(): ModuleInfo.DependencyOnBuiltIns =
|
||||
if (platform == TargetPlatform.Common)
|
||||
ModuleInfo.DependencyOnBuiltIns.AFTER_SDK
|
||||
else
|
||||
ModuleInfo.DependencyOnBuiltIns.LAST
|
||||
if (platform == TargetPlatform.Common)
|
||||
ModuleInfo.DependencyOnBuiltIns.AFTER_SDK
|
||||
else
|
||||
ModuleInfo.DependencyOnBuiltIns.LAST
|
||||
|
||||
//TODO: (module refactoring) provide dependency on builtins after runtime in IDEA
|
||||
enum class DependencyOnBuiltIns { NONE, AFTER_SDK, LAST }
|
||||
@@ -257,25 +268,25 @@ interface TrackableModuleInfo : ModuleInfo {
|
||||
|
||||
abstract class AnalyzerFacade {
|
||||
abstract fun <M : ModuleInfo> createResolverForModule(
|
||||
moduleInfo: M,
|
||||
moduleDescriptor: ModuleDescriptorImpl,
|
||||
moduleContext: ModuleContext,
|
||||
moduleContent: ModuleContent,
|
||||
platformParameters: PlatformAnalysisParameters,
|
||||
targetEnvironment: TargetEnvironment,
|
||||
resolverForProject: ResolverForProject<M>,
|
||||
languageSettingsProvider: LanguageSettingsProvider,
|
||||
packagePartProvider: PackagePartProvider
|
||||
moduleInfo: M,
|
||||
moduleDescriptor: ModuleDescriptorImpl,
|
||||
moduleContext: ModuleContext,
|
||||
moduleContent: ModuleContent,
|
||||
platformParameters: PlatformAnalysisParameters,
|
||||
targetEnvironment: TargetEnvironment,
|
||||
resolverForProject: ResolverForProject<M>,
|
||||
languageSettingsProvider: LanguageSettingsProvider,
|
||||
packagePartProvider: PackagePartProvider
|
||||
): ResolverForModule
|
||||
|
||||
abstract val targetPlatform: TargetPlatform
|
||||
}
|
||||
|
||||
class LazyModuleDependencies<M: ModuleInfo>(
|
||||
storageManager: StorageManager,
|
||||
private val module: M,
|
||||
firstDependency: M? = null,
|
||||
private val resolverForProject: ResolverForProjectImpl<M>
|
||||
class LazyModuleDependencies<M : ModuleInfo>(
|
||||
storageManager: StorageManager,
|
||||
private val module: M,
|
||||
firstDependency: M? = null,
|
||||
private val resolverForProject: ResolverForProjectImpl<M>
|
||||
) : ModuleDependencies {
|
||||
private val dependencies = storageManager.createLazyValue {
|
||||
val moduleDescriptor = resolverForProject.descriptorForModule(module)
|
||||
@@ -307,10 +318,10 @@ class LazyModuleDependencies<M: ModuleInfo>(
|
||||
|
||||
|
||||
private class DelegatingPackageFragmentProvider<M : ModuleInfo>(
|
||||
private val resolverForProject: ResolverForProjectImpl<M>,
|
||||
private val module: ModuleDescriptor,
|
||||
moduleContent: ModuleContent,
|
||||
private val packageOracle: PackageOracle
|
||||
private val resolverForProject: ResolverForProjectImpl<M>,
|
||||
private val module: ModuleDescriptor,
|
||||
moduleContent: ModuleContent,
|
||||
private val packageOracle: PackageOracle
|
||||
) : PackageFragmentProvider {
|
||||
private val syntheticFilePackages = moduleContent.syntheticFiles.map { it.packageFqName }.toSet()
|
||||
|
||||
@@ -366,6 +377,7 @@ interface ResolverForModuleComputationTracker {
|
||||
fun onResolverComputed(moduleInfo: ModuleInfo)
|
||||
|
||||
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() {
|
||||
private class SourceModuleInfo(
|
||||
override val name: Name,
|
||||
override val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>,
|
||||
private val dependOnOldBuiltIns: Boolean
|
||||
override val name: Name,
|
||||
override val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>,
|
||||
private val dependOnOldBuiltIns: Boolean
|
||||
) : ModuleInfo {
|
||||
override fun dependencies() = listOf(this)
|
||||
|
||||
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(
|
||||
files: Collection<KtFile>, moduleName: Name, dependOnBuiltIns: Boolean, languageVersionSettings: LanguageVersionSettings,
|
||||
capabilities: Map<ModuleDescriptor.Capability<*>, Any?> = mapOf(MultiTargetPlatform.CAPABILITY to MultiTargetPlatform.Common),
|
||||
packagePartProviderFactory: (ModuleInfo, ModuleContent) -> PackagePartProvider
|
||||
files: Collection<KtFile>, moduleName: Name, dependOnBuiltIns: Boolean, languageVersionSettings: LanguageVersionSettings,
|
||||
capabilities: Map<ModuleDescriptor.Capability<*>, Any?> = mapOf(MultiTargetPlatform.CAPABILITY to MultiTargetPlatform.Common),
|
||||
packagePartProviderFactory: (ModuleInfo, ModuleContent) -> PackagePartProvider
|
||||
): AnalysisResult {
|
||||
val moduleInfo = SourceModuleInfo(moduleName, capabilities, dependOnBuiltIns)
|
||||
val project = files.firstOrNull()?.project ?: throw AssertionError("No files to analyze")
|
||||
|
||||
val multiplatformLanguageSettings = object : LanguageVersionSettings by languageVersionSettings {
|
||||
override fun getFeatureSupport(feature: LanguageFeature): LanguageFeature.State =
|
||||
if (feature == LanguageFeature.MultiPlatformProjects) LanguageFeature.State.ENABLED
|
||||
else languageVersionSettings.getFeatureSupport(feature)
|
||||
if (feature == LanguageFeature.MultiPlatformProjects) LanguageFeature.State.ENABLED
|
||||
else languageVersionSettings.getFeatureSupport(feature)
|
||||
}
|
||||
|
||||
@Suppress("NAME_SHADOWING")
|
||||
val resolver = ResolverForProjectImpl (
|
||||
"sources for metadata serializer",
|
||||
ProjectContext(project), listOf(moduleInfo), { CommonAnalyzerFacade },
|
||||
{ ModuleContent(files, GlobalSearchScope.allScope(project)) },
|
||||
object : PlatformAnalysisParameters {},
|
||||
languageSettingsProvider = object : LanguageSettingsProvider {
|
||||
override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project) = multiplatformLanguageSettings
|
||||
override fun getTargetPlatform(moduleInfo: ModuleInfo) = TargetPlatformVersion.NoVersion
|
||||
},
|
||||
packagePartProviderFactory = packagePartProviderFactory,
|
||||
modulePlatforms = { MultiTargetPlatform.Common }
|
||||
val resolver = ResolverForProjectImpl(
|
||||
"sources for metadata serializer",
|
||||
ProjectContext(project), listOf(moduleInfo), { CommonAnalyzerFacade },
|
||||
{ ModuleContent(files, GlobalSearchScope.allScope(project)) },
|
||||
object : PlatformAnalysisParameters {},
|
||||
languageSettingsProvider = object : LanguageSettingsProvider {
|
||||
override fun getLanguageVersionSettings(moduleInfo: ModuleInfo, project: Project) = multiplatformLanguageSettings
|
||||
override fun getTargetPlatform(moduleInfo: ModuleInfo) = TargetPlatformVersion.NoVersion
|
||||
},
|
||||
packagePartProviderFactory = packagePartProviderFactory,
|
||||
modulePlatforms = { MultiTargetPlatform.Common }
|
||||
)
|
||||
|
||||
val moduleDescriptor = resolver.descriptorForModule(moduleInfo)
|
||||
@@ -98,46 +98,46 @@ object CommonAnalyzerFacade : AnalyzerFacade() {
|
||||
}
|
||||
|
||||
override fun <M : ModuleInfo> createResolverForModule(
|
||||
moduleInfo: M,
|
||||
moduleDescriptor: ModuleDescriptorImpl,
|
||||
moduleContext: ModuleContext,
|
||||
moduleContent: ModuleContent,
|
||||
platformParameters: PlatformAnalysisParameters,
|
||||
targetEnvironment: TargetEnvironment,
|
||||
resolverForProject: ResolverForProject<M>,
|
||||
languageSettingsProvider: LanguageSettingsProvider,
|
||||
packagePartProvider: PackagePartProvider
|
||||
moduleInfo: M,
|
||||
moduleDescriptor: ModuleDescriptorImpl,
|
||||
moduleContext: ModuleContext,
|
||||
moduleContent: ModuleContent,
|
||||
platformParameters: PlatformAnalysisParameters,
|
||||
targetEnvironment: TargetEnvironment,
|
||||
resolverForProject: ResolverForProject<M>,
|
||||
languageSettingsProvider: LanguageSettingsProvider,
|
||||
packagePartProvider: PackagePartProvider
|
||||
): ResolverForModule {
|
||||
val (syntheticFiles, moduleContentScope) = moduleContent
|
||||
val project = moduleContext.project
|
||||
val declarationProviderFactory = DeclarationProviderFactoryService.createDeclarationProviderFactory(
|
||||
project, moduleContext.storageManager, syntheticFiles,
|
||||
if (moduleInfo.isLibrary) GlobalSearchScope.EMPTY_SCOPE else moduleContentScope,
|
||||
moduleInfo
|
||||
project, moduleContext.storageManager, syntheticFiles,
|
||||
if (moduleInfo.isLibrary) GlobalSearchScope.EMPTY_SCOPE else moduleContentScope,
|
||||
moduleInfo
|
||||
)
|
||||
|
||||
val trace = CodeAnalyzerInitializer.getInstance(project).createTrace()
|
||||
val container = createContainerToResolveCommonCode(
|
||||
moduleContext, trace, declarationProviderFactory, moduleContentScope, targetEnvironment, packagePartProvider,
|
||||
languageSettingsProvider.getLanguageVersionSettings(moduleInfo, project)
|
||||
moduleContext, trace, declarationProviderFactory, moduleContentScope, targetEnvironment, packagePartProvider,
|
||||
languageSettingsProvider.getLanguageVersionSettings(moduleInfo, project)
|
||||
)
|
||||
|
||||
val packageFragmentProviders = listOf(
|
||||
container.get<ResolveSession>().packageFragmentProvider,
|
||||
container.get<MetadataPackageFragmentProvider>()
|
||||
container.get<ResolveSession>().packageFragmentProvider,
|
||||
container.get<MetadataPackageFragmentProvider>()
|
||||
)
|
||||
|
||||
return ResolverForModule(CompositePackageFragmentProvider(packageFragmentProviders), container)
|
||||
}
|
||||
|
||||
private fun createContainerToResolveCommonCode(
|
||||
moduleContext: ModuleContext,
|
||||
bindingTrace: BindingTrace,
|
||||
declarationProviderFactory: DeclarationProviderFactory,
|
||||
moduleContentScope: GlobalSearchScope,
|
||||
targetEnvironment: TargetEnvironment,
|
||||
packagePartProvider: PackagePartProvider,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
moduleContext: ModuleContext,
|
||||
bindingTrace: BindingTrace,
|
||||
declarationProviderFactory: DeclarationProviderFactory,
|
||||
moduleContentScope: GlobalSearchScope,
|
||||
targetEnvironment: TargetEnvironment,
|
||||
packagePartProvider: PackagePartProvider,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): StorageComponentContainer = createContainer("ResolveCommonCode", targetPlatform) {
|
||||
configureModule(moduleContext, targetPlatform, TargetPlatformVersion.NoVersion, bindingTrace)
|
||||
|
||||
@@ -154,7 +154,7 @@ object CommonAnalyzerFacade : AnalyzerFacade() {
|
||||
useImpl<MetadataPackageFragmentProvider>()
|
||||
|
||||
val metadataFinderFactory = ServiceManager.getService(moduleContext.project, MetadataFinderFactory::class.java)
|
||||
?: error("No MetadataFinderFactory in project")
|
||||
?: error("No MetadataFinderFactory in project")
|
||||
useInstance(metadataFinderFactory.create(moduleContentScope))
|
||||
|
||||
targetEnvironment.configure(this)
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||
interface ControlFlowBuilder {
|
||||
// Subroutines
|
||||
fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind? = null)
|
||||
|
||||
fun exitSubroutine(subroutine: KtElement, invocationKind: InvocationKind? = null): Pseudocode
|
||||
|
||||
val currentSubroutine: KtElement
|
||||
|
||||
@@ -624,7 +624,7 @@ class ControlFlowInformationProvider private constructor(
|
||||
if (!VariableUseState.isUsed(variableUseState)) {
|
||||
if (element.isSingleUnderscore) return
|
||||
when {
|
||||
// KtDestructuringDeclarationEntry -> KtDestructuringDeclaration -> KtParameter -> KtParameterList
|
||||
// KtDestructuringDeclarationEntry -> KtDestructuringDeclaration -> KtParameter -> KtParameterList
|
||||
element is KtDestructuringDeclarationEntry && element.parent.parent?.parent is KtParameterList ->
|
||||
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<*>)
|
||||
|
||||
val calls = HashMap<KtElement, KindAndCall>()
|
||||
traverseCalls traverse@{ instruction, resolvedCall ->
|
||||
traverseCalls traverse@ { instruction, resolvedCall ->
|
||||
// is this a recursive call?
|
||||
val functionDescriptor = resolvedCall.resultingDescriptor
|
||||
if (functionDescriptor.original != subroutineDescriptor) return@traverse
|
||||
|
||||
@@ -1021,23 +1021,23 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
||||
private fun visitInlinedFunction(lambdaFunctionLiteral: KtFunction, invocationKind: InvocationKind) {
|
||||
// Defer emitting of inlined declaration
|
||||
deferredGeneratorsStack.peek().add({ builder ->
|
||||
val beforeDeclaration = builder.createUnboundLabel("before inlined declaration")
|
||||
val afterDeclaration = builder.createUnboundLabel("after inlined declaration")
|
||||
val beforeDeclaration = builder.createUnboundLabel("before inlined declaration")
|
||||
val afterDeclaration = builder.createUnboundLabel("after inlined declaration")
|
||||
|
||||
builder.bindLabel(beforeDeclaration)
|
||||
builder.bindLabel(beforeDeclaration)
|
||||
|
||||
if (!invocationKind.isDefinitelyVisited()) {
|
||||
builder.nondeterministicJump(afterDeclaration, lambdaFunctionLiteral, null)
|
||||
}
|
||||
if (!invocationKind.isDefinitelyVisited()) {
|
||||
builder.nondeterministicJump(afterDeclaration, lambdaFunctionLiteral, null)
|
||||
}
|
||||
|
||||
generate(lambdaFunctionLiteral, invocationKind)
|
||||
generate(lambdaFunctionLiteral, invocationKind)
|
||||
|
||||
if (invocationKind.canBeRevisited()) {
|
||||
builder.nondeterministicJump(beforeDeclaration, lambdaFunctionLiteral, null)
|
||||
}
|
||||
if (invocationKind.canBeRevisited()) {
|
||||
builder.nondeterministicJump(beforeDeclaration, lambdaFunctionLiteral, null)
|
||||
}
|
||||
|
||||
builder.bindLabel(afterDeclaration)
|
||||
})
|
||||
builder.bindLabel(afterDeclaration)
|
||||
})
|
||||
}
|
||||
|
||||
override fun visitNamedFunction(function: KtNamedFunction) {
|
||||
@@ -1544,8 +1544,10 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
||||
//noinspection EnumSwitchStatementWhichMissesCases
|
||||
when (kind) {
|
||||
ExplicitReceiverKind.DISPATCH_RECEIVER -> explicitReceiver = resolvedCall.dispatchReceiver
|
||||
ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> explicitReceiver = resolvedCall.extensionReceiver
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER -> {}
|
||||
ExplicitReceiverKind.EXTENSION_RECEIVER, ExplicitReceiverKind.BOTH_RECEIVERS -> explicitReceiver =
|
||||
resolvedCall.extensionReceiver
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -29,28 +29,28 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
||||
|
||||
class PseudocodeVariableDataCollector(
|
||||
private val bindingContext: BindingContext,
|
||||
private val pseudocode: Pseudocode
|
||||
private val bindingContext: BindingContext,
|
||||
private val pseudocode: Pseudocode
|
||||
) {
|
||||
val blockScopeVariableInfo = computeBlockScopeVariableInfo(pseudocode)
|
||||
|
||||
fun <I : ControlFlowInfo<*, *>> collectData(
|
||||
traversalOrder: TraversalOrder,
|
||||
initialInfo: I,
|
||||
instructionDataMergeStrategy: (Instruction, Collection<I>) -> Edges<I>
|
||||
traversalOrder: TraversalOrder,
|
||||
initialInfo: I,
|
||||
instructionDataMergeStrategy: (Instruction, Collection<I>) -> Edges<I>
|
||||
): Map<Instruction, Edges<I>> {
|
||||
return pseudocode.collectData(
|
||||
traversalOrder,
|
||||
instructionDataMergeStrategy,
|
||||
{ from, to, info -> filterOutVariablesOutOfScope(from, to, info) },
|
||||
initialInfo
|
||||
traversalOrder,
|
||||
instructionDataMergeStrategy,
|
||||
{ from, to, info -> filterOutVariablesOutOfScope(from, to, info) },
|
||||
initialInfo
|
||||
)
|
||||
}
|
||||
|
||||
private fun <I : ControlFlowInfo<*, *>> filterOutVariablesOutOfScope(
|
||||
from: Instruction,
|
||||
to: Instruction,
|
||||
info: I
|
||||
from: Instruction,
|
||||
to: Instruction,
|
||||
info: I
|
||||
): I {
|
||||
// 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
|
||||
@@ -74,9 +74,11 @@ class PseudocodeVariableDataCollector(
|
||||
val variableDeclarationElement = instruction.variableDeclarationElement
|
||||
val descriptor = bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement) ?: return@traverse
|
||||
val variableDescriptor = BindingContextUtils.variableDescriptorForDeclaration(descriptor)
|
||||
?: throw AssertionError("Variable or class descriptor should correspond to " +
|
||||
"the instruction for ${instruction.element.text}.\n" +
|
||||
"Descriptor: $descriptor")
|
||||
?: throw AssertionError(
|
||||
"Variable or class descriptor should correspond to " +
|
||||
"the instruction for ${instruction.element.text}.\n" +
|
||||
"Descriptor: $descriptor"
|
||||
)
|
||||
blockScopeVariableInfo.registerVariableDeclaredInScope(variableDescriptor, instruction.blockScope)
|
||||
}
|
||||
})
|
||||
@@ -85,8 +87,8 @@ class PseudocodeVariableDataCollector(
|
||||
}
|
||||
|
||||
interface BlockScopeVariableInfo {
|
||||
val declaredIn : Map<VariableDescriptor, BlockScope>
|
||||
val scopeVariables : Map<BlockScope, Collection<VariableDescriptor>>
|
||||
val declaredIn: Map<VariableDescriptor, BlockScope>
|
||||
val scopeVariables: Map<BlockScope, Collection<VariableDescriptor>>
|
||||
}
|
||||
|
||||
class BlockScopeVariableInfoImpl : BlockScopeVariableInfo {
|
||||
|
||||
@@ -42,14 +42,14 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
private val pseudocodeVariableDataCollector = PseudocodeVariableDataCollector(bindingContext, pseudocode)
|
||||
|
||||
private class VariablesForDeclaration(
|
||||
val valsWithTrivialInitializer: Set<VariableDescriptor>,
|
||||
val nonTrivialVariables: Set<VariableDescriptor>
|
||||
val valsWithTrivialInitializer: Set<VariableDescriptor>,
|
||||
val nonTrivialVariables: Set<VariableDescriptor>
|
||||
) {
|
||||
val allVars =
|
||||
if (nonTrivialVariables.isEmpty())
|
||||
valsWithTrivialInitializer
|
||||
else
|
||||
LinkedHashSet(valsWithTrivialInitializer).also { it.addAll(nonTrivialVariables) }
|
||||
if (nonTrivialVariables.isEmpty())
|
||||
valsWithTrivialInitializer
|
||||
else
|
||||
LinkedHashSet(valsWithTrivialInitializer).also { it.addAll(nonTrivialVariables) }
|
||||
}
|
||||
|
||||
private val declaredVariablesForDeclaration = hashMapOf<Pseudocode, VariablesForDeclaration>()
|
||||
@@ -65,10 +65,10 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
get() = pseudocodeVariableDataCollector.blockScopeVariableInfo
|
||||
|
||||
fun getDeclaredVariables(pseudocode: Pseudocode, includeInsideLocalDeclarations: Boolean): Set<VariableDescriptor> =
|
||||
getAllDeclaredVariables(pseudocode, includeInsideLocalDeclarations).allVars
|
||||
getAllDeclaredVariables(pseudocode, includeInsideLocalDeclarations).allVars
|
||||
|
||||
fun isVariableWithTrivialInitializer(variableDescriptor: VariableDescriptor) =
|
||||
variableDescriptor in rootVariables.valsWithTrivialInitializer
|
||||
variableDescriptor in rootVariables.valsWithTrivialInitializer
|
||||
|
||||
private fun getAllDeclaredVariables(pseudocode: Pseudocode, includeInsideLocalDeclarations: Boolean): VariablesForDeclaration {
|
||||
if (!includeInsideLocalDeclarations) {
|
||||
@@ -86,9 +86,9 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
}
|
||||
|
||||
private fun addVariablesFromPseudocode(
|
||||
pseudocode: Pseudocode,
|
||||
nonTrivialVariables: MutableSet<VariableDescriptor>,
|
||||
valsWithTrivialInitializer: MutableSet<VariableDescriptor>
|
||||
pseudocode: Pseudocode,
|
||||
nonTrivialVariables: MutableSet<VariableDescriptor>,
|
||||
valsWithTrivialInitializer: MutableSet<VariableDescriptor>
|
||||
) {
|
||||
getUpperLevelDeclaredVariables(pseudocode).let {
|
||||
nonTrivialVariables.addAll(it.nonTrivialVariables)
|
||||
@@ -107,14 +107,13 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
if (instruction is VariableDeclarationInstruction) {
|
||||
val variableDeclarationElement = instruction.variableDeclarationElement
|
||||
val descriptor =
|
||||
variableDescriptorForDeclaration(
|
||||
bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement)
|
||||
) ?: continue
|
||||
variableDescriptorForDeclaration(
|
||||
bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, variableDeclarationElement)
|
||||
) ?: continue
|
||||
|
||||
if (!containsDoWhile && isValWithTrivialInitializer(variableDeclarationElement, descriptor)) {
|
||||
valsWithTrivialInitializer.add(descriptor)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
nonTrivialVariables.add(descriptor)
|
||||
}
|
||||
}
|
||||
@@ -124,8 +123,8 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
}
|
||||
|
||||
private fun isValWithTrivialInitializer(variableDeclarationElement: KtDeclaration, descriptor: VariableDescriptor) =
|
||||
variableDeclarationElement is KtParameter || variableDeclarationElement is KtObjectDeclaration ||
|
||||
variableDeclarationElement.safeAs<KtVariableDeclaration>()?.isVariableWithTrivialInitializer(descriptor) == true
|
||||
variableDeclarationElement is KtParameter || variableDeclarationElement is KtObjectDeclaration ||
|
||||
variableDeclarationElement.safeAs<KtVariableDeclaration>()?.isVariableWithTrivialInitializer(descriptor) == true
|
||||
|
||||
private fun KtVariableDeclaration.isVariableWithTrivialInitializer(descriptor: VariableDescriptor): Boolean {
|
||||
if (descriptor.isPropertyWithoutBackingField()) return true
|
||||
@@ -148,18 +147,20 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
|
||||
if (rootVariables.nonTrivialVariables.isEmpty()) return resultForValsWithTrivialInitializer
|
||||
|
||||
return pseudocodeVariableDataCollector.collectData(TraversalOrder.FORWARD, InitControlFlowInfo()) {
|
||||
instruction: Instruction, incomingEdgesData: Collection<InitControlFlowInfo> ->
|
||||
return pseudocodeVariableDataCollector.collectData(
|
||||
TraversalOrder.FORWARD,
|
||||
InitControlFlowInfo()
|
||||
) { instruction: Instruction, incomingEdgesData: Collection<InitControlFlowInfo> ->
|
||||
|
||||
val enterInstructionData = mergeIncomingEdgesDataForInitializers(instruction, incomingEdgesData, blockScopeVariableInfo)
|
||||
val exitInstructionData = addVariableInitStateFromCurrentInstructionIfAny(
|
||||
instruction, enterInstructionData, blockScopeVariableInfo)
|
||||
instruction, enterInstructionData, blockScopeVariableInfo
|
||||
)
|
||||
Edges(enterInstructionData, exitInstructionData)
|
||||
}.mapValues {
|
||||
(instruction, edges) ->
|
||||
val trivialEdges = resultForValsWithTrivialInitializer[instruction]!!
|
||||
Edges(trivialEdges.incoming.replaceDelegate(edges.incoming), trivialEdges.outgoing.replaceDelegate(edges.outgoing))
|
||||
}
|
||||
}.mapValues { (instruction, edges) ->
|
||||
val trivialEdges = resultForValsWithTrivialInitializer[instruction]!!
|
||||
Edges(trivialEdges.incoming.replaceDelegate(edges.incoming), trivialEdges.outgoing.replaceDelegate(edges.outgoing))
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
when (instruction) {
|
||||
is VariableDeclarationInstruction ->
|
||||
extractValWithTrivialInitializer(instruction)?.let {
|
||||
variableDescriptor ->
|
||||
extractValWithTrivialInitializer(instruction)?.let { variableDescriptor ->
|
||||
declaredSet = declaredSet.add(variableDescriptor)
|
||||
}
|
||||
is WriteValueInstruction -> {
|
||||
@@ -193,12 +193,12 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
// WriteValueInstruction having KtDeclaration as an element means
|
||||
// it must be a write happened at the same time when
|
||||
// the variable (common variable/parameter/object) has been declared
|
||||
element is KtDeclaration
|
||||
element is KtDeclaration
|
||||
|
||||
private inner class ReadOnlyInitControlFlowInfoImpl(
|
||||
val declaredSet: ImmutableSet<VariableDescriptor>,
|
||||
val initSet: ImmutableSet<VariableDescriptor>,
|
||||
private val delegate: ReadOnlyInitControlFlowInfo?
|
||||
val declaredSet: ImmutableSet<VariableDescriptor>,
|
||||
val initSet: ImmutableSet<VariableDescriptor>,
|
||||
private val delegate: ReadOnlyInitControlFlowInfo?
|
||||
) : ReadOnlyInitControlFlowInfo {
|
||||
override fun getOrNull(variableDescriptor: VariableDescriptor): VariableControlFlowState? {
|
||||
if (variableDescriptor in declaredSet) {
|
||||
@@ -208,16 +208,15 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
}
|
||||
|
||||
override fun checkDefiniteInitializationInWhen(merge: ReadOnlyInitControlFlowInfo): Boolean =
|
||||
delegate?.checkDefiniteInitializationInWhen(merge) ?: false
|
||||
delegate?.checkDefiniteInitializationInWhen(merge) ?: false
|
||||
|
||||
fun replaceDelegate(newDelegate: ReadOnlyInitControlFlowInfo): ReadOnlyInitControlFlowInfo =
|
||||
ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, newDelegate)
|
||||
ReadOnlyInitControlFlowInfoImpl(declaredSet, initSet, newDelegate)
|
||||
|
||||
override fun asMap(): ImmutableMap<VariableDescriptor, VariableControlFlowState> {
|
||||
val initial = delegate?.asMap() ?: ImmutableHashMap.empty()
|
||||
|
||||
return declaredSet.fold(initial) {
|
||||
acc, variableDescriptor ->
|
||||
return declaredSet.fold(initial) { acc, variableDescriptor ->
|
||||
acc.put(variableDescriptor, getOrNull(variableDescriptor)!!)
|
||||
}
|
||||
}
|
||||
@@ -244,17 +243,16 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
}
|
||||
|
||||
private fun addVariableInitStateFromCurrentInstructionIfAny(
|
||||
instruction: Instruction,
|
||||
enterInstructionData: InitControlFlowInfo,
|
||||
blockScopeVariableInfo: BlockScopeVariableInfo): InitControlFlowInfo {
|
||||
instruction: Instruction,
|
||||
enterInstructionData: InitControlFlowInfo,
|
||||
blockScopeVariableInfo: BlockScopeVariableInfo
|
||||
): InitControlFlowInfo {
|
||||
if (instruction is MagicInstruction) {
|
||||
if (instruction.kind === MagicKind.EXHAUSTIVE_WHEN_ELSE) {
|
||||
return enterInstructionData.iterator().fold(enterInstructionData) {
|
||||
result, (key, value) ->
|
||||
return enterInstructionData.iterator().fold(enterInstructionData) { result, (key, value) ->
|
||||
if (!value.definitelyInitialized()) {
|
||||
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
|
||||
}
|
||||
val variable =
|
||||
PseudocodeUtil.extractVariableDescriptorIfAny(instruction, bindingContext)
|
||||
?.takeIf { it in rootVariables.nonTrivialVariables }
|
||||
?: return enterInstructionData
|
||||
PseudocodeUtil.extractVariableDescriptorIfAny(instruction, bindingContext)
|
||||
?.takeIf { it in rootVariables.nonTrivialVariables }
|
||||
?: return enterInstructionData
|
||||
var exitInstructionData = enterInstructionData
|
||||
if (instruction is WriteValueInstruction) {
|
||||
// if writing to already initialized object
|
||||
@@ -275,12 +273,11 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
val enterInitState = enterInstructionData.getOrNull(variable)
|
||||
val initializationAtThisElement = VariableControlFlowState.create(instruction.element is KtProperty, enterInitState)
|
||||
exitInstructionData = exitInstructionData.put(variable, initializationAtThisElement, enterInitState)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// instruction instanceof VariableDeclarationInstruction
|
||||
val enterInitState =
|
||||
enterInstructionData.getOrNull(variable)
|
||||
?: getDefaultValueForInitializers(variable, instruction, blockScopeVariableInfo)
|
||||
enterInstructionData.getOrNull(variable)
|
||||
?: getDefaultValueForInitializers(variable, instruction, blockScopeVariableInfo)
|
||||
|
||||
if (!enterInitState.mayBeInitialized() || !enterInitState.isDeclared) {
|
||||
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) {
|
||||
incomingEdgesData.single()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
incomingEdgesData.fold(UseControlFlowInfo()) { result, edgeData ->
|
||||
edgeData.iterator().fold(result) { subResult, (variableDescriptor, variableUseState) ->
|
||||
subResult.put(variableDescriptor, variableUseState.merge(subResult.getOrNull(variableDescriptor)))
|
||||
@@ -317,38 +316,35 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
}
|
||||
|
||||
val variableDescriptor =
|
||||
PseudocodeUtil.extractVariableDescriptorFromReference(instruction, bindingContext)
|
||||
?.takeIf { it in rootVariables.nonTrivialVariables }
|
||||
PseudocodeUtil.extractVariableDescriptorFromReference(instruction, bindingContext)
|
||||
?.takeIf { it in rootVariables.nonTrivialVariables }
|
||||
if (variableDescriptor == null || instruction !is ReadValueInstruction && instruction !is WriteValueInstruction) {
|
||||
Edges(enterResult, enterResult)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val exitResult =
|
||||
if (instruction is ReadValueInstruction) {
|
||||
enterResult.put(variableDescriptor, VariableUseState.READ)
|
||||
if (instruction is ReadValueInstruction) {
|
||||
enterResult.put(variableDescriptor, VariableUseState.READ)
|
||||
} else {
|
||||
var variableUseState: VariableUseState? = enterResult.getOrNull(variableDescriptor)
|
||||
if (variableUseState == null) {
|
||||
variableUseState = VariableUseState.UNUSED
|
||||
}
|
||||
else {
|
||||
var variableUseState: VariableUseState? = enterResult.getOrNull(variableDescriptor)
|
||||
if (variableUseState == null) {
|
||||
variableUseState = VariableUseState.UNUSED
|
||||
}
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
}.mapValues {
|
||||
(_, edges) ->
|
||||
}.mapValues { (_, edges) ->
|
||||
|
||||
Edges(
|
||||
Edges(
|
||||
edgesForTrivialVals.incoming.replaceDelegate(edges.incoming),
|
||||
edgesForTrivialVals.outgoing.replaceDelegate(edges.outgoing)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun computeUseInfoForTrivialVals(): Edges<ReadOnlyUseControlFlowInfoImpl> {
|
||||
@@ -373,8 +369,8 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
}
|
||||
|
||||
private inner class ReadOnlyUseControlFlowInfoImpl(
|
||||
val used: Set<VariableDescriptor>,
|
||||
val delegate: ReadOnlyUseControlFlowInfo?
|
||||
val used: Set<VariableDescriptor>,
|
||||
val delegate: ReadOnlyUseControlFlowInfo?
|
||||
) : ReadOnlyUseControlFlowInfo {
|
||||
override fun getOrNull(variableDescriptor: VariableDescriptor): VariableUseState? {
|
||||
if (variableDescriptor in used) return VariableUseState.READ
|
||||
@@ -382,13 +378,12 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
}
|
||||
|
||||
fun replaceDelegate(newDelegate: ReadOnlyUseControlFlowInfo): ReadOnlyUseControlFlowInfo =
|
||||
ReadOnlyUseControlFlowInfoImpl(used, newDelegate)
|
||||
ReadOnlyUseControlFlowInfoImpl(used, newDelegate)
|
||||
|
||||
override fun asMap(): ImmutableMap<VariableDescriptor, VariableUseState> {
|
||||
val initial = delegate?.asMap() ?: ImmutableHashMap.empty()
|
||||
|
||||
return used.fold(initial) {
|
||||
acc, variableDescriptor ->
|
||||
return used.fold(initial) { acc, variableDescriptor ->
|
||||
acc.put(variableDescriptor, getOrNull(variableDescriptor)!!)
|
||||
}
|
||||
}
|
||||
@@ -417,24 +412,24 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
|
||||
@JvmStatic
|
||||
fun getDefaultValueForInitializers(
|
||||
variable: VariableDescriptor,
|
||||
instruction: Instruction,
|
||||
blockScopeVariableInfo: BlockScopeVariableInfo
|
||||
variable: VariableDescriptor,
|
||||
instruction: Instruction,
|
||||
blockScopeVariableInfo: BlockScopeVariableInfo
|
||||
): VariableControlFlowState {
|
||||
//todo: think of replacing it with "MapWithDefaultValue"
|
||||
val declaredIn = blockScopeVariableInfo.declaredIn[variable]
|
||||
val declaredOutsideThisDeclaration =
|
||||
declaredIn == null //declared outside this pseudocode
|
||||
|| declaredIn.blockScopeForContainingDeclaration != instruction.blockScope.blockScopeForContainingDeclaration
|
||||
declaredIn == null //declared outside this pseudocode
|
||||
|| declaredIn.blockScopeForContainingDeclaration != instruction.blockScope.blockScopeForContainingDeclaration
|
||||
return VariableControlFlowState.create(isInitialized = declaredOutsideThisDeclaration)
|
||||
}
|
||||
|
||||
private val EMPTY_INIT_CONTROL_FLOW_INFO = InitControlFlowInfo()
|
||||
|
||||
private fun mergeIncomingEdgesDataForInitializers(
|
||||
instruction: Instruction,
|
||||
incomingEdgesData: Collection<InitControlFlowInfo>,
|
||||
blockScopeVariableInfo: BlockScopeVariableInfo
|
||||
instruction: Instruction,
|
||||
incomingEdgesData: Collection<InitControlFlowInfo>,
|
||||
blockScopeVariableInfo: BlockScopeVariableInfo
|
||||
): InitControlFlowInfo {
|
||||
if (incomingEdgesData.size == 1) return incomingEdgesData.single()
|
||||
if (incomingEdgesData.isEmpty()) return EMPTY_INIT_CONTROL_FLOW_INFO
|
||||
@@ -448,7 +443,7 @@ class PseudocodeVariablesData(val pseudocode: Pseudocode, private val bindingCon
|
||||
var isDeclared = true
|
||||
for (edgeData in incomingEdgesData) {
|
||||
val varControlFlowState = edgeData.getOrNull(variable)
|
||||
?: getDefaultValueForInitializers(variable, instruction, blockScopeVariableInfo)
|
||||
?: getDefaultValueForInitializers(variable, instruction, blockScopeVariableInfo)
|
||||
initState = initState?.merge(varControlFlowState.initState) ?: varControlFlowState.initState
|
||||
if (!varControlFlowState.isDeclared) {
|
||||
isDeclared = false
|
||||
|
||||
@@ -33,8 +33,8 @@ interface UnreachableCode {
|
||||
}
|
||||
|
||||
class UnreachableCodeImpl(
|
||||
private val reachableElements: Set<KtElement>,
|
||||
private val unreachableElements: Set<KtElement>
|
||||
private val reachableElements: Set<KtElement>,
|
||||
private val unreachableElements: Set<KtElement>
|
||||
) : UnreachableCode {
|
||||
|
||||
// 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> {
|
||||
return if (element.hasChildrenInSet(reachableElements)) {
|
||||
with (element.getLeavesOrReachableChildren().removeReachableElementsWithMeaninglessSiblings().mergeAdjacentTextRanges()) {
|
||||
with(element.getLeavesOrReachableChildren().removeReachableElementsWithMeaninglessSiblings().mergeAdjacentTextRanges()) {
|
||||
if (isNotEmpty()) this
|
||||
// Specific case like condition in when:
|
||||
// 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 {
|
||||
} else {
|
||||
listOf(element.textRange!!)
|
||||
}
|
||||
}
|
||||
|
||||
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> {
|
||||
val children = ArrayList<PsiElement>()
|
||||
acceptChildren(object : PsiElementVisitor() {
|
||||
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()) {
|
||||
children.add(element)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
element.acceptChildren(this)
|
||||
}
|
||||
}
|
||||
@@ -102,8 +101,7 @@ class UnreachableCodeImpl(
|
||||
|
||||
private fun List<PsiElement>.mergeAdjacentTextRanges(): List<TextRange> {
|
||||
val result = ArrayList<TextRange>()
|
||||
val lastRange = fold(null as TextRange?) {
|
||||
currentTextRange, element ->
|
||||
val lastRange = fold(null as TextRange?) { currentTextRange, element ->
|
||||
|
||||
val elementRange = element.textRange!!
|
||||
when {
|
||||
|
||||
@@ -54,10 +54,10 @@ val List<WhenMissingCase>.hasUnknown: Boolean
|
||||
|
||||
private interface WhenExhaustivenessChecker {
|
||||
fun getMissingCases(
|
||||
expression: KtWhenExpression,
|
||||
context: BindingContext,
|
||||
subjectDescriptor: ClassDescriptor?,
|
||||
nullable: Boolean
|
||||
expression: KtWhenExpression,
|
||||
context: BindingContext,
|
||||
subjectDescriptor: ClassDescriptor?,
|
||||
nullable: Boolean
|
||||
): List<WhenMissingCase>
|
||||
|
||||
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
|
||||
private object WhenOnNullableExhaustivenessChecker /* : WhenExhaustivenessChecker*/ {
|
||||
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> {
|
||||
for (entry in expression.entries) {
|
||||
@@ -99,10 +99,10 @@ class BooleanMissingCase(val b: Boolean) : WhenMissingCase() {
|
||||
|
||||
private object WhenOnBooleanExhaustivenessChecker : WhenExhaustivenessChecker {
|
||||
override fun getMissingCases(
|
||||
expression: KtWhenExpression,
|
||||
context: BindingContext,
|
||||
subjectDescriptor: ClassDescriptor?,
|
||||
nullable: Boolean
|
||||
expression: KtWhenExpression,
|
||||
context: BindingContext,
|
||||
subjectDescriptor: ClassDescriptor?,
|
||||
nullable: Boolean
|
||||
): List<WhenMissingCase> {
|
||||
// It's assumed (and not checked) that expression is of the boolean type
|
||||
var containsFalse = false
|
||||
@@ -117,8 +117,8 @@ private object WhenOnBooleanExhaustivenessChecker : WhenExhaustivenessChecker {
|
||||
}
|
||||
}
|
||||
return (if (!containsTrue) listOf(BooleanMissingCase(true)) else listOf()) +
|
||||
(if (!containsFalse) listOf(BooleanMissingCase(false)) else listOf()) +
|
||||
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
|
||||
(if (!containsFalse) listOf(BooleanMissingCase(false)) else listOf()) +
|
||||
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
|
||||
}
|
||||
|
||||
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 classFqName get() = DescriptorUtils.getFqNameFromTopLevelClass(descriptor)
|
||||
@@ -138,11 +138,11 @@ class ClassMissingCase(val descriptor: ClassDescriptor): WhenMissingCase() {
|
||||
|
||||
internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChecker {
|
||||
private fun getReference(expression: KtExpression?): KtSimpleNameExpression? =
|
||||
when (expression) {
|
||||
is KtSimpleNameExpression -> expression
|
||||
is KtQualifiedExpression -> getReference(expression.selectorExpression)
|
||||
else -> null
|
||||
}
|
||||
when (expression) {
|
||||
is KtSimpleNameExpression -> expression
|
||||
is KtQualifiedExpression -> getReference(expression.selectorExpression)
|
||||
else -> null
|
||||
}
|
||||
|
||||
protected val ClassDescriptor.deepSealedSubclasses: List<ClassDescriptor>
|
||||
get() = this.sealedSubclasses.flatMap {
|
||||
@@ -154,9 +154,9 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
|
||||
get() = (this as? KtWhenConditionIsPattern)?.isNegated ?: false
|
||||
|
||||
private fun KtWhenCondition.isRelevant(checkedDescriptor: ClassDescriptor) =
|
||||
this !is KtWhenConditionWithExpression ||
|
||||
DescriptorUtils.isObject(checkedDescriptor) ||
|
||||
DescriptorUtils.isEnumEntry(checkedDescriptor)
|
||||
this !is KtWhenConditionWithExpression ||
|
||||
DescriptorUtils.isObject(checkedDescriptor) ||
|
||||
DescriptorUtils.isEnumEntry(checkedDescriptor)
|
||||
|
||||
private fun KtWhenCondition.getCheckedDescriptor(context: BindingContext): ClassDescriptor? {
|
||||
return when (this) {
|
||||
@@ -175,9 +175,9 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
|
||||
}
|
||||
|
||||
protected fun getMissingClassCases(
|
||||
whenExpression: KtWhenExpression,
|
||||
subclasses: Set<ClassDescriptor>,
|
||||
context: BindingContext
|
||||
whenExpression: KtWhenExpression,
|
||||
subclasses: Set<ClassDescriptor>,
|
||||
context: BindingContext
|
||||
): List<WhenMissingCase> {
|
||||
// when on empty enum / sealed is considered non-exhaustive, see test whenOnEmptySealed
|
||||
if (subclasses.isEmpty()) return listOf(UnknownMissingCase)
|
||||
@@ -188,8 +188,8 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
|
||||
val negated = condition.negated
|
||||
val checkedDescriptor = condition.getCheckedDescriptor(context) ?: continue
|
||||
val checkedDescriptorSubclasses =
|
||||
if (checkedDescriptor.modality == Modality.SEALED) checkedDescriptor.deepSealedSubclasses
|
||||
else listOf(checkedDescriptor)
|
||||
if (checkedDescriptor.modality == Modality.SEALED) checkedDescriptor.deepSealedSubclasses
|
||||
else listOf(checkedDescriptor)
|
||||
|
||||
// Checks are important only for nested subclasses of the sealed class
|
||||
// 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()
|
||||
checkedDescriptors.addAll(subclasses)
|
||||
checkedDescriptors.removeAll(checkedDescriptorSubclasses)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
checkedDescriptors.addAll(checkedDescriptorSubclasses)
|
||||
}
|
||||
}
|
||||
@@ -213,19 +212,19 @@ internal abstract class WhenOnClassExhaustivenessChecker : WhenExhaustivenessChe
|
||||
|
||||
private object WhenOnEnumExhaustivenessChecker : WhenOnClassExhaustivenessChecker() {
|
||||
override fun getMissingCases(
|
||||
expression: KtWhenExpression,
|
||||
context: BindingContext,
|
||||
subjectDescriptor: ClassDescriptor?,
|
||||
nullable: Boolean
|
||||
expression: KtWhenExpression,
|
||||
context: BindingContext,
|
||||
subjectDescriptor: ClassDescriptor?,
|
||||
nullable: Boolean
|
||||
): List<WhenMissingCase> {
|
||||
assert(isEnumClass(subjectDescriptor)) { "isWhenOnEnumExhaustive should be called with an enum class descriptor" }
|
||||
val entryDescriptors =
|
||||
DescriptorUtils.getAllDescriptors(subjectDescriptor!!.unsubstitutedInnerClassesScope)
|
||||
.filter(::isEnumEntry)
|
||||
.filterIsInstance<ClassDescriptor>()
|
||||
.toSet()
|
||||
DescriptorUtils.getAllDescriptors(subjectDescriptor!!.unsubstitutedInnerClassesScope)
|
||||
.filter(::isEnumEntry)
|
||||
.filterIsInstance<ClassDescriptor>()
|
||||
.toSet()
|
||||
return getMissingClassCases(expression, entryDescriptors, context) +
|
||||
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
|
||||
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
|
||||
}
|
||||
|
||||
override fun isApplicable(subjectType: KotlinType): Boolean {
|
||||
@@ -236,10 +235,10 @@ private object WhenOnEnumExhaustivenessChecker : WhenOnClassExhaustivenessChecke
|
||||
internal object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChecker() {
|
||||
|
||||
override fun getMissingCases(
|
||||
expression: KtWhenExpression,
|
||||
context: BindingContext,
|
||||
subjectDescriptor: ClassDescriptor?,
|
||||
nullable: Boolean
|
||||
expression: KtWhenExpression,
|
||||
context: BindingContext,
|
||||
subjectDescriptor: ClassDescriptor?,
|
||||
nullable: Boolean
|
||||
): List<WhenMissingCase> {
|
||||
assert(DescriptorUtils.isSealedClass(subjectDescriptor)) {
|
||||
"isWhenOnSealedClassExhaustive should be called with a sealed class descriptor: $subjectDescriptor"
|
||||
@@ -247,7 +246,7 @@ internal object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChe
|
||||
|
||||
val allSubclasses = subjectDescriptor!!.deepSealedSubclasses
|
||||
return getMissingClassCases(expression, allSubclasses.toSet(), context) +
|
||||
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
|
||||
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, nullable)
|
||||
}
|
||||
|
||||
override fun isApplicable(subjectType: KotlinType): Boolean {
|
||||
@@ -258,13 +257,15 @@ internal object WhenOnSealedExhaustivenessChecker : WhenOnClassExhaustivenessChe
|
||||
|
||||
object WhenChecker {
|
||||
|
||||
private val exhaustivenessCheckers = listOf(WhenOnBooleanExhaustivenessChecker,
|
||||
WhenOnEnumExhaustivenessChecker,
|
||||
WhenOnSealedExhaustivenessChecker)
|
||||
private val exhaustivenessCheckers = listOf(
|
||||
WhenOnBooleanExhaustivenessChecker,
|
||||
WhenOnEnumExhaustivenessChecker,
|
||||
WhenOnSealedExhaustivenessChecker
|
||||
)
|
||||
|
||||
@JvmStatic
|
||||
fun isWhenByEnum(expression: KtWhenExpression, context: BindingContext) =
|
||||
getClassDescriptorOfTypeIfEnum(whenSubjectType(expression, context)) != null
|
||||
getClassDescriptorOfTypeIfEnum(whenSubjectType(expression, context)) != null
|
||||
|
||||
@JvmStatic
|
||||
fun getClassDescriptorOfTypeIfEnum(type: KotlinType?): ClassDescriptor? {
|
||||
@@ -276,26 +277,26 @@ object WhenChecker {
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getClassDescriptorOfTypeIfSealed(type: KotlinType?): ClassDescriptor?
|
||||
= type?.let { TypeUtils.getClassDescriptor(it) }?.takeIf { DescriptorUtils.isSealedClass(it) }
|
||||
fun getClassDescriptorOfTypeIfSealed(type: KotlinType?): ClassDescriptor? =
|
||||
type?.let { TypeUtils.getClassDescriptor(it) }?.takeIf { DescriptorUtils.isSealedClass(it) }
|
||||
|
||||
|
||||
@JvmStatic
|
||||
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
|
||||
fun getEnumMissingCases(
|
||||
expression: KtWhenExpression,
|
||||
context: BindingContext,
|
||||
enumClassDescriptor: ClassDescriptor
|
||||
expression: KtWhenExpression,
|
||||
context: BindingContext,
|
||||
enumClassDescriptor: ClassDescriptor
|
||||
) = WhenOnEnumExhaustivenessChecker.getMissingCases(expression, context, enumClassDescriptor, false)
|
||||
|
||||
@JvmStatic
|
||||
fun getSealedMissingCases(
|
||||
expression: KtWhenExpression,
|
||||
context: BindingContext,
|
||||
sealedClassDescriptor: ClassDescriptor
|
||||
expression: KtWhenExpression,
|
||||
context: BindingContext,
|
||||
sealedClassDescriptor: ClassDescriptor
|
||||
) = WhenOnSealedExhaustivenessChecker.getMissingCases(expression, context, sealedClassDescriptor, false)
|
||||
|
||||
fun getMissingCases(expression: KtWhenExpression, context: BindingContext): List<WhenMissingCase> {
|
||||
@@ -308,15 +309,15 @@ object WhenChecker {
|
||||
|
||||
@JvmStatic
|
||||
fun isWhenExhaustive(expression: KtWhenExpression, trace: BindingTrace) =
|
||||
if (getMissingCases(expression, trace.bindingContext).isEmpty()) {
|
||||
trace.record(BindingContext.EXHAUSTIVE_WHEN, expression)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
if (getMissingCases(expression, trace.bindingContext).isEmpty()) {
|
||||
trace.record(BindingContext.EXHAUSTIVE_WHEN, expression)
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
fun containsNullCase(expression: KtWhenExpression, context: BindingContext) =
|
||||
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, true).isEmpty()
|
||||
WhenOnNullableExhaustivenessChecker.getMissingCases(expression, context, true).isEmpty()
|
||||
|
||||
fun checkDuplicatedLabels(expression: KtWhenExpression, trace: BindingTrace) {
|
||||
if (expression.subjectExpression == null) return
|
||||
@@ -331,11 +332,11 @@ object WhenChecker {
|
||||
is KtWhenConditionWithExpression -> {
|
||||
val constantExpression = condition.expression ?: continue@conditions
|
||||
val constant = ConstantExpressionEvaluator.getConstant(
|
||||
constantExpression, trace.bindingContext) ?: continue@conditions
|
||||
constantExpression, trace.bindingContext
|
||||
) ?: continue@conditions
|
||||
if (checkedConstants.contains(constant)) {
|
||||
trace.report(Errors.DUPLICATE_LABEL_IN_WHEN.on(constantExpression))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
checkedConstants.add(constant)
|
||||
}
|
||||
|
||||
@@ -346,12 +347,12 @@ object WhenChecker {
|
||||
val typeWithIsNegation = type to condition.isNegated
|
||||
if (checkedTypes.contains(typeWithIsNegation)) {
|
||||
trace.report(Errors.DUPLICATE_LABEL_IN_WHEN.on(typeReference))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
checkedTypes.add(typeWithIsNegation)
|
||||
}
|
||||
}
|
||||
else -> {}
|
||||
else -> {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+66
-60
@@ -58,8 +58,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
||||
val worker = builders.pop()
|
||||
builder = if (!builders.isEmpty()) {
|
||||
builders.peek()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
null
|
||||
}
|
||||
return worker
|
||||
@@ -70,8 +69,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
||||
val shouldInlnie = invocationKind != null
|
||||
if (builder != null && subroutine is KtFunctionLiteral) {
|
||||
pushBuilder(subroutine, builder.returnSubroutine, shouldInlnie)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
pushBuilder(subroutine, subroutine, shouldInlnie)
|
||||
}
|
||||
delegateBuilder.enterBlockScope(subroutine)
|
||||
@@ -86,8 +84,7 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
||||
val builder = builders.peek()
|
||||
if (invocationKind == null) {
|
||||
builder.declareFunction(subroutine, worker.pseudocode)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
builder.declareInlinedFunction(subroutine, worker.pseudocode, invocationKind)
|
||||
}
|
||||
}
|
||||
@@ -95,9 +92,9 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
||||
}
|
||||
|
||||
private inner class ControlFlowInstructionsGeneratorWorker(
|
||||
scopingElement: KtElement,
|
||||
override val returnSubroutine: KtElement,
|
||||
shouldInline: Boolean
|
||||
scopingElement: KtElement,
|
||||
override val returnSubroutine: KtElement,
|
||||
shouldInline: Boolean
|
||||
) : ControlFlowBuilder {
|
||||
|
||||
val pseudocode: PseudocodeImpl = PseudocodeImpl(scopingElement, shouldInline)
|
||||
@@ -128,12 +125,13 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
||||
}
|
||||
|
||||
val info = LoopInfo(
|
||||
expression,
|
||||
createUnboundLabel("loop entry point"),
|
||||
createUnboundLabel("loop exit point"),
|
||||
createUnboundLabel("body entry point"),
|
||||
createUnboundLabel("body exit point"),
|
||||
createUnboundLabel("condition entry point"))
|
||||
expression,
|
||||
createUnboundLabel("loop entry point"),
|
||||
createUnboundLabel("loop exit point"),
|
||||
createUnboundLabel("body entry point"),
|
||||
createUnboundLabel("body exit point"),
|
||||
createUnboundLabel("condition entry point")
|
||||
)
|
||||
bindLabel(info.entryPoint)
|
||||
elementToLoopInfo.put(expression, info)
|
||||
return info
|
||||
@@ -158,9 +156,10 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
||||
|
||||
override fun enterSubroutine(subroutine: KtElement, invocationKind: InvocationKind?) {
|
||||
val blockInfo = SubroutineInfo(
|
||||
subroutine,
|
||||
/* entry point */ createUnboundLabel(),
|
||||
/* exit point */ createUnboundLabel())
|
||||
subroutine,
|
||||
/* entry point */ createUnboundLabel(),
|
||||
/* exit point */ createUnboundLabel()
|
||||
)
|
||||
elementToSubroutineInfo.put(subroutine, blockInfo)
|
||||
allBlocks.push(blockInfo)
|
||||
bindLabel(blockInfo.entryPoint)
|
||||
@@ -173,10 +172,11 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
||||
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
|
||||
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)
|
||||
elementToSubroutineInfo[labelElement]?.exitPoint
|
||||
override fun getSubroutineExitPoint(labelElement: KtElement): Label? =
|
||||
// It's quite possible to have null here, e.g. for non-local returns (see KT-10823)
|
||||
elementToSubroutineInfo[labelElement]?.exitPoint
|
||||
|
||||
private val currentScope: BlockScope
|
||||
get() = blockScopes.peek()
|
||||
@@ -191,8 +191,8 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
||||
val currentScope = currentScope
|
||||
assert(currentScope.block === block) {
|
||||
"Exit from not the current block scope.\n" +
|
||||
"Current scope is for a block: " + currentScope.block.text + ".\n" +
|
||||
"Exit from the scope for: " + block.text
|
||||
"Current scope is for a block: " + currentScope.block.text + ".\n" +
|
||||
"Exit from the scope for: " + block.text
|
||||
}
|
||||
blockScopes.pop()
|
||||
}
|
||||
@@ -252,11 +252,12 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
||||
}
|
||||
|
||||
override fun write(
|
||||
assignment: KtElement,
|
||||
lValue: KtElement,
|
||||
rValue: PseudoValue,
|
||||
target: AccessTarget,
|
||||
receiverValues: Map<PseudoValue, ReceiverValue>) {
|
||||
assignment: KtElement,
|
||||
lValue: KtElement,
|
||||
rValue: PseudoValue,
|
||||
target: AccessTarget,
|
||||
receiverValues: Map<PseudoValue, ReceiverValue>
|
||||
) {
|
||||
add(WriteValueInstruction(assignment, currentScope, target, receiverValues, lValue, rValue))
|
||||
}
|
||||
|
||||
@@ -342,22 +343,24 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
||||
override fun createAnonymousObject(expression: KtObjectLiteralExpression) = read(expression)
|
||||
|
||||
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(
|
||||
expression: KtStringTemplateExpression,
|
||||
inputValues: List<PseudoValue>
|
||||
expression: KtStringTemplateExpression,
|
||||
inputValues: List<PseudoValue>
|
||||
): InstructionWithValue =
|
||||
if (inputValues.isEmpty()) read(expression)
|
||||
else magic(expression, expression, inputValues, MagicKind.STRING_TEMPLATE)
|
||||
if (inputValues.isEmpty()) read(expression)
|
||||
else magic(expression, expression, inputValues, MagicKind.STRING_TEMPLATE)
|
||||
|
||||
override fun magic(
|
||||
instructionElement: KtElement,
|
||||
valueElement: KtElement?,
|
||||
inputValues: List<PseudoValue>,
|
||||
kind: MagicKind): MagicInstruction {
|
||||
instructionElement: KtElement,
|
||||
valueElement: KtElement?,
|
||||
inputValues: List<PseudoValue>,
|
||||
kind: MagicKind
|
||||
): MagicInstruction {
|
||||
val instruction = MagicInstruction(
|
||||
instructionElement, valueElement, currentScope, inputValues, kind, valueFactory)
|
||||
instructionElement, valueElement, currentScope, inputValues, kind, valueFactory
|
||||
)
|
||||
add(instruction)
|
||||
return instruction
|
||||
}
|
||||
@@ -369,32 +372,35 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
||||
}
|
||||
|
||||
override fun readVariable(
|
||||
expression: KtExpression,
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
receiverValues: Map<PseudoValue, ReceiverValue>
|
||||
expression: KtExpression,
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
receiverValues: Map<PseudoValue, ReceiverValue>
|
||||
) = read(expression, resolvedCall, receiverValues)
|
||||
|
||||
override fun call(
|
||||
valueElement: KtElement,
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
receiverValues: Map<PseudoValue, ReceiverValue>,
|
||||
arguments: Map<PseudoValue, ValueParameterDescriptor>): CallInstruction {
|
||||
valueElement: KtElement,
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
receiverValues: Map<PseudoValue, ReceiverValue>,
|
||||
arguments: Map<PseudoValue, ValueParameterDescriptor>
|
||||
): CallInstruction {
|
||||
val returnType = resolvedCall.resultingDescriptor.returnType
|
||||
val instruction = CallInstruction(
|
||||
valueElement,
|
||||
currentScope,
|
||||
resolvedCall,
|
||||
receiverValues,
|
||||
arguments,
|
||||
if (returnType != null && KotlinBuiltIns.isNothing(returnType)) null else valueFactory)
|
||||
valueElement,
|
||||
currentScope,
|
||||
resolvedCall,
|
||||
receiverValues,
|
||||
arguments,
|
||||
if (returnType != null && KotlinBuiltIns.isNothing(returnType)) null else valueFactory
|
||||
)
|
||||
add(instruction)
|
||||
return instruction
|
||||
}
|
||||
|
||||
override fun predefinedOperation(
|
||||
expression: KtExpression,
|
||||
operation: ControlFlowBuilder.PredefinedOperation,
|
||||
inputValues: List<PseudoValue>): OperationInstruction = magic(expression, expression, inputValues, getMagicKind(operation))
|
||||
expression: KtExpression,
|
||||
operation: ControlFlowBuilder.PredefinedOperation,
|
||||
inputValues: List<PseudoValue>
|
||||
): OperationInstruction = magic(expression, expression, inputValues, getMagicKind(operation))
|
||||
|
||||
private fun getMagicKind(operation: ControlFlowBuilder.PredefinedOperation) = when (operation) {
|
||||
ControlFlowBuilder.PredefinedOperation.AND -> MagicKind.AND
|
||||
@@ -403,17 +409,17 @@ class ControlFlowInstructionsGenerator : ControlFlowBuilderAdapter() {
|
||||
}
|
||||
|
||||
override fun read(
|
||||
element: KtElement,
|
||||
target: AccessTarget,
|
||||
receiverValues: Map<PseudoValue, ReceiverValue>
|
||||
element: KtElement,
|
||||
target: AccessTarget,
|
||||
receiverValues: Map<PseudoValue, ReceiverValue>
|
||||
) = ReadValueInstruction(element, currentScope, target, receiverValues, valueFactory).apply {
|
||||
add(this)
|
||||
}
|
||||
|
||||
private fun read(
|
||||
expression: KtExpression,
|
||||
resolvedCall: ResolvedCall<*>? = null,
|
||||
receiverValues: Map<PseudoValue, ReceiverValue> = emptyMap()
|
||||
expression: KtExpression,
|
||||
resolvedCall: ResolvedCall<*>? = null,
|
||||
receiverValues: Map<PseudoValue, ReceiverValue> = emptyMap()
|
||||
) = 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.checker.KotlinTypeChecker
|
||||
|
||||
interface TypePredicate: (KotlinType) -> Boolean {
|
||||
interface TypePredicate : (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 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 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 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 toString(): String = "OR{${typeSets.joinToString(", ")}}"
|
||||
@@ -58,18 +58,18 @@ object AllTypes : TypePredicate {
|
||||
|
||||
// todo: simplify computed type predicate when possible
|
||||
fun and(predicates: Collection<TypePredicate>): TypePredicate =
|
||||
when (predicates.size) {
|
||||
0 -> AllTypes
|
||||
1 -> predicates.first()
|
||||
else -> ForAllTypes(predicates.toList())
|
||||
}
|
||||
when (predicates.size) {
|
||||
0 -> AllTypes
|
||||
1 -> predicates.first()
|
||||
else -> ForAllTypes(predicates.toList())
|
||||
}
|
||||
|
||||
fun or(predicates: Collection<TypePredicate>): TypePredicate? =
|
||||
when (predicates.size) {
|
||||
0 -> null
|
||||
1 -> predicates.first()
|
||||
else -> ForSomeType(predicates.toList())
|
||||
}
|
||||
when (predicates.size) {
|
||||
0 -> null
|
||||
1 -> predicates.first()
|
||||
else -> ForSomeType(predicates.toList())
|
||||
}
|
||||
|
||||
fun KotlinType.getSubtypesPredicate(): TypePredicate = when {
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
abstract class AbstractJumpInstruction(
|
||||
element: KtElement,
|
||||
val targetLabel: Label,
|
||||
blockScope: BlockScope
|
||||
element: KtElement,
|
||||
val targetLabel: Label,
|
||||
blockScope: BlockScope
|
||||
) : KtElementInstructionImpl(element, blockScope), JumpInstruction {
|
||||
var resolvedTarget: Instruction? = null
|
||||
set(value) {
|
||||
|
||||
+6
-6
@@ -27,17 +27,17 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionVisitorWithRe
|
||||
import org.jetbrains.kotlin.cfg.pseudocode.instructions.InstructionImpl
|
||||
|
||||
class NondeterministicJumpInstruction(
|
||||
element: KtElement,
|
||||
targetLabels: List<Label>,
|
||||
blockScope: BlockScope,
|
||||
private val inputValue: PseudoValue?
|
||||
element: KtElement,
|
||||
targetLabels: List<Label>,
|
||||
blockScope: BlockScope,
|
||||
private val inputValue: PseudoValue?
|
||||
) : KtElementInstructionImpl(element, blockScope), JumpInstruction {
|
||||
private var _next: Instruction? = null
|
||||
private val _resolvedTargets: MutableMap<Label, Instruction> = linkedMapOf()
|
||||
|
||||
val targetLabels: List<Label> = ArrayList(targetLabels)
|
||||
private val resolvedTargets: Map<Label, Instruction>
|
||||
get() = _resolvedTargets
|
||||
get() = _resolvedTargets
|
||||
|
||||
fun setResolvedTarget(label: Label, resolvedTarget: Instruction) {
|
||||
_resolvedTargets[label] = outgoingEdgeTo(resolvedTarget)!!
|
||||
@@ -76,5 +76,5 @@ class NondeterministicJumpInstruction(
|
||||
fun copy(newTargetLabels: MutableList<Label>): Instruction = updateCopyInfo(createCopy(newTargetLabels))
|
||||
|
||||
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 -> {
|
||||
val rootCallableDescriptors = callableDescriptor.findTopMostOverriddenDescriptors()
|
||||
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(
|
||||
value: PseudoValue,
|
||||
bindingContext: BindingContext,
|
||||
builtIns: KotlinBuiltIns
|
||||
value: PseudoValue,
|
||||
bindingContext: BindingContext,
|
||||
builtIns: KotlinBuiltIns
|
||||
): TypePredicate {
|
||||
val pseudocode = value.createdAt?.owner ?: return AllTypes
|
||||
val typePredicates = LinkedHashSet<TypePredicate?>()
|
||||
@@ -92,8 +93,8 @@ fun getExpectedTypePredicate(
|
||||
val callee = call.calleeExpression ?: return null
|
||||
|
||||
val candidates = callee.getReferenceTargets(bindingContext)
|
||||
.filterIsInstance<FunctionDescriptor>()
|
||||
.sortedBy { DescriptorRenderer.FQ_NAMES_IN_TYPES.render(it) }
|
||||
.filterIsInstance<FunctionDescriptor>()
|
||||
.sortedBy { DescriptorRenderer.FQ_NAMES_IN_TYPES.render(it) }
|
||||
if (candidates.isEmpty()) return null
|
||||
|
||||
val explicitReceiver = call.explicitReceiver
|
||||
@@ -103,17 +104,17 @@ fun getExpectedTypePredicate(
|
||||
|
||||
for (candidate in candidates) {
|
||||
val resolutionCandidate = ResolutionCandidate.create(
|
||||
call,
|
||||
candidate,
|
||||
null,
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
||||
null
|
||||
call,
|
||||
candidate,
|
||||
null,
|
||||
ExplicitReceiverKind.NO_EXPLICIT_RECEIVER,
|
||||
null
|
||||
)
|
||||
val candidateCall = ResolvedCallImpl.create(
|
||||
resolutionCandidate,
|
||||
DelegatingBindingTrace(bindingContext, "Compute type predicates for unresolved call arguments"),
|
||||
TracingStrategy.EMPTY,
|
||||
DataFlowInfoForArgumentsImpl(DataFlowInfo.EMPTY, call)
|
||||
resolutionCandidate,
|
||||
DelegatingBindingTrace(bindingContext, "Compute type predicates for unresolved call arguments"),
|
||||
TracingStrategy.EMPTY,
|
||||
DataFlowInfoForArgumentsImpl(DataFlowInfo.EMPTY, call)
|
||||
)
|
||||
val status = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(call, TracingStrategy.EMPTY, candidateCall)
|
||||
if (!status.isSuccess) continue
|
||||
@@ -143,7 +144,7 @@ fun getExpectedTypePredicate(
|
||||
when (it) {
|
||||
is ReturnValueInstruction -> {
|
||||
val returnElement = it.element
|
||||
val functionDescriptor = when(returnElement) {
|
||||
val functionDescriptor = when (returnElement) {
|
||||
is KtReturnExpression -> returnElement.getTargetFunctionDescriptor(bindingContext)
|
||||
else -> bindingContext[DECLARATION_TO_DESCRIPTOR, pseudocode.correspondingElement]
|
||||
}
|
||||
@@ -164,8 +165,7 @@ fun getExpectedTypePredicate(
|
||||
val receiverValue = it.receiverValues[value]
|
||||
if (receiverValue != null) {
|
||||
typePredicates.add(getReceiverTypePredicate((accessTarget as AccessTarget.Call).resolvedCall, receiverValue))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val expectedType = when (accessTarget) {
|
||||
is AccessTarget.Call ->
|
||||
(accessTarget.resolvedCall.resultingDescriptor as? VariableDescriptor)?.type
|
||||
@@ -182,8 +182,7 @@ fun getExpectedTypePredicate(
|
||||
val receiverValue = it.receiverValues[value]
|
||||
if (receiverValue != null) {
|
||||
typePredicates.add(getReceiverTypePredicate(it.resolvedCall, receiverValue))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
it.arguments[value]?.let { parameter ->
|
||||
val expectedType = when (it.resolvedCall.valueArguments[parameter]) {
|
||||
is VarargValueArgument ->
|
||||
@@ -281,8 +280,8 @@ fun Pseudocode.getElementValuesRecursively(element: KtElement): List<PseudoValue
|
||||
}
|
||||
|
||||
val KtElement.containingDeclarationForPseudocode: KtDeclaration?
|
||||
get() = PsiTreeUtil.getParentOfType(this, KtDeclarationWithBody::class.java, KtClassOrObject::class.java, KtScript::class.java)
|
||||
?: getNonStrictParentOfType<KtProperty>()
|
||||
get() = PsiTreeUtil.getParentOfType(this, KtDeclarationWithBody::class.java, KtClassOrObject::class.java, KtScript::class.java)
|
||||
?: getNonStrictParentOfType<KtProperty>()
|
||||
|
||||
fun KtDeclaration.getContainingPseudocode(context: BindingContext): Pseudocode? {
|
||||
val enclosingPseudocodeDeclaration = (this as? KtFunctionLiteral)?.let {
|
||||
|
||||
+9
-9
@@ -44,9 +44,9 @@ class ContractParsingServices(val languageVersionSettings: LanguageVersionSettin
|
||||
val contractProvider = ownerDescriptor.getUserData(ContractProviderKey) ?: return
|
||||
|
||||
val isFeatureTurnedOn = languageVersionSettings.supportsFeature(LanguageFeature.CallsInPlaceEffect) ||
|
||||
languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect) ||
|
||||
// This condition is here for technical purposes of compiling 1.2-runtime with contracts
|
||||
languageVersionSettings.getFlag(AnalysisFlag.Flags.allowKotlinPackage)
|
||||
languageVersionSettings.supportsFeature(LanguageFeature.ReturnsEffect) ||
|
||||
// This condition is here for technical purposes of compiling 1.2-runtime with contracts
|
||||
languageVersionSettings.getFlag(AnalysisFlag.Flags.allowKotlinPackage)
|
||||
|
||||
val contractDescriptor = when {
|
||||
!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? =
|
||||
PsiContractParserDispatcher(trace, this).parseContract(expression, ownerDescriptor)
|
||||
PsiContractParserDispatcher(trace, this).parseContract(expression, ownerDescriptor)
|
||||
|
||||
internal fun isContractDescriptionCall(expression: KtExpression, context: BindingContext): Boolean =
|
||||
isContractDescriptionCallFastCheck(expression) && isContractDescriptionCallPreciseCheck(expression, context)
|
||||
isContractDescriptionCallFastCheck(expression) && isContractDescriptionCallPreciseCheck(expression, context)
|
||||
|
||||
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 =
|
||||
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 =
|
||||
expression is KtCallExpression && expression.calleeExpression?.text == "contract"
|
||||
expression is KtCallExpression && expression.calleeExpression?.text == "contract"
|
||||
|
||||
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.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? {
|
||||
val variable = dispatcher.parseVariable(expression.leftHandSide) ?: 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)
|
||||
val arg = expression.baseExpression?.accept(this, data) ?: return null
|
||||
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)
|
||||
}
|
||||
|
||||
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?
|
||||
}
|
||||
|
||||
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> {
|
||||
when (element) {
|
||||
is KtObjectLiteralExpression -> {
|
||||
@@ -61,8 +62,8 @@ object PositioningStrategies {
|
||||
}
|
||||
is KtObjectDeclaration -> {
|
||||
return markRange(
|
||||
element.getObjectKeyword()!!,
|
||||
element.nameIdentifier ?: element.getObjectKeyword()!!
|
||||
element.getObjectKeyword()!!,
|
||||
element.nameIdentifier ?: element.getObjectKeyword()!!
|
||||
)
|
||||
}
|
||||
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> {
|
||||
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> {
|
||||
val nameIdentifier = element.nameIdentifier
|
||||
return when {
|
||||
@@ -112,11 +115,11 @@ object PositioningStrategies {
|
||||
get() {
|
||||
val map = when (factory) {
|
||||
NO_ACTUAL_FOR_EXPECT ->
|
||||
NO_ACTUAL_FOR_EXPECT.cast(this).c
|
||||
NO_ACTUAL_FOR_EXPECT.cast(this).c
|
||||
ACTUAL_WITHOUT_EXPECT ->
|
||||
ACTUAL_WITHOUT_EXPECT.cast(this).b
|
||||
ACTUAL_WITHOUT_EXPECT.cast(this).b
|
||||
else ->
|
||||
return null
|
||||
return null
|
||||
}
|
||||
return map.keys.firstOrNull()
|
||||
}
|
||||
@@ -125,7 +128,8 @@ object PositioningStrategies {
|
||||
|
||||
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> {
|
||||
val element = diagnostic.psiElement
|
||||
val callableDeclaration = element as? KtCallableDeclaration
|
||||
@@ -134,15 +138,14 @@ object PositioningStrategies {
|
||||
null, Unknown, is ClassScopes, EnumEntries -> null
|
||||
ClassKind -> {
|
||||
val startElement =
|
||||
element.modifierList?.getModifier(KtTokens.ENUM_KEYWORD)
|
||||
?: element.modifierList?.getModifier(KtTokens.ANNOTATION_KEYWORD)
|
||||
element.modifierList?.getModifier(KtTokens.ENUM_KEYWORD)
|
||||
?: element.modifierList?.getModifier(KtTokens.ANNOTATION_KEYWORD)
|
||||
val endElement =
|
||||
element.node.findChildByType(classKindTokens)?.psi
|
||||
?: element.nameIdentifier
|
||||
element.node.findChildByType(classKindTokens)?.psi
|
||||
?: element.nameIdentifier
|
||||
if (startElement != null && endElement != null) {
|
||||
return markRange(startElement, endElement)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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> {
|
||||
val nameIdentifier = element.nameIdentifier
|
||||
if (nameIdentifier != null) {
|
||||
if (element is KtClassOrObject) {
|
||||
val startElement =
|
||||
element.getModifierList()?.getModifier(KtTokens.ENUM_KEYWORD)
|
||||
?: element.node.findChildByType(TokenSet.create(KtTokens.CLASS_KEYWORD, KtTokens.OBJECT_KEYWORD))?.psi
|
||||
?: element
|
||||
element.getModifierList()?.getModifier(KtTokens.ENUM_KEYWORD)
|
||||
?: element.node.findChildByType(TokenSet.create(KtTokens.CLASS_KEYWORD, KtTokens.OBJECT_KEYWORD))?.psi
|
||||
?: element
|
||||
|
||||
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> {
|
||||
when (element) {
|
||||
is KtConstructor<*> -> {
|
||||
@@ -212,17 +217,15 @@ object PositioningStrategies {
|
||||
}
|
||||
is KtFunction -> {
|
||||
val endOfSignatureElement =
|
||||
element.typeReference
|
||||
?: element.valueParameterList
|
||||
?: element.nameIdentifier
|
||||
?: element
|
||||
val startElement
|
||||
= if (element is KtFunctionLiteral) {
|
||||
element.getReceiverTypeReference()
|
||||
element.typeReference
|
||||
?: element.valueParameterList
|
||||
?: element.nameIdentifier
|
||||
?: element
|
||||
val startElement = if (element is KtFunctionLiteral) {
|
||||
element.getReceiverTypeReference()
|
||||
?: element.getValueParameterList()
|
||||
?: element
|
||||
}
|
||||
else element
|
||||
} else element
|
||||
return markRange(startElement, endOfSignatureElement)
|
||||
}
|
||||
is KtProperty -> {
|
||||
@@ -231,15 +234,16 @@ object PositioningStrategies {
|
||||
}
|
||||
is KtPropertyAccessor -> {
|
||||
val endOfSignatureElement =
|
||||
element.returnTypeReference
|
||||
?: element.rightParenthesis?.psi
|
||||
?: element.namePlaceholder
|
||||
element.returnTypeReference
|
||||
?: element.rightParenthesis?.psi
|
||||
?: element.namePlaceholder
|
||||
|
||||
return markRange(element, endOfSignatureElement)
|
||||
}
|
||||
is KtClass -> {
|
||||
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)
|
||||
}
|
||||
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> {
|
||||
return if (element is KtDeclaration)
|
||||
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> =
|
||||
markElement(
|
||||
when (element) {
|
||||
is KtClassOrObject ->
|
||||
element.getDeclarationKeyword() ?:
|
||||
element.nameIdentifier ?:
|
||||
element
|
||||
markElement(
|
||||
when (element) {
|
||||
is KtClassOrObject ->
|
||||
element.getDeclarationKeyword() ?: element.nameIdentifier ?: element
|
||||
|
||||
is KtNamedFunction ->
|
||||
element.modifierList?.getModifier(KtTokens.INLINE_KEYWORD) ?:
|
||||
element.funKeyword ?:
|
||||
element
|
||||
is KtNamedFunction ->
|
||||
element.modifierList?.getModifier(KtTokens.INLINE_KEYWORD) ?: 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> {
|
||||
if (element is KtTypeParameterListOwner) {
|
||||
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> {
|
||||
val nameIdentifier = when (element) {
|
||||
is KtNamedDeclaration -> element.nameIdentifier
|
||||
@@ -325,7 +335,8 @@ object PositioningStrategies {
|
||||
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> {
|
||||
if (element is KtArrayAccessExpression) {
|
||||
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>() {
|
||||
override fun mark(element: KtModifierListOwner): List<TextRange> {
|
||||
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> {
|
||||
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> {
|
||||
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 result = visibilityTokens.mapNotNull { modifierList?.getModifier(it)?.textRange }
|
||||
@@ -380,38 +395,44 @@ object PositioningStrategies {
|
||||
is KtPropertyAccessor -> element.namePlaceholder
|
||||
is KtAnonymousInitializer -> element
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
@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> {
|
||||
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> {
|
||||
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> {
|
||||
val varargModifier = element.modifierList!!.getModifier(KtTokens.VARARG_KEYWORD)!!
|
||||
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> {
|
||||
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> {
|
||||
val lastBracketRange = (element.bodyExpression as? KtBlockExpression)?.lastBracketRange
|
||||
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> {
|
||||
return when (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> {
|
||||
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> {
|
||||
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> {
|
||||
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> =
|
||||
when (element) {
|
||||
is KtWhenExpression -> markElement(element.whenKeyword)
|
||||
is KtIfExpression -> markElement(element.ifKeyword)
|
||||
is KtOperationExpression -> markElement(element.operationReference)
|
||||
else -> error("Expression is not an if, when or operation expression: ${element.getElementTextWithContext()}")
|
||||
}
|
||||
when (element) {
|
||||
is KtWhenExpression -> markElement(element.whenKeyword)
|
||||
is KtIfExpression -> markElement(element.ifKeyword)
|
||||
is KtOperationExpression -> markElement(element.operationReference)
|
||||
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> {
|
||||
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> {
|
||||
if (element is KtCallExpression) {
|
||||
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> {
|
||||
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> {
|
||||
val valueParameterList = element.valueParameterList
|
||||
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> {
|
||||
if (element is KtConstantExpression) {
|
||||
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> {
|
||||
if (element is KtConstantExpression) {
|
||||
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> {
|
||||
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> {
|
||||
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> {
|
||||
if (element.hasModifier(KtTokens.COMPANION_KEYWORD)) {
|
||||
return modifierSetPosition(KtTokens.COMPANION_KEYWORD).mark(element)
|
||||
@@ -542,38 +577,43 @@ object PositioningStrategies {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField val SECONDARY_CONSTRUCTOR_DELEGATION_CALL: PositioningStrategy<KtConstructorDelegationCall> =
|
||||
object : PositioningStrategy<KtConstructorDelegationCall>() {
|
||||
override fun mark(element: KtConstructorDelegationCall): List<TextRange> {
|
||||
if (element.isImplicit) {
|
||||
val constructor = element.getStrictParentOfType<KtSecondaryConstructor>()!!
|
||||
val valueParameterList = constructor.valueParameterList ?: return markElement(constructor)
|
||||
return markRange(constructor.getConstructorKeyword(), valueParameterList.lastChild)
|
||||
}
|
||||
return markElement(element.calleeExpression ?: element)
|
||||
@JvmField
|
||||
val SECONDARY_CONSTRUCTOR_DELEGATION_CALL: PositioningStrategy<KtConstructorDelegationCall> =
|
||||
object : PositioningStrategy<KtConstructorDelegationCall>() {
|
||||
override fun mark(element: KtConstructorDelegationCall): List<TextRange> {
|
||||
if (element.isImplicit) {
|
||||
val constructor = element.getStrictParentOfType<KtSecondaryConstructor>()!!
|
||||
val valueParameterList = constructor.valueParameterList ?: return markElement(constructor)
|
||||
return markRange(constructor.getConstructorKeyword(), valueParameterList.lastChild)
|
||||
}
|
||||
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> {
|
||||
val specifiers = element.superTypeListEntries
|
||||
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> {
|
||||
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> {
|
||||
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> {
|
||||
element.alias?.nameIdentifier?.let { return markElement(it) }
|
||||
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> {
|
||||
val labeledExpression = element.labeledExpression
|
||||
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> {
|
||||
element.receiverTypeReference?.let { return markElement(it) }
|
||||
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.renderer.DescriptorRenderer
|
||||
|
||||
fun <P : Any> renderParameter(parameter: P, renderer: DiagnosticParameterRenderer<P>?, context: RenderingContext): Any
|
||||
= renderer?.render(parameter, context) ?: parameter
|
||||
fun <P : Any> renderParameter(parameter: P, renderer: DiagnosticParameterRenderer<P>?, context: RenderingContext): Any =
|
||||
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)
|
||||
|
||||
|
||||
@@ -57,27 +57,33 @@ object Renderers {
|
||||
|
||||
private val LOG = Logger.getInstance(Renderers::class.java)
|
||||
|
||||
@JvmField val TO_STRING = Renderer<Any> {
|
||||
element ->
|
||||
@JvmField
|
||||
val TO_STRING = Renderer<Any> { element ->
|
||||
if (element is DeclarationDescriptor) {
|
||||
LOG.warn("Diagnostic renderer TO_STRING was used to render an instance of DeclarationDescriptor.\n"
|
||||
+ "This is usually a bad idea, because descriptors' toString() includes some debug information, "
|
||||
+ "which should not be seen by the user.\nDescriptor: " + element)
|
||||
LOG.warn(
|
||||
"Diagnostic renderer TO_STRING was used to render an instance of DeclarationDescriptor.\n"
|
||||
+ "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()
|
||||
}
|
||||
|
||||
@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()
|
||||
it.printStackTrace(PrintWriter(writer))
|
||||
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()
|
||||
" ${it.getCapability(ModuleInfo.Capability)?.displayedName ?: ""}" + when (platform) {
|
||||
MultiTargetPlatform.Common -> ""
|
||||
@@ -86,13 +92,15 @@ object Renderers {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField val VISIBILITY = Renderer<Visibility> {
|
||||
@JvmField
|
||||
val VISIBILITY = Renderer<Visibility> {
|
||||
if (it == Visibilities.INVISIBLE_FAKE)
|
||||
"invisible (private in a supertype)"
|
||||
else it.displayName
|
||||
}
|
||||
|
||||
@JvmField val DECLARATION_NAME_WITH_KIND = Renderer<DeclarationDescriptor> {
|
||||
@JvmField
|
||||
val DECLARATION_NAME_WITH_KIND = Renderer<DeclarationDescriptor> {
|
||||
val name = it.name.asString()
|
||||
when (it) {
|
||||
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 withPlatform = if (descriptor is MemberDescriptor && descriptor.isActual)
|
||||
"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) {
|
||||
"file"
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val containingDeclaration = it.containingDeclaration
|
||||
if (containingDeclaration is PackageFragmentDescriptor) {
|
||||
containingDeclaration.fqName.asString().wrapIntoQuotes()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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 {
|
||||
classOrObject: KtClassOrObject ->
|
||||
@JvmField
|
||||
val RENDER_CLASS_OR_OBJECT = Renderer { classOrObject: KtClassOrObject ->
|
||||
val name = classOrObject.name?.let { " ${it.wrapIntoQuotes()}" } ?: ""
|
||||
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 {
|
||||
variance: Variance ->
|
||||
@JvmField
|
||||
val RENDER_POSITION_VARIANCE = Renderer { variance: Variance ->
|
||||
when (variance) {
|
||||
Variance.INVARIANT -> "invariant"
|
||||
Variance.IN_VARIANCE -> "in"
|
||||
@@ -157,17 +169,17 @@ object Renderers {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField val AMBIGUOUS_CALLS = Renderer {
|
||||
calls: Collection<ResolvedCall<*>> ->
|
||||
@JvmField
|
||||
val AMBIGUOUS_CALLS = Renderer { calls: Collection<ResolvedCall<*>> ->
|
||||
val descriptors = calls.map { it.resultingDescriptor }
|
||||
val context = RenderingContext.Impl(descriptors)
|
||||
descriptors
|
||||
.sortedWith(MemberComparator.INSTANCE)
|
||||
.joinToString(separator = "\n", prefix = "\n") { FQ_NAMES_IN_TYPES.render(it, context) }
|
||||
.sortedWith(MemberComparator.INSTANCE)
|
||||
.joinToString(separator = "\n", prefix = "\n") { FQ_NAMES_IN_TYPES.render(it, context) }
|
||||
}
|
||||
|
||||
@JvmStatic fun <T> commaSeparated(itemRenderer: DiagnosticParameterRenderer<T>) = ContextDependentRenderer<Collection<T>> {
|
||||
collection, context ->
|
||||
@JvmStatic
|
||||
fun <T> commaSeparated(itemRenderer: DiagnosticParameterRenderer<T>) = ContextDependentRenderer<Collection<T>> { collection, context ->
|
||||
buildString {
|
||||
val iterator = collection.iterator()
|
||||
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()
|
||||
}
|
||||
|
||||
@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()
|
||||
}
|
||||
|
||||
@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()
|
||||
}
|
||||
|
||||
@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()
|
||||
}
|
||||
|
||||
@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()
|
||||
}
|
||||
|
||||
@JvmStatic fun renderConflictingSubstitutionsInferenceError(
|
||||
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
||||
@JvmStatic
|
||||
fun renderConflictingSubstitutionsInferenceError(
|
||||
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
||||
): TabledDescriptorRenderer {
|
||||
LOG.assertTrue(inferenceErrorData.constraintSystem.status.hasConflictingConstraints(),
|
||||
debugMessage("Conflicting substitutions inference error renderer is applied for incorrect status", inferenceErrorData))
|
||||
LOG.assertTrue(
|
||||
inferenceErrorData.constraintSystem.status.hasConflictingConstraints(),
|
||||
debugMessage("Conflicting substitutions inference error renderer is applied for incorrect status", inferenceErrorData)
|
||||
)
|
||||
|
||||
val substitutedDescriptors = Lists.newArrayList<CallableDescriptor>()
|
||||
val substitutors = ConstraintsUtil.getSubstitutorsForConflictingParameters(inferenceErrorData.constraintSystem)
|
||||
@@ -219,10 +239,12 @@ object Renderers {
|
||||
return result
|
||||
}
|
||||
|
||||
result.text(newText()
|
||||
.normal("Cannot infer type parameter ")
|
||||
.strong(firstConflictingVariable.name)
|
||||
.normal(" in "))
|
||||
result.text(
|
||||
newText()
|
||||
.normal("Cannot infer type parameter ")
|
||||
.strong(firstConflictingVariable.name)
|
||||
.normal(" in ")
|
||||
)
|
||||
val table = newTable()
|
||||
result.table(table)
|
||||
table.descriptor(inferenceErrorData.descriptor).text("None of the following substitutions")
|
||||
@@ -249,29 +271,33 @@ object Renderers {
|
||||
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
|
||||
}
|
||||
|
||||
@JvmStatic fun renderParameterConstraintError(
|
||||
inferenceErrorData: InferenceErrorData, renderer: TabledDescriptorRenderer
|
||||
@JvmStatic
|
||||
fun renderParameterConstraintError(
|
||||
inferenceErrorData: InferenceErrorData, renderer: TabledDescriptorRenderer
|
||||
): TabledDescriptorRenderer {
|
||||
val constraintErrors = inferenceErrorData.constraintSystem.status.constraintErrors
|
||||
val errorPositions = constraintErrors.filter { it is ParameterConstraintError }.map { it.constraintPosition }
|
||||
return renderer.table(
|
||||
TabledDescriptorRenderer
|
||||
.newTable()
|
||||
.descriptor(inferenceErrorData.descriptor)
|
||||
.text("cannot be applied to")
|
||||
.functionArgumentTypeList(inferenceErrorData.receiverArgumentType,
|
||||
inferenceErrorData.valueArgumentsTypes,
|
||||
{ errorPositions.contains(it) }))
|
||||
TabledDescriptorRenderer
|
||||
.newTable()
|
||||
.descriptor(inferenceErrorData.descriptor)
|
||||
.text("cannot be applied to")
|
||||
.functionArgumentTypeList(inferenceErrorData.receiverArgumentType,
|
||||
inferenceErrorData.valueArgumentsTypes,
|
||||
{ errorPositions.contains(it) })
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@JvmStatic fun renderNoInformationForParameterError(
|
||||
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
||||
@JvmStatic
|
||||
fun renderNoInformationForParameterError(
|
||||
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
||||
): TabledDescriptorRenderer {
|
||||
val firstUnknownVariable = inferenceErrorData.constraintSystem.typeVariables.firstOrNull { variable ->
|
||||
inferenceErrorData.constraintSystem.getTypeBounds(variable).values.isEmpty()
|
||||
@@ -280,21 +306,28 @@ object Renderers {
|
||||
}
|
||||
|
||||
return result
|
||||
.text(newText().normal("Not enough information to infer parameter ")
|
||||
.strong(firstUnknownVariable.name)
|
||||
.normal(" in "))
|
||||
.table(newTable()
|
||||
.descriptor(inferenceErrorData.descriptor)
|
||||
.text("Please specify it explicitly."))
|
||||
.text(
|
||||
newText().normal("Not enough information to infer parameter ")
|
||||
.strong(firstUnknownVariable.name)
|
||||
.normal(" in ")
|
||||
)
|
||||
.table(
|
||||
newTable()
|
||||
.descriptor(inferenceErrorData.descriptor)
|
||||
.text("Please specify it explicitly.")
|
||||
)
|
||||
}
|
||||
|
||||
@JvmStatic fun renderUpperBoundViolatedInferenceError(
|
||||
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
||||
@JvmStatic
|
||||
fun renderUpperBoundViolatedInferenceError(
|
||||
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
||||
): TabledDescriptorRenderer {
|
||||
val constraintSystem = inferenceErrorData.constraintSystem
|
||||
val status = constraintSystem.status
|
||||
LOG.assertTrue(status.hasViolatedUpperBound(),
|
||||
debugMessage("Upper bound violated renderer is applied for incorrect status", inferenceErrorData))
|
||||
LOG.assertTrue(
|
||||
status.hasViolatedUpperBound(),
|
||||
debugMessage("Upper bound violated renderer is applied for incorrect status", inferenceErrorData)
|
||||
)
|
||||
|
||||
val systemWithoutWeakConstraints = constraintSystem.filterConstraintsOut(TYPE_BOUND_POSITION)
|
||||
val typeParameterDescriptor = inferenceErrorData.descriptor.typeParameters.firstOrNull {
|
||||
@@ -304,7 +337,7 @@ object Renderers {
|
||||
if (typeParameterDescriptor == null) {
|
||||
if (inferenceErrorData.descriptor is TypeAliasConstructorDescriptor) {
|
||||
renderUpperBoundViolatedInferenceErrorForTypeAliasConstructor(
|
||||
inferenceErrorData, result, systemWithoutWeakConstraints
|
||||
inferenceErrorData, result, systemWithoutWeakConstraints
|
||||
)?.let {
|
||||
return it
|
||||
}
|
||||
@@ -313,7 +346,12 @@ object Renderers {
|
||||
return if (status.hasConflictingConstraints())
|
||||
renderConflictingSubstitutionsInferenceError(inferenceErrorData, result)
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -321,21 +359,30 @@ object Renderers {
|
||||
val typeVariable = systemWithoutWeakConstraints.descriptorToVariable(inferenceErrorData.call.toHandle(), typeParameterDescriptor)
|
||||
val inferredValueForTypeParameter = systemWithoutWeakConstraints.getTypeBounds(typeVariable).value
|
||||
if (inferredValueForTypeParameter == null) {
|
||||
LOG.error(debugMessage("System without weak constraints is not successful, there is no value for type parameter " +
|
||||
typeParameterDescriptor.name + "\n: " + systemWithoutWeakConstraints, inferenceErrorData))
|
||||
LOG.error(
|
||||
debugMessage(
|
||||
"System without weak constraints is not successful, there is no value for type parameter " +
|
||||
typeParameterDescriptor.name + "\n: " + systemWithoutWeakConstraints, inferenceErrorData
|
||||
)
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
result.text(newText()
|
||||
.normal("Type parameter bound for ")
|
||||
.strong(typeParameterDescriptor.name)
|
||||
.normal(" in "))
|
||||
.table(newTable()
|
||||
.descriptor(inferenceErrorData.descriptor))
|
||||
result.text(
|
||||
newText()
|
||||
.normal("Type parameter bound for ")
|
||||
.strong(typeParameterDescriptor.name)
|
||||
.normal(" in ")
|
||||
)
|
||||
.table(
|
||||
newTable()
|
||||
.descriptor(inferenceErrorData.descriptor)
|
||||
)
|
||||
|
||||
var violatedUpperBound: KotlinType? = null
|
||||
for (upperBound in typeParameterDescriptor.upperBounds) {
|
||||
val upperBoundWithSubstitutedInferredTypes = systemWithoutWeakConstraints.resultingSubstitutor.substitute(upperBound, Variance.INVARIANT)
|
||||
val upperBoundWithSubstitutedInferredTypes =
|
||||
systemWithoutWeakConstraints.resultingSubstitutor.substitute(upperBound, Variance.INVARIANT)
|
||||
if (upperBoundWithSubstitutedInferredTypes != null
|
||||
&& !KotlinTypeChecker.DEFAULT.isSubtypeOf(inferredValueForTypeParameter, upperBoundWithSubstitutedInferredTypes)) {
|
||||
violatedUpperBound = upperBoundWithSubstitutedInferredTypes
|
||||
@@ -343,26 +390,32 @@ object Renderers {
|
||||
}
|
||||
}
|
||||
if (violatedUpperBound == null) {
|
||||
LOG.error(debugMessage("Type parameter (chosen as violating its upper bound)" +
|
||||
typeParameterDescriptor.name + " violates no bounds after substitution", inferenceErrorData))
|
||||
LOG.error(
|
||||
debugMessage(
|
||||
"Type parameter (chosen as violating its upper bound)" +
|
||||
typeParameterDescriptor.name + " violates no bounds after substitution", inferenceErrorData
|
||||
)
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
// TODO: context should be in fact shared for the table and these two types
|
||||
val context = RenderingContext.of(inferredValueForTypeParameter, violatedUpperBound)
|
||||
val typeRenderer = result.typeRenderer
|
||||
result.text(newText()
|
||||
.normal(" is not satisfied: inferred type ")
|
||||
.error(typeRenderer.render(inferredValueForTypeParameter, context))
|
||||
.normal(" is not a subtype of ")
|
||||
.strong(typeRenderer.render(violatedUpperBound, context)))
|
||||
result.text(
|
||||
newText()
|
||||
.normal(" is not satisfied: inferred type ")
|
||||
.error(typeRenderer.render(inferredValueForTypeParameter, context))
|
||||
.normal(" is not a subtype of ")
|
||||
.strong(typeRenderer.render(violatedUpperBound, context))
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun renderUpperBoundViolatedInferenceErrorForTypeAliasConstructor(
|
||||
inferenceErrorData: InferenceErrorData,
|
||||
result: TabledDescriptorRenderer,
|
||||
systemWithoutWeakConstraints: ConstraintSystem
|
||||
inferenceErrorData: InferenceErrorData,
|
||||
result: TabledDescriptorRenderer,
|
||||
systemWithoutWeakConstraints: ConstraintSystem
|
||||
): TabledDescriptorRenderer? {
|
||||
val descriptor = inferenceErrorData.descriptor
|
||||
if (descriptor !is TypeAliasConstructorDescriptor) {
|
||||
@@ -391,12 +444,16 @@ object Renderers {
|
||||
val context = RenderingContext.of(violatingInferredType, violatedUpperBound)
|
||||
val typeRenderer = result.typeRenderer
|
||||
|
||||
result.text(newText().normal("Type parameter bound for ").strong(constraintInfo.typeParameter.name)
|
||||
.normal(" in type inferred from type alias expansion for "))
|
||||
.table(newTable().descriptor(inferenceErrorData.descriptor))
|
||||
result.text(
|
||||
newText().normal("Type parameter bound for ").strong(constraintInfo.typeParameter.name)
|
||||
.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))
|
||||
.normal(" is not a subtype of ").strong(typeRenderer.render(violatedUpperBound, context)))
|
||||
result.text(
|
||||
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
|
||||
}
|
||||
@@ -404,8 +461,9 @@ object Renderers {
|
||||
return null
|
||||
}
|
||||
|
||||
@JvmStatic fun renderCannotCaptureTypeParameterError(
|
||||
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
||||
@JvmStatic
|
||||
fun renderCannotCaptureTypeParameterError(
|
||||
inferenceErrorData: InferenceErrorData, result: TabledDescriptorRenderer
|
||||
): TabledDescriptorRenderer {
|
||||
val system = inferenceErrorData.constraintSystem
|
||||
val errors = system.status.constraintErrors
|
||||
@@ -419,7 +477,12 @@ object Renderers {
|
||||
val boundWithCapturedType = typeBounds.bounds.firstOrNull { it.constrainingType.isCaptured() }
|
||||
val capturedTypeConstructor = boundWithCapturedType?.constrainingType?.constructor as? CapturedTypeConstructor
|
||||
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
|
||||
}
|
||||
|
||||
@@ -431,20 +494,25 @@ object Renderers {
|
||||
}
|
||||
|
||||
val explanation =
|
||||
"Type parameter has an upper bound ${result.typeRenderer.render(upperBound, RenderingContext.of(upperBound)).wrapIntoQuotes()}" +
|
||||
" that cannot be satisfied capturing 'in' projection"
|
||||
"Type parameter has an upper bound ${result.typeRenderer.render(
|
||||
upperBound,
|
||||
RenderingContext.of(upperBound)
|
||||
).wrapIntoQuotes()}" +
|
||||
" that cannot be satisfied capturing 'in' projection"
|
||||
|
||||
result.text(newText().normal(
|
||||
result.text(
|
||||
newText().normal(
|
||||
typeParameter.name.wrapIntoQuotes() +
|
||||
" cannot capture " +
|
||||
"${capturedTypeConstructor.typeProjection.toString().wrapIntoQuotes()}. " +
|
||||
explanation
|
||||
))
|
||||
" cannot capture " +
|
||||
"${capturedTypeConstructor.typeProjection.toString().wrapIntoQuotes()}. " +
|
||||
explanation
|
||||
)
|
||||
)
|
||||
return result
|
||||
}
|
||||
|
||||
@JvmField val CLASSES_OR_SEPARATED = Renderer<Collection<ClassDescriptor>> {
|
||||
descriptors ->
|
||||
@JvmField
|
||||
val CLASSES_OR_SEPARATED = Renderer<Collection<ClassDescriptor>> { descriptors ->
|
||||
buildString {
|
||||
var index = 0
|
||||
for (descriptor in descriptors) {
|
||||
@@ -452,17 +520,18 @@ object Renderers {
|
||||
index++
|
||||
if (index <= descriptors.size - 2) {
|
||||
append(", ")
|
||||
}
|
||||
else if (index == descriptors.size - 1) {
|
||||
} else if (index == descriptors.size - 1) {
|
||||
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 {
|
||||
val typeBounds = linkedSetOf<TypeBounds>()
|
||||
@@ -470,8 +539,8 @@ object Renderers {
|
||||
typeBounds.add(constraintSystem.getTypeBounds(variable))
|
||||
}
|
||||
return "type parameter bounds:\n" +
|
||||
StringUtil.join(typeBounds, { renderTypeBounds(it, short = shortTypeBounds) }, "\n") + "\n\n" + "status:\n" +
|
||||
ConstraintsUtil.getDebugMessageForStatus(constraintSystem.status)
|
||||
StringUtil.join(typeBounds, { renderTypeBounds(it, short = shortTypeBounds) }, "\n") + "\n\n" + "status:\n" +
|
||||
ConstraintsUtil.getDebugMessageForStatus(constraintSystem.status)
|
||||
}
|
||||
|
||||
private fun renderTypeBounds(typeBounds: TypeBounds, short: Boolean): String {
|
||||
@@ -482,14 +551,13 @@ object Renderers {
|
||||
else -> ":= "
|
||||
}
|
||||
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 + ')'
|
||||
}
|
||||
val typeVariableName = typeBounds.typeVariable.name
|
||||
return if (typeBounds.bounds.isEmpty()) {
|
||||
typeVariableName.asString()
|
||||
}
|
||||
else
|
||||
} else
|
||||
"$typeVariableName ${StringUtil.join(typeBounds.bounds, renderBound, ", ")}"
|
||||
}
|
||||
|
||||
@@ -503,8 +571,7 @@ object Renderers {
|
||||
val context = RenderingContext.Empty
|
||||
if (TypeUtils.noExpectedType(inferenceErrorData.expectedType)) {
|
||||
append(inferenceErrorData.expectedType)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
append(RENDER_TYPE.render(inferenceErrorData.expectedType, context))
|
||||
}
|
||||
append("\nArgument types:\n")
|
||||
@@ -519,26 +586,33 @@ object Renderers {
|
||||
|
||||
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) {
|
||||
val list = it.joinToString(", ", limit = WHEN_MISSING_LIMIT) { "'$it'" }
|
||||
val branches = if (it.size > 1) "branches" else "branch"
|
||||
"$list $branches or 'else' branch instead"
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
"'else' branch"
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField val FQ_NAMES_IN_TYPES = DescriptorRenderer.FQ_NAMES_IN_TYPES.asRenderer()
|
||||
@JvmField val COMPACT = DescriptorRenderer.COMPACT.asRenderer()
|
||||
@JvmField val COMPACT_WITHOUT_SUPERTYPES = DescriptorRenderer.COMPACT_WITHOUT_SUPERTYPES.asRenderer()
|
||||
@JvmField val WITHOUT_MODIFIERS = DescriptorRenderer.withOptions {
|
||||
@JvmField
|
||||
val FQ_NAMES_IN_TYPES = DescriptorRenderer.FQ_NAMES_IN_TYPES.asRenderer()
|
||||
@JvmField
|
||||
val COMPACT = DescriptorRenderer.COMPACT.asRenderer()
|
||||
@JvmField
|
||||
val COMPACT_WITHOUT_SUPERTYPES = DescriptorRenderer.COMPACT_WITHOUT_SUPERTYPES.asRenderer()
|
||||
@JvmField
|
||||
val WITHOUT_MODIFIERS = DescriptorRenderer.withOptions {
|
||||
modifiers = emptySet()
|
||||
}.asRenderer()
|
||||
@JvmField val SHORT_NAMES_IN_TYPES = DescriptorRenderer.SHORT_NAMES_IN_TYPES.asRenderer()
|
||||
@JvmField val COMPACT_WITH_MODIFIERS = DescriptorRenderer.COMPACT_WITH_MODIFIERS.asRenderer()
|
||||
@JvmField val DEPRECATION_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.withOptions {
|
||||
@JvmField
|
||||
val SHORT_NAMES_IN_TYPES = DescriptorRenderer.SHORT_NAMES_IN_TYPES.asRenderer()
|
||||
@JvmField
|
||||
val COMPACT_WITH_MODIFIERS = DescriptorRenderer.COMPACT_WITH_MODIFIERS.asRenderer()
|
||||
@JvmField
|
||||
val DEPRECATION_RENDERER = DescriptorRenderer.ONLY_NAMES_WITH_SHORT_TYPES.withOptions {
|
||||
withoutTypeParameters = false
|
||||
receiverAfterName = false
|
||||
renderAccessors = true
|
||||
|
||||
+8
-7
@@ -37,7 +37,7 @@ private class AdaptiveClassifierNamePolicy(private val ambiguousNames: List<Name
|
||||
return when {
|
||||
hasUniqueName(classifier) -> ClassifierNamePolicy.SHORT.renderClassifier(classifier, renderer)
|
||||
classifier is ClassDescriptor ||
|
||||
classifier is TypeAliasDescriptor ->
|
||||
classifier is TypeAliasDescriptor ->
|
||||
ClassifierNamePolicy.FULLY_QUALIFIED.renderClassifier(classifier, renderer)
|
||||
classifier is TypeParameterDescriptor -> {
|
||||
val name = classifier.name
|
||||
@@ -55,7 +55,7 @@ private class AdaptiveClassifierNamePolicy(private val ambiguousNames: List<Name
|
||||
}
|
||||
|
||||
private fun DescriptorRenderer.renderAmbiguousTypeParameter(
|
||||
typeParameter: TypeParameterDescriptor, index: Int, firstOccurence: Boolean
|
||||
typeParameter: TypeParameterDescriptor, index: Int, firstOccurence: Boolean
|
||||
) = buildString {
|
||||
append(typeParameter.name)
|
||||
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") {
|
||||
override fun compute(objectsToRender: Collection<Any?>): ClassifierNamePolicy {
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -83,8 +83,7 @@ private fun collectMentionedClassifiersFqNames(contextObjects: Collection<Any?>,
|
||||
}
|
||||
|
||||
contextObjects.filterIsInstance<KotlinType>().forEach { diagnosticType ->
|
||||
diagnosticType.contains {
|
||||
innerType ->
|
||||
diagnosticType.contains { innerType ->
|
||||
innerType.addMentionedTypeConstructor()
|
||||
innerType.getAbbreviation()?.addMentionedTypeConstructor()
|
||||
false
|
||||
@@ -101,12 +100,14 @@ private fun collectMentionedClassifiersFqNames(contextObjects: Collection<Any?>,
|
||||
collectMentionedClassifiersFqNames(it.upperBounds, result)
|
||||
}
|
||||
contextObjects.filterIsInstance<CallableDescriptor>().forEach {
|
||||
collectMentionedClassifiersFqNames(listOf(
|
||||
collectMentionedClassifiersFqNames(
|
||||
listOf(
|
||||
it.typeParameters,
|
||||
it.returnType,
|
||||
it.valueParameters,
|
||||
it.dispatchReceiverParameter?.type,
|
||||
it.extensionReceiverParameter?.type
|
||||
), result)
|
||||
), result
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,9 +38,9 @@ import org.jetbrains.kotlin.types.expressions.LocalClassDescriptorHolder
|
||||
import org.jetbrains.kotlin.types.expressions.LocalLazyDeclarationResolver
|
||||
|
||||
fun StorageComponentContainer.configureModule(
|
||||
moduleContext: ModuleContext,
|
||||
platform: TargetPlatform,
|
||||
platformVersion: TargetPlatformVersion
|
||||
moduleContext: ModuleContext,
|
||||
platform: TargetPlatform,
|
||||
platformVersion: TargetPlatformVersion
|
||||
) {
|
||||
useInstance(moduleContext)
|
||||
useInstance(moduleContext.module)
|
||||
@@ -54,7 +54,7 @@ fun StorageComponentContainer.configureModule(
|
||||
platform.platformConfigurator.configureModuleComponents(this)
|
||||
|
||||
for (extension in StorageComponentContainerContributor.getInstances(moduleContext.project)) {
|
||||
extension.registerModuleComponents(this, platform, moduleContext.module)
|
||||
extension.registerModuleComponents(this, platform, moduleContext.module)
|
||||
}
|
||||
|
||||
configurePlatformIndependentComponents()
|
||||
@@ -66,22 +66,22 @@ private fun StorageComponentContainer.configurePlatformIndependentComponents() {
|
||||
}
|
||||
|
||||
fun StorageComponentContainer.configureModule(
|
||||
moduleContext: ModuleContext,
|
||||
platform: TargetPlatform,
|
||||
platformVersion: TargetPlatformVersion,
|
||||
trace: BindingTrace
|
||||
moduleContext: ModuleContext,
|
||||
platform: TargetPlatform,
|
||||
platformVersion: TargetPlatformVersion,
|
||||
trace: BindingTrace
|
||||
) {
|
||||
configureModule(moduleContext, platform, platformVersion)
|
||||
useInstance(trace)
|
||||
}
|
||||
|
||||
fun createContainerForBodyResolve(
|
||||
moduleContext: ModuleContext,
|
||||
bindingTrace: BindingTrace,
|
||||
platform: TargetPlatform,
|
||||
statementFilter: StatementFilter,
|
||||
targetPlatformVersion: TargetPlatformVersion,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
moduleContext: ModuleContext,
|
||||
bindingTrace: BindingTrace,
|
||||
platform: TargetPlatform,
|
||||
statementFilter: StatementFilter,
|
||||
targetPlatformVersion: TargetPlatformVersion,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): StorageComponentContainer = createContainer("BodyResolve", platform) {
|
||||
configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
|
||||
|
||||
@@ -95,13 +95,13 @@ fun createContainerForBodyResolve(
|
||||
}
|
||||
|
||||
fun createContainerForLazyBodyResolve(
|
||||
moduleContext: ModuleContext,
|
||||
kotlinCodeAnalyzer: KotlinCodeAnalyzer,
|
||||
bindingTrace: BindingTrace,
|
||||
platform: TargetPlatform,
|
||||
bodyResolveCache: BodyResolveCache,
|
||||
targetPlatformVersion: TargetPlatformVersion,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
moduleContext: ModuleContext,
|
||||
kotlinCodeAnalyzer: KotlinCodeAnalyzer,
|
||||
bindingTrace: BindingTrace,
|
||||
platform: TargetPlatform,
|
||||
bodyResolveCache: BodyResolveCache,
|
||||
targetPlatformVersion: TargetPlatformVersion,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): StorageComponentContainer = createContainer("LazyBodyResolve", platform) {
|
||||
configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
|
||||
|
||||
@@ -115,14 +115,14 @@ fun createContainerForLazyBodyResolve(
|
||||
}
|
||||
|
||||
fun createContainerForLazyLocalClassifierAnalyzer(
|
||||
moduleContext: ModuleContext,
|
||||
bindingTrace: BindingTrace,
|
||||
platform: TargetPlatform,
|
||||
lookupTracker: LookupTracker,
|
||||
targetPlatformVersion: TargetPlatformVersion,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
statementFilter: StatementFilter,
|
||||
localClassDescriptorHolder: LocalClassDescriptorHolder
|
||||
moduleContext: ModuleContext,
|
||||
bindingTrace: BindingTrace,
|
||||
platform: TargetPlatform,
|
||||
lookupTracker: LookupTracker,
|
||||
targetPlatformVersion: TargetPlatformVersion,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
statementFilter: StatementFilter,
|
||||
localClassDescriptorHolder: LocalClassDescriptorHolder
|
||||
): StorageComponentContainer = createContainer("LocalClassifierAnalyzer", platform) {
|
||||
configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
|
||||
|
||||
@@ -147,13 +147,13 @@ fun createContainerForLazyLocalClassifierAnalyzer(
|
||||
}
|
||||
|
||||
fun createContainerForLazyResolve(
|
||||
moduleContext: ModuleContext,
|
||||
declarationProviderFactory: DeclarationProviderFactory,
|
||||
bindingTrace: BindingTrace,
|
||||
platform: TargetPlatform,
|
||||
targetPlatformVersion: TargetPlatformVersion,
|
||||
targetEnvironment: TargetEnvironment,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
moduleContext: ModuleContext,
|
||||
declarationProviderFactory: DeclarationProviderFactory,
|
||||
bindingTrace: BindingTrace,
|
||||
platform: TargetPlatform,
|
||||
targetPlatformVersion: TargetPlatformVersion,
|
||||
targetEnvironment: TargetEnvironment,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): StorageComponentContainer = createContainer("LazyResolve", platform) {
|
||||
configureModule(moduleContext, platform, targetPlatformVersion, bindingTrace)
|
||||
|
||||
@@ -168,12 +168,12 @@ fun createContainerForLazyResolve(
|
||||
}
|
||||
|
||||
fun createLazyResolveSession(moduleContext: ModuleContext, files: Collection<KtFile>): ResolveSession =
|
||||
createContainerForLazyResolve(
|
||||
moduleContext,
|
||||
FileBasedDeclarationProviderFactory(moduleContext.storageManager, files),
|
||||
BindingTraceContext(),
|
||||
TargetPlatform.Common,
|
||||
TargetPlatformVersion.NoVersion,
|
||||
CompilerEnvironment,
|
||||
LanguageVersionSettingsImpl.DEFAULT
|
||||
).get<ResolveSession>()
|
||||
createContainerForLazyResolve(
|
||||
moduleContext,
|
||||
FileBasedDeclarationProviderFactory(moduleContext.storageManager, files),
|
||||
BindingTraceContext(),
|
||||
TargetPlatform.Common,
|
||||
TargetPlatformVersion.NoVersion,
|
||||
CompilerEnvironment,
|
||||
LanguageVersionSettingsImpl.DEFAULT
|
||||
).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`. */
|
||||
constructor(bindingContext: BindingContext) {
|
||||
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? {
|
||||
for (packageFragment in packageView.fragments.filter { it.module == module }) {
|
||||
DescriptorUtils.getAllDescriptors(packageFragment.getMemberScope())
|
||||
.filterIsInstance<FunctionDescriptor>()
|
||||
.firstOrNull { isMain(it) }
|
||||
?.let { return it }
|
||||
.filterIsInstance<FunctionDescriptor>()
|
||||
.firstOrNull { isMain(it) }
|
||||
?.let { return it }
|
||||
}
|
||||
|
||||
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 }
|
||||
descriptor.extensionReceiverParameter?.type?.let {parameters += it}
|
||||
descriptor.extensionReceiverParameter?.type?.let { parameters += it }
|
||||
|
||||
if (parameters.size != 1 || !descriptor.typeParameters.isEmpty()) return false
|
||||
|
||||
@@ -127,14 +128,14 @@ class MainFunctionDetector {
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
val containingDeclaration = descriptor.containingDeclaration
|
||||
return containingDeclaration is ClassDescriptor
|
||||
&& containingDeclaration.kind.isSingleton
|
||||
&& (descriptor.hasJvmStaticAnnotation() || !checkJvmStaticAnnotation)
|
||||
&& containingDeclaration.kind.isSingleton
|
||||
&& (descriptor.hasJvmStaticAnnotation() || !checkJvmStaticAnnotation)
|
||||
}
|
||||
|
||||
private fun getJVMFunctionName(functionDescriptor: FunctionDescriptor): String {
|
||||
|
||||
@@ -29,14 +29,17 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
||||
*/
|
||||
class KDocLinkParser : PsiParser {
|
||||
companion object {
|
||||
@JvmStatic fun parseMarkdownLink(root: IElementType, chameleon: ASTNode): ASTNode {
|
||||
@JvmStatic
|
||||
fun parseMarkdownLink(root: IElementType, chameleon: ASTNode): ASTNode {
|
||||
val parentElement = chameleon.treeParent.psi
|
||||
val project = parentElement.project
|
||||
val builder = PsiBuilderFactory.getInstance().createBuilder(project,
|
||||
chameleon,
|
||||
KotlinLexer(),
|
||||
root.language,
|
||||
chameleon.text)
|
||||
val builder = PsiBuilderFactory.getInstance().createBuilder(
|
||||
project,
|
||||
chameleon,
|
||||
KotlinLexer(),
|
||||
root.language,
|
||||
chameleon.text
|
||||
)
|
||||
val parser = KDocLinkParser()
|
||||
|
||||
return parser.parse(root, builder).firstChildNode
|
||||
@@ -60,8 +63,7 @@ class KDocLinkParser : PsiParser {
|
||||
if (builder.tokenType == KtTokens.RBRACKET) {
|
||||
builder.advanceLexer()
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (!builder.eof()) {
|
||||
builder.error("Expression expected")
|
||||
while (!builder.eof()) {
|
||||
|
||||
@@ -32,18 +32,17 @@ class KDocSection(node: ASTNode) : KDocTag(node) {
|
||||
* or null for the default section).
|
||||
*/
|
||||
override fun getName(): String? =
|
||||
(firstChild as? KDocTag)?.name
|
||||
(firstChild as? KDocTag)?.name
|
||||
|
||||
override fun getSubjectName(): String? =
|
||||
(firstChild as? KDocTag)?.getSubjectName()
|
||||
(firstChild as? KDocTag)?.getSubjectName()
|
||||
|
||||
override fun getContent(): String =
|
||||
(firstChild as? KDocTag)?.getContent() ?: super.getContent()
|
||||
(firstChild as? KDocTag)?.getContent() ?: super.getContent()
|
||||
|
||||
fun findTagsByName(name: String): List<KDocTag> {
|
||||
return getChildrenOfType<KDocTag>().filter { it.name == name }
|
||||
}
|
||||
|
||||
fun findTagByName(name: String): KDocTag?
|
||||
= findTagsByName(name).firstOrNull()
|
||||
fun findTagByName(name: String): KDocTag? = findTagsByName(name).firstOrNull()
|
||||
}
|
||||
|
||||
@@ -67,9 +67,9 @@ open class KDocTag(node: ASTNode) : KDocElementImpl(node) {
|
||||
}
|
||||
|
||||
private fun childrenAfterTagName(): List<ASTNode> =
|
||||
node.getChildren(null)
|
||||
.dropWhile { it.elementType == KDocTokens.TAG_NAME }
|
||||
.dropWhile { it.elementType == TokenType.WHITE_SPACE }
|
||||
node.getChildren(null)
|
||||
.dropWhile { it.elementType == KDocTokens.TAG_NAME }
|
||||
.dropWhile { it.elementType == TokenType.WHITE_SPACE }
|
||||
|
||||
/**
|
||||
* 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())
|
||||
indentedCodeBlock = indentedCodeBlock || node.text.startsWith(indentationWhiteSpaces) || node.text.startsWith("\t")
|
||||
startCodeBlock()
|
||||
}
|
||||
else if (KDocTokens.CONTENT_TOKENS.contains(type)) {
|
||||
} else if (KDocTokens.CONTENT_TOKENS.contains(type)) {
|
||||
flushCodeBlock()
|
||||
indentedCodeBlock = false
|
||||
}
|
||||
|
||||
@@ -63,7 +63,9 @@ class KotlinParserDefinition : ParserDefinition {
|
||||
|
||||
return when (elementType) {
|
||||
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)
|
||||
KDocTokens.MARKDOWN_LINK -> KDocLink(astNode)
|
||||
else -> (elementType as KtNodeType).createPsi(astNode)
|
||||
|
||||
+15
-8
@@ -23,7 +23,8 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
||||
|
||||
object PrecedingCommentsBinder : WhitespacesAndCommentsBinder {
|
||||
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
|
||||
|
||||
// 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 {
|
||||
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
|
||||
|
||||
for (idx in tokens.indices.reversed()) {
|
||||
@@ -68,7 +70,8 @@ object PrecedingDocCommentsBinder : WhitespacesAndCommentsBinder {
|
||||
// Binds comments on the same line
|
||||
object TrailingCommentsBinder : WhitespacesAndCommentsBinder {
|
||||
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
|
||||
|
||||
var result = 0
|
||||
@@ -89,7 +92,8 @@ object TrailingCommentsBinder : WhitespacesAndCommentsBinder {
|
||||
|
||||
private class AllCommentsBinder(val isTrailing: Boolean) : WhitespacesAndCommentsBinder {
|
||||
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
|
||||
|
||||
val size = tokens.size
|
||||
@@ -110,14 +114,16 @@ val TRAILING_ALL_COMMENTS_BINDER: WhitespacesAndCommentsBinder = AllCommentsBind
|
||||
|
||||
object DoNotBindAnything : WhitespacesAndCommentsBinder {
|
||||
override fun getEdgePosition(
|
||||
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter): Int {
|
||||
tokens: List<IElementType>, atStreamEdge: Boolean, getter: WhitespacesAndCommentsBinder.TokenTextGetter
|
||||
): Int {
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
object BindFirstShebangWithWhitespaceOnly : WhitespacesAndCommentsBinder {
|
||||
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) {
|
||||
return if (tokens.getOrNull(1) == KtTokens.WHITE_SPACE) 2 else 1
|
||||
}
|
||||
@@ -128,7 +134,8 @@ object BindFirstShebangWithWhitespaceOnly : WhitespacesAndCommentsBinder {
|
||||
|
||||
class BindAll(val isTrailing: Boolean) : WhitespacesAndCommentsBinder {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ import gnu.trove.TIntArrayList
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getContentRange
|
||||
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
|
||||
|
||||
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
|
||||
// It uses the superclass enum node to provide access to the real constructor name
|
||||
class KtEnumEntrySuperclassReferenceExpression :
|
||||
KtExpressionImplStub<KotlinEnumEntrySuperclassReferenceExpressionStub>, KtSimpleNameExpression {
|
||||
KtExpressionImplStub<KotlinEnumEntrySuperclassReferenceExpressionStub>, KtSimpleNameExpression {
|
||||
|
||||
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)
|
||||
private val referencedElement: KtClass
|
||||
get() = calcReferencedElement()!!
|
||||
get() = calcReferencedElement()!!
|
||||
|
||||
private fun calcReferencedElement(): KtClass? {
|
||||
val owner = this.getStrictParentOfType<KtEnumEntry>()
|
||||
|
||||
@@ -35,7 +35,8 @@ abstract class KtExpressionImpl(node: ASTNode) : KtElementImpl(node), KtExpressi
|
||||
}
|
||||
is KtSimpleNameStringTemplateEntry -> {
|
||||
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!!
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,8 +43,7 @@ class KtPrimaryConstructor : KtConstructor<KtPrimaryConstructor> {
|
||||
if (this.modifierList == null) {
|
||||
getConstructorKeyword()?.delete()
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (modifier == KtTokens.PUBLIC_KEYWORD) return
|
||||
val newModifierList = KtPsiFactory(this).createModifierList(modifier)
|
||||
addBefore(newModifierList, getOrCreateConstructorKeyword())
|
||||
@@ -62,8 +61,7 @@ class KtPrimaryConstructor : KtConstructor<KtPrimaryConstructor> {
|
||||
val modifierList = modifierList
|
||||
return if (modifierList != null) {
|
||||
modifierList.addBefore(annotationEntry, modifierList.firstChild) as KtAnnotationEntry
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val parameterList = valueParameterList!!
|
||||
val newModifierList = KtPsiFactory(project).createModifierList(annotationEntry.text)
|
||||
(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)
|
||||
|
||||
@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" +
|
||||
"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.analysisContext: PsiElement? by UserDataProperty(Key.create("ANALYSIS_CONTEXT"))
|
||||
@@ -72,7 +73,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
||||
}
|
||||
|
||||
fun createThisExpression() =
|
||||
(createExpression("this.x") as KtQualifiedExpression).receiverExpression as KtThisExpression
|
||||
(createExpression("this.x") as KtQualifiedExpression).receiverExpression as KtThisExpression
|
||||
|
||||
fun createThisExpression(qualifier: String) =
|
||||
(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 {
|
||||
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 {
|
||||
@@ -184,7 +186,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
||||
return createFileAnnotationListWithAnnotation(annotationText).annotationEntries.first()
|
||||
}
|
||||
|
||||
fun createFileAnnotationListWithAnnotation(annotationText: String) : KtFileAnnotationList {
|
||||
fun createFileAnnotationListWithAnnotation(annotationText: String): KtFileAnnotationList {
|
||||
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 {
|
||||
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 {
|
||||
@@ -217,13 +226,19 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
||||
}
|
||||
|
||||
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 {
|
||||
val text = modifiers.let { "$it "} +
|
||||
(if (isVar) " var " else " val ") + name +
|
||||
(if (type != null) ":" + type else "") + (if (initializer == null) "" else " = " + initializer)
|
||||
val text = modifiers.let { "$it " } +
|
||||
(if (isVar) " var " else " val ") + name +
|
||||
(if (type != null) ":" + type else "") + (if (initializer == null) "" else " = " + initializer)
|
||||
return createProperty(text)
|
||||
}
|
||||
|
||||
@@ -333,7 +348,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
||||
return createClass("class A(){}").getBody()!!
|
||||
}
|
||||
|
||||
fun createParameter(text : String): KtParameter {
|
||||
fun createParameter(text: String): KtParameter {
|
||||
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 createLambdaParameterListIfAny(text: String) =
|
||||
createLambdaExpression(text, "0").functionLiteral.valueParameterList
|
||||
createLambdaExpression(text, "0").functionLiteral.valueParameterList
|
||||
|
||||
fun createLambdaParameterList(text: String) = createLambdaParameterListIfAny(text)!!
|
||||
|
||||
fun createLambdaExpression(parameters: String, body: String): KtLambdaExpression =
|
||||
(if (parameters.isNotEmpty()) createExpression("{ $parameters -> $body }")
|
||||
else createExpression("{ $body }")) as KtLambdaExpression
|
||||
(if (parameters.isNotEmpty()) createExpression("{ $parameters -> $body }")
|
||||
else createExpression("{ $body }")) as KtLambdaExpression
|
||||
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
val file = createFile(buildString { appendImport (importPath) })
|
||||
val file = createFile(buildString { appendImport(importPath) })
|
||||
return file.importDirectives.first()
|
||||
}
|
||||
|
||||
@@ -435,7 +450,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
||||
}
|
||||
|
||||
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 {
|
||||
@@ -443,10 +458,9 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
||||
}
|
||||
|
||||
fun createConstructorKeyword(): PsiElement =
|
||||
createClass("class A constructor()").primaryConstructor!!.getConstructorKeyword()!!
|
||||
createClass("class A constructor()").primaryConstructor!!.getConstructorKeyword()!!
|
||||
|
||||
fun createLabeledExpression(labelName: String): KtLabeledExpression
|
||||
= createExpression("$labelName@ 1") as KtLabeledExpression
|
||||
fun createLabeledExpression(labelName: String): KtLabeledExpression = createExpression("$labelName@ 1") as KtLabeledExpression
|
||||
|
||||
fun createTypeCodeFragment(text: String, context: PsiElement?): KtTypeCodeFragment {
|
||||
return KtTypeCodeFragment(project, "fragment.kt", text, context)
|
||||
@@ -512,6 +526,7 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
||||
TYPE_CONSTRAINTS,
|
||||
DONE
|
||||
}
|
||||
|
||||
private val sb = StringBuilder()
|
||||
private var state = State.MODIFIERS
|
||||
|
||||
@@ -820,7 +835,8 @@ class KtPsiFactory @JvmOverloads constructor(private val project: Project, val m
|
||||
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> {
|
||||
return listOf(expression)
|
||||
}
|
||||
|
||||
@@ -30,22 +30,22 @@ class KtTypeAlias : KtTypeParameterListOwnerStub<KotlinTypeAliasStub>, KtNamedDe
|
||||
constructor(stub: KotlinTypeAliasStub) : super(stub, KtStubElementTypes.TYPEALIAS)
|
||||
|
||||
override fun <R, D> accept(visitor: KtVisitor<R, D>, data: D): R =
|
||||
visitor.visitTypeAlias(this, data)
|
||||
visitor.visitTypeAlias(this, data)
|
||||
|
||||
fun isTopLevel(): Boolean =
|
||||
stub?.isTopLevel() ?: parent is KtFile
|
||||
stub?.isTopLevel() ?: parent is KtFile
|
||||
|
||||
@IfNotParsed
|
||||
fun getTypeAliasKeyword(): PsiElement? =
|
||||
findChildByType(KtTokens.TYPE_ALIAS_KEYWORD)
|
||||
findChildByType(KtTokens.TYPE_ALIAS_KEYWORD)
|
||||
|
||||
@IfNotParsed
|
||||
fun getTypeReference(): KtTypeReference? {
|
||||
return if (stub != null) {
|
||||
val typeReferences = getStubOrPsiChildrenAsList<KtTypeReference, KotlinPlaceHolderStub<KtTypeReference>>(KtStubElementTypes.TYPE_REFERENCE)
|
||||
val typeReferences =
|
||||
getStubOrPsiChildrenAsList<KtTypeReference, KotlinPlaceHolderStub<KtTypeReference>>(KtStubElementTypes.TYPE_REFERENCE)
|
||||
typeReferences[0]
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
findChildByType(KtNodeTypes.TYPE_REFERENCE)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,10 +21,10 @@ import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
|
||||
class KtTypeCodeFragment(
|
||||
project: Project,
|
||||
name: String,
|
||||
text: CharSequence,
|
||||
context: PsiElement?
|
||||
project: Project,
|
||||
name: String,
|
||||
text: CharSequence,
|
||||
context: PsiElement?
|
||||
) : KtCodeFragment(project, name, text, null, KtNodeTypes.TYPE_CODE_FRAGMENT, context) {
|
||||
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 {
|
||||
val anchor = firstChild!!
|
||||
.siblings(forward = true)
|
||||
.dropWhile { it is PsiComment || it is PsiWhiteSpace }
|
||||
.first()
|
||||
.siblings(forward = true)
|
||||
.dropWhile { it is PsiComment || it is PsiWhiteSpace }
|
||||
.first()
|
||||
return addBefore(newModifierList, anchor) as KtModifierList
|
||||
}
|
||||
|
||||
@@ -40,8 +40,7 @@ fun KtModifierListOwner.setModifierList(newModifierList: KtModifierList) {
|
||||
val currentModifierList = modifierList
|
||||
if (currentModifierList != null) {
|
||||
currentModifierList.replace(newModifierList)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
addModifierList(newModifierList)
|
||||
}
|
||||
}
|
||||
@@ -50,8 +49,7 @@ fun addModifier(owner: KtModifierListOwner, modifier: KtModifierKeywordToken) {
|
||||
val modifierList = owner.modifierList
|
||||
if (modifierList == null) {
|
||||
createModifierList(modifier.value, owner)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
addModifier(modifierList, modifier)
|
||||
}
|
||||
}
|
||||
@@ -60,8 +58,7 @@ fun addAnnotationEntry(owner: KtModifierListOwner, annotationEntry: KtAnnotation
|
||||
val modifierList = owner.modifierList
|
||||
return if (modifierList == null) {
|
||||
createModifierList(annotationEntry.text, owner).annotationEntries.first()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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 modifierToReplace = MODIFIERS_TO_REPLACE[modifier]
|
||||
?.mapNotNull { modifierList.getModifier(it) }
|
||||
?.firstOrNull()
|
||||
?.mapNotNull { modifierList.getModifier(it) }
|
||||
?.firstOrNull()
|
||||
|
||||
if (modifier == FINAL_KEYWORD && !modifierList.hasModifier(OVERRIDE_KEYWORD)) {
|
||||
if (modifierToReplace != null) {
|
||||
@@ -85,8 +82,7 @@ internal fun addModifier(modifierList: KtModifierList, modifier: KtModifierKeywo
|
||||
}
|
||||
if (modifierToReplace != null && modifierList.firstChild == modifierList.lastChild) {
|
||||
modifierToReplace.replace(newModifier)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
modifierToReplace?.delete()
|
||||
val newModifierOrder = MODIFIERS_ORDER.indexOf(modifier)
|
||||
|
||||
@@ -129,34 +125,36 @@ fun sortModifiers(modifiers: List<KtModifierKeywordToken>): List<KtModifierKeywo
|
||||
}
|
||||
|
||||
private val MODIFIERS_TO_REPLACE = mapOf(
|
||||
OVERRIDE_KEYWORD to listOf(OPEN_KEYWORD),
|
||||
ABSTRACT_KEYWORD to listOf(OPEN_KEYWORD, FINAL_KEYWORD),
|
||||
OPEN_KEYWORD to listOf(FINAL_KEYWORD, ABSTRACT_KEYWORD),
|
||||
FINAL_KEYWORD to listOf(ABSTRACT_KEYWORD, OPEN_KEYWORD),
|
||||
PUBLIC_KEYWORD to listOf(PROTECTED_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),
|
||||
INTERNAL_KEYWORD to listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD),
|
||||
HEADER_KEYWORD to listOf(IMPL_KEYWORD, ACTUAL_KEYWORD, EXPECT_KEYWORD),
|
||||
IMPL_KEYWORD to listOf(HEADER_KEYWORD, EXPECT_KEYWORD, ACTUAL_KEYWORD),
|
||||
EXPECT_KEYWORD to listOf(IMPL_KEYWORD, ACTUAL_KEYWORD, HEADER_KEYWORD),
|
||||
ACTUAL_KEYWORD to listOf(HEADER_KEYWORD, EXPECT_KEYWORD, IMPL_KEYWORD)
|
||||
OVERRIDE_KEYWORD to listOf(OPEN_KEYWORD),
|
||||
ABSTRACT_KEYWORD to listOf(OPEN_KEYWORD, FINAL_KEYWORD),
|
||||
OPEN_KEYWORD to listOf(FINAL_KEYWORD, ABSTRACT_KEYWORD),
|
||||
FINAL_KEYWORD to listOf(ABSTRACT_KEYWORD, OPEN_KEYWORD),
|
||||
PUBLIC_KEYWORD to listOf(PROTECTED_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),
|
||||
INTERNAL_KEYWORD to listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD),
|
||||
HEADER_KEYWORD to listOf(IMPL_KEYWORD, ACTUAL_KEYWORD, EXPECT_KEYWORD),
|
||||
IMPL_KEYWORD to listOf(HEADER_KEYWORD, EXPECT_KEYWORD, ACTUAL_KEYWORD),
|
||||
EXPECT_KEYWORD to listOf(IMPL_KEYWORD, ACTUAL_KEYWORD, HEADER_KEYWORD),
|
||||
ACTUAL_KEYWORD to listOf(HEADER_KEYWORD, EXPECT_KEYWORD, IMPL_KEYWORD)
|
||||
)
|
||||
|
||||
val MODIFIERS_ORDER = listOf(PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD,
|
||||
HEADER_KEYWORD, IMPL_KEYWORD, EXPECT_KEYWORD, ACTUAL_KEYWORD,
|
||||
FINAL_KEYWORD, OPEN_KEYWORD, ABSTRACT_KEYWORD, SEALED_KEYWORD,
|
||||
CONST_KEYWORD,
|
||||
EXTERNAL_KEYWORD,
|
||||
OVERRIDE_KEYWORD,
|
||||
LATEINIT_KEYWORD,
|
||||
TAILREC_KEYWORD,
|
||||
VARARG_KEYWORD,
|
||||
SUSPEND_KEYWORD,
|
||||
INNER_KEYWORD,
|
||||
ENUM_KEYWORD, ANNOTATION_KEYWORD,
|
||||
COMPANION_KEYWORD,
|
||||
INLINE_KEYWORD,
|
||||
INFIX_KEYWORD,
|
||||
OPERATOR_KEYWORD,
|
||||
DATA_KEYWORD)
|
||||
val MODIFIERS_ORDER = listOf(
|
||||
PUBLIC_KEYWORD, PROTECTED_KEYWORD, PRIVATE_KEYWORD, INTERNAL_KEYWORD,
|
||||
HEADER_KEYWORD, IMPL_KEYWORD, EXPECT_KEYWORD, ACTUAL_KEYWORD,
|
||||
FINAL_KEYWORD, OPEN_KEYWORD, ABSTRACT_KEYWORD, SEALED_KEYWORD,
|
||||
CONST_KEYWORD,
|
||||
EXTERNAL_KEYWORD,
|
||||
OVERRIDE_KEYWORD,
|
||||
LATEINIT_KEYWORD,
|
||||
TAILREC_KEYWORD,
|
||||
VARARG_KEYWORD,
|
||||
SUSPEND_KEYWORD,
|
||||
INNER_KEYWORD,
|
||||
ENUM_KEYWORD, ANNOTATION_KEYWORD,
|
||||
COMPANION_KEYWORD,
|
||||
INLINE_KEYWORD,
|
||||
INFIX_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 {
|
||||
return if (this is KtFile) {
|
||||
this.suppressDiagnosticsInDebugMode
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val file = this.containingFile
|
||||
file is KtFile && file.suppressDiagnosticsInDebugMode
|
||||
}
|
||||
|
||||
@@ -31,23 +31,32 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
import org.jetbrains.kotlin.renderer.render
|
||||
import java.util.*
|
||||
|
||||
fun KtPsiFactory.createExpressionByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtExpression
|
||||
= createByPattern(pattern, *args, reformat = reformat) { createExpression(it) }
|
||||
fun KtPsiFactory.createExpressionByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtExpression =
|
||||
createByPattern(pattern, *args, reformat = reformat) { createExpression(it) }
|
||||
|
||||
fun KtPsiFactory.createValueArgumentListByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtValueArgumentList
|
||||
= createByPattern(pattern, *args, reformat = reformat) { createCallArguments(it) }
|
||||
fun KtPsiFactory.createValueArgumentListByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): KtValueArgumentList =
|
||||
createByPattern(pattern, *args, reformat = reformat) { createCallArguments(it) }
|
||||
|
||||
fun <TDeclaration : KtDeclaration> KtPsiFactory.createDeclarationByPattern(pattern: String, vararg args: Any, reformat: Boolean = true): TDeclaration
|
||||
= createByPattern(pattern, *args, reformat = reformat) { createDeclaration<TDeclaration>(it) }
|
||||
fun <TDeclaration : KtDeclaration> KtPsiFactory.createDeclarationByPattern(
|
||||
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
|
||||
= createByPattern(pattern, *args, reformat = reformat) { createDestructuringDeclaration(it) }
|
||||
fun KtPsiFactory.createDestructuringDeclarationByPattern(
|
||||
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 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
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
val project = placeholder.project
|
||||
val codeStyleManager = CodeStyleManager.getInstance(project)
|
||||
@@ -79,8 +89,7 @@ private object PsiChildRangeArgumentType : PsiElementPlaceholderArgumentType<Psi
|
||||
codeStyleManager.reformatNewlyAddedElement(last.node.treeParent, last.node)
|
||||
}
|
||||
PsiChildRange(first, last)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
placeholder.delete()
|
||||
PsiChildRange.EMPTY
|
||||
}
|
||||
@@ -88,20 +97,25 @@ private object PsiChildRangeArgumentType : PsiElementPlaceholderArgumentType<Psi
|
||||
}
|
||||
|
||||
private val SUPPORTED_ARGUMENT_TYPES = listOf(
|
||||
PsiElementArgumentType(KtExpression::class.java),
|
||||
PsiElementArgumentType(KtTypeReference::class.java),
|
||||
PlainTextArgumentType(String::class.java, toPlainText = { it }),
|
||||
PlainTextArgumentType(Name::class.java, toPlainText = Name::render),
|
||||
PsiChildRangeArgumentType
|
||||
PsiElementArgumentType(KtExpression::class.java),
|
||||
PsiElementArgumentType(KtTypeReference::class.java),
|
||||
PlainTextArgumentType(String::class.java, toPlainText = { it }),
|
||||
PlainTextArgumentType(Name::class.java, toPlainText = Name::render),
|
||||
PsiChildRangeArgumentType
|
||||
)
|
||||
|
||||
@TestOnly
|
||||
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 ->
|
||||
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
|
||||
@@ -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")
|
||||
}
|
||||
val stringPlaceholderRanges = allPlaceholders
|
||||
.filter { args[it.key] is String }
|
||||
.flatMap { it.value }
|
||||
.map { it.range }
|
||||
.filterNot { it.isEmpty }
|
||||
.sortedByDescending { it.startOffset }
|
||||
.filter { args[it.key] is String }
|
||||
.flatMap { it.value }
|
||||
.map { it.range }
|
||||
.filterNot { it.isEmpty }
|
||||
.sortedByDescending { it.startOffset }
|
||||
|
||||
// reformat whole text except for String arguments (as they can contain user's formatting to be preserved)
|
||||
resultElement = if (stringPlaceholderRanges.none()) {
|
||||
codeStyleManager.reformat(resultElement, true) as TElement
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
var bound = resultElement.endOffset - 1
|
||||
for (range in stringPlaceholderRanges) {
|
||||
// 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)
|
||||
if (nextChar == '$') {
|
||||
append(nextChar)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
check(nextChar?.isDigit() ?: false, "unclosed '$'")
|
||||
|
||||
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 placeholderText = if (charOrNull(i) != ':' || charOrNull(i + 1) != '\'') {
|
||||
arg as? String ?: "xyz"
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
check(arg !is String, "do not specify placeholder text for $$n - plain text argument passed")
|
||||
i += 2 // skip ':' and '\''
|
||||
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))
|
||||
continue
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
append(c)
|
||||
}
|
||||
i++
|
||||
|
||||
@@ -152,25 +152,24 @@ fun KtExpression.getQualifiedExpressionForReceiverOrThis(): KtExpression {
|
||||
}
|
||||
|
||||
fun KtExpression.isDotReceiver(): Boolean =
|
||||
(parent as? KtDotQualifiedExpression)?.receiverExpression == this
|
||||
(parent as? KtDotQualifiedExpression)?.receiverExpression == this
|
||||
|
||||
// ---------- Block expression -------------------------------------------------------------------------------------------------------------
|
||||
|
||||
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
|
||||
= (this as? KtBlockExpression)?.statements?.lastOrNull() ?: this
|
||||
fun KtExpression.lastBlockStatementOrThis(): KtExpression = (this as? KtBlockExpression)?.statements?.lastOrNull() ?: this
|
||||
|
||||
fun KtBlockExpression.contentRange(): PsiChildRange {
|
||||
val first = (lBrace?.nextSibling ?: firstChild)
|
||||
?.siblings(withItself = false)
|
||||
?.firstOrNull { it !is PsiWhiteSpace }
|
||||
?.siblings(withItself = false)
|
||||
?.firstOrNull { it !is PsiWhiteSpace }
|
||||
val rBrace = rBrace
|
||||
if (first == rBrace) return PsiChildRange.EMPTY
|
||||
val last = rBrace!!
|
||||
.siblings(forward = false, withItself = false)
|
||||
.first { it !is PsiWhiteSpace }
|
||||
.siblings(forward = false, withItself = false)
|
||||
.first { it !is PsiWhiteSpace }
|
||||
if (last == lBrace) return PsiChildRange.EMPTY
|
||||
return PsiChildRange(first, last)
|
||||
}
|
||||
@@ -248,8 +247,7 @@ fun KtAnnotationsContainer.collectAnnotationEntriesFromStubOrPsi(): List<KtAnnot
|
||||
}
|
||||
|
||||
private fun StubElement<*>.collectAnnotationEntriesFromStubElement(): List<KtAnnotationEntry> {
|
||||
return childrenStubs.flatMap {
|
||||
child ->
|
||||
return childrenStubs.flatMap { child ->
|
||||
when (child.stubType) {
|
||||
KtNodeTypes.ANNOTATION_ENTRY -> listOf(child.psi as KtAnnotationEntry)
|
||||
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)) }
|
||||
}
|
||||
|
||||
// ----------- Other -----------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
fun KtClassOrObject.effectiveDeclarations(): List<KtDeclaration> {
|
||||
return when(this) {
|
||||
return when (this) {
|
||||
is KtClass -> getDeclarations() + getPrimaryConstructorParameters().filter { p -> p.hasValOrVar() }
|
||||
else -> declarations
|
||||
}
|
||||
@@ -368,7 +369,7 @@ fun KtSimpleNameExpression.isCallee(): Boolean {
|
||||
is KtBinaryExpression -> parent.operationReference == this
|
||||
else -> {
|
||||
val callElement =
|
||||
getStrictParentOfType<KtUserType>()
|
||||
getStrictParentOfType<KtUserType>()
|
||||
?.getStrictParentOfType<KtTypeReference>()
|
||||
?.getStrictParentOfType<KtConstructorCalleeExpression>()
|
||||
?.getStrictParentOfType<KtCallElement>()
|
||||
@@ -376,8 +377,7 @@ fun KtSimpleNameExpression.isCallee(): Boolean {
|
||||
if (callElement != null) {
|
||||
val ktConstructorCalleeExpression = callElement.calleeExpression as? KtConstructorCalleeExpression
|
||||
(ktConstructorCalleeExpression?.typeReference?.typeElement as? KtUserType)?.referenceExpression == this
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
@@ -387,8 +387,7 @@ fun KtSimpleNameExpression.isCallee(): Boolean {
|
||||
val KtStringTemplateExpression.plainContent: String
|
||||
get() = getContentRange().substring(text)
|
||||
|
||||
fun KtStringTemplateExpression.isSingleQuoted(): Boolean
|
||||
= node.firstChildNode.textLength == 1
|
||||
fun KtStringTemplateExpression.isSingleQuoted(): Boolean = node.firstChildNode.textLength == 1
|
||||
|
||||
fun KtNamedDeclaration.getValueParameters(): List<KtParameter> {
|
||||
return getValueParameterList()?.parameters ?: Collections.emptyList()
|
||||
@@ -409,13 +408,13 @@ fun KtLambdaArgument.getLambdaArgumentName(bindingContext: BindingContext): Name
|
||||
}
|
||||
|
||||
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? {
|
||||
return set.types
|
||||
.asSequence()
|
||||
.map { getModifier(it as KtModifierKeywordToken) }
|
||||
.firstOrNull { it != null }
|
||||
.asSequence()
|
||||
.map { getModifier(it as KtModifierKeywordToken) }
|
||||
.firstOrNull { it != null }
|
||||
|
||||
}
|
||||
|
||||
@@ -423,34 +422,34 @@ private fun KtModifierListOwner.modifierFromTokenSet(set: TokenSet) = modifierLi
|
||||
|
||||
fun KtModifierList.visibilityModifier() = modifierFromTokenSet(KtTokens.VISIBILITY_MODIFIERS)
|
||||
|
||||
fun KtModifierList.visibilityModifierType(): KtModifierKeywordToken?
|
||||
= visibilityModifier()?.node?.elementType as KtModifierKeywordToken?
|
||||
fun KtModifierList.visibilityModifierType(): KtModifierKeywordToken? = visibilityModifier()?.node?.elementType as KtModifierKeywordToken?
|
||||
|
||||
fun KtModifierListOwner.visibilityModifier() = modifierList?.modifierFromTokenSet(KtTokens.VISIBILITY_MODIFIERS)
|
||||
|
||||
fun KtModifierListOwner.visibilityModifierType(): KtModifierKeywordToken?
|
||||
= visibilityModifier()?.node?.elementType as KtModifierKeywordToken?
|
||||
fun KtModifierListOwner.visibilityModifierType(): KtModifierKeywordToken? =
|
||||
visibilityModifier()?.node?.elementType as KtModifierKeywordToken?
|
||||
|
||||
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 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)
|
||||
// Returns null e.g. for member function parameters, member function locals, property accessors
|
||||
val KtDeclaration.containingClassOrObject: KtClassOrObject?
|
||||
get() = parent.let {
|
||||
when (it) {
|
||||
is KtClassBody -> it.parent as? KtClassOrObject
|
||||
is KtClassOrObject -> it
|
||||
is KtParameterList -> (it.parent as? KtPrimaryConstructor)?.getContainingClassOrObject()
|
||||
else -> null
|
||||
}
|
||||
get() = parent.let {
|
||||
when (it) {
|
||||
is KtClassBody -> it.parent as? KtClassOrObject
|
||||
is KtClassOrObject -> it
|
||||
is KtParameterList -> (it.parent as? KtPrimaryConstructor)?.getContainingClassOrObject()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun KtExpression.getOutermostParenthesizerOrThis(): KtExpression {
|
||||
return (parentsWithSelf.zip(parents)).firstOrNull {
|
||||
@@ -506,7 +505,7 @@ fun KtElement.containingClass(): KtClass? = getStrictParentOfType()
|
||||
|
||||
fun KtClassOrObject.findPropertyByName(name: String): 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 {
|
||||
@@ -516,7 +515,8 @@ fun isTypeConstructorReference(e: PsiElement): Boolean {
|
||||
|
||||
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 {
|
||||
valueParameterList?.let { return it }
|
||||
@@ -535,15 +535,16 @@ fun KtFunctionLiteral.getOrCreateParameterList(): KtParameterList {
|
||||
|
||||
fun KtCallExpression.getOrCreateValueArgumentList(): KtValueArgumentList {
|
||||
valueArgumentList?.let { return it }
|
||||
return addAfter(KtPsiFactory(this).createCallArguments("()"),
|
||||
typeArgumentList ?: calleeExpression) as KtValueArgumentList
|
||||
return addAfter(
|
||||
KtPsiFactory(this).createCallArguments("()"),
|
||||
typeArgumentList ?: calleeExpression
|
||||
) as KtValueArgumentList
|
||||
}
|
||||
|
||||
fun KtCallExpression.addTypeArgument(typeArgument: KtTypeProjection) {
|
||||
if (typeArgumentList != null) {
|
||||
typeArgumentList?.addArgument(typeArgument)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
addAfter(KtPsiFactory(this).createTypeArguments("<${typeArgument.text}>"), calleeExpression)
|
||||
}
|
||||
}
|
||||
@@ -556,7 +557,7 @@ fun KtDeclaration.hasBody() = when (this) {
|
||||
|
||||
|
||||
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? {
|
||||
parents.forEach {
|
||||
|
||||
@@ -68,11 +68,9 @@ val PsiElement.parentsWithSelf: Sequence<PsiElement>
|
||||
val PsiElement.parents: Sequence<PsiElement>
|
||||
get() = parentsWithSelf.drop(1)
|
||||
|
||||
fun PsiElement.prevLeaf(skipEmptyElements: Boolean = false): PsiElement?
|
||||
= PsiTreeUtil.prevLeaf(this, skipEmptyElements)
|
||||
fun PsiElement.prevLeaf(skipEmptyElements: Boolean = false): PsiElement? = PsiTreeUtil.prevLeaf(this, skipEmptyElements)
|
||||
|
||||
fun PsiElement.nextLeaf(skipEmptyElements: Boolean = false): PsiElement?
|
||||
= PsiTreeUtil.nextLeaf(this, skipEmptyElements)
|
||||
fun PsiElement.nextLeaf(skipEmptyElements: Boolean = false): PsiElement? = PsiTreeUtil.nextLeaf(this, skipEmptyElements)
|
||||
|
||||
val PsiElement.prevLeafs: Sequence<PsiElement>
|
||||
get() = generateSequence({ prevLeaf() }, { it.prevLeaf() })
|
||||
@@ -97,7 +95,7 @@ fun PsiElement.nextLeaf(filter: (PsiElement) -> Boolean): PsiElement? {
|
||||
}
|
||||
|
||||
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? {
|
||||
var element = if (strict) parent else this
|
||||
while (element != null) {
|
||||
@@ -175,7 +173,10 @@ inline fun <reified T : PsiElement> PsiElement.getParentOfTypeAndBranch(strict:
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -188,7 +189,9 @@ fun PsiElement.isInsideOf(elements: Iterable<PsiElement>): Boolean = elements.an
|
||||
|
||||
fun PsiChildRange.trimWhiteSpaces(): PsiChildRange {
|
||||
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 --------------------------------------------------------------------------------------------
|
||||
@@ -197,7 +200,10 @@ inline fun <reified T : PsiElement> PsiElement.forEachDescendantOfType(noinline
|
||||
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() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
if (canGoInside(element)) {
|
||||
@@ -215,7 +221,10 @@ inline fun <reified T : PsiElement> PsiElement.anyDescendantOfType(noinline pred
|
||||
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
|
||||
}
|
||||
|
||||
@@ -223,7 +232,10 @@ inline fun <reified T : PsiElement> PsiElement.findDescendantOfType(noinline pre
|
||||
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
|
||||
this.accept(object : PsiRecursiveElementWalkingVisitor() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
@@ -245,7 +257,10 @@ inline fun <reified T : PsiElement> PsiElement.collectDescendantsOfType(noinline
|
||||
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>()
|
||||
forEachDescendantOfType<T>(canGoInside) {
|
||||
if (predicate(it)) {
|
||||
@@ -294,11 +309,11 @@ fun PsiFile.elementsInRange(range: TextRange): List<PsiElement> {
|
||||
val leaf = findFirstLeafWhollyInRange(this, currentRange) ?: break
|
||||
|
||||
val element = leaf
|
||||
.parentsWithSelf
|
||||
.first {
|
||||
val parent = it.parent
|
||||
it is PsiFile || parent.textRange !in currentRange
|
||||
}
|
||||
.parentsWithSelf
|
||||
.first {
|
||||
val parent = it.parent
|
||||
it is PsiFile || parent.textRange !in currentRange
|
||||
}
|
||||
result.add(element)
|
||||
|
||||
offset = element.endOffset
|
||||
@@ -333,8 +348,8 @@ fun PsiElement.getElementTextWithContext(): String {
|
||||
}
|
||||
|
||||
// Find parent for element among file children
|
||||
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")
|
||||
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")
|
||||
|
||||
val startContextOffset = topLevelElement.startOffset
|
||||
val elementContextOffset = textRange.startOffset
|
||||
@@ -344,9 +359,9 @@ fun PsiElement.getElementTextWithContext(): String {
|
||||
|
||||
val isInjected = containingFile is VirtualFileWindow
|
||||
return StringBuilder(topLevelElement.text)
|
||||
.insert(inFileParentOffset, "<caret>")
|
||||
.insert(0, "File name: ${containingFile.name} Physical: ${containingFile.isPhysical} Injected: $isInjected\n")
|
||||
.toString()
|
||||
.insert(inFileParentOffset, "<caret>")
|
||||
.insert(0, "File name: ${containingFile.name} Physical: ${containingFile.isPhysical} Injected: $isInjected\n")
|
||||
.toString()
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
val beforeAnchor : PsiElement? = when {
|
||||
val beforeAnchor: PsiElement? = when {
|
||||
file.packageDirective?.packageKeyword != null -> file.packageDirective!!
|
||||
file.importList != null -> file.importList!!
|
||||
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)
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ interface KotlinPropertyStub : KotlinCallableStubBase<KtProperty> {
|
||||
fun hasReturnTypeRef(): Boolean
|
||||
}
|
||||
|
||||
interface KotlinCallableStubBase<TDeclaration: KtCallableDeclaration> : KotlinStubWithFqName<TDeclaration> {
|
||||
interface KotlinCallableStubBase<TDeclaration : KtCallableDeclaration> : KotlinStubWithFqName<TDeclaration> {
|
||||
fun isTopLevel(): 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.impl.KotlinAnnotationUseSiteTargetStubImpl
|
||||
|
||||
class KtAnnotationUseSiteTargetElementType(debugName: String) : KtStubElementType<KotlinAnnotationUseSiteTargetStub, KtAnnotationUseSiteTarget>(
|
||||
class KtAnnotationUseSiteTargetElementType(debugName: String) :
|
||||
KtStubElementType<KotlinAnnotationUseSiteTargetStub, KtAnnotationUseSiteTarget>(
|
||||
debugName, KtAnnotationUseSiteTarget::class.java, KotlinAnnotationUseSiteTargetStub::class.java
|
||||
) {
|
||||
) {
|
||||
|
||||
override fun createStub(psi: KtAnnotationUseSiteTarget, parentStub: StubElement<PsiElement>): KotlinAnnotationUseSiteTargetStub {
|
||||
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.impl.KotlinEnumEntrySuperclassReferenceExpressionStubImpl
|
||||
|
||||
class KtEnumEntrySuperClassReferenceExpressionElementType(@NonNls debugName: String)
|
||||
: KtStubElementType<KotlinEnumEntrySuperclassReferenceExpressionStub, KtEnumEntrySuperclassReferenceExpression>(
|
||||
class KtEnumEntrySuperClassReferenceExpressionElementType(@NonNls debugName: String) :
|
||||
KtStubElementType<KotlinEnumEntrySuperclassReferenceExpressionStub, KtEnumEntrySuperclassReferenceExpression>(
|
||||
debugName,
|
||||
KtEnumEntrySuperclassReferenceExpression::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())!!)
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.psi.stubs.KotlinImportAliasStub
|
||||
import org.jetbrains.kotlin.psi.stubs.impl.KotlinImportAliasStubImpl
|
||||
|
||||
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 {
|
||||
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
|
||||
|
||||
class KotlinAnnotationEntryStubImpl(
|
||||
parent: StubElement<out PsiElement>?,
|
||||
private val shortName: StringRef,
|
||||
private val hasValueArguments: Boolean
|
||||
parent: StubElement<out PsiElement>?,
|
||||
private val shortName: StringRef,
|
||||
private val hasValueArguments: Boolean
|
||||
) : KotlinStubBaseImpl<KtAnnotationEntry>(parent, KtStubElementTypes.ANNOTATION_ENTRY), KotlinAnnotationEntryStub {
|
||||
|
||||
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
|
||||
|
||||
class KotlinAnnotationUseSiteTargetStubImpl(
|
||||
parent: StubElement<out PsiElement>?,
|
||||
private val target: StringRef
|
||||
parent: StubElement<out PsiElement>?,
|
||||
private val target: StringRef
|
||||
) : KotlinStubBaseImpl<KtAnnotationUseSiteTarget>(parent, KtStubElementTypes.ANNOTATION_TARGET), KotlinAnnotationUseSiteTargetStub {
|
||||
|
||||
override fun getUseSiteTarget() = target.string
|
||||
|
||||
@@ -25,20 +25,21 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import com.intellij.psi.PsiElement
|
||||
|
||||
class KotlinFunctionStubImpl(
|
||||
parent: StubElement<out PsiElement>?,
|
||||
private val nameRef: StringRef?,
|
||||
private val isTopLevel: Boolean,
|
||||
private val fqName: FqName?,
|
||||
private val isExtension: Boolean,
|
||||
private val hasBlockBody: Boolean,
|
||||
private val hasBody: Boolean,
|
||||
private val hasTypeParameterListBeforeFunctionName: Boolean
|
||||
parent: StubElement<out PsiElement>?,
|
||||
private val nameRef: StringRef?,
|
||||
private val isTopLevel: Boolean,
|
||||
private val fqName: FqName?,
|
||||
private val isExtension: Boolean,
|
||||
private val hasBlockBody: Boolean,
|
||||
private val hasBody: Boolean,
|
||||
private val hasTypeParameterListBeforeFunctionName: Boolean
|
||||
) : KotlinStubBaseImpl<KtNamedFunction>(parent, KtStubElementTypes.FUNCTION), KotlinFunctionStub {
|
||||
init {
|
||||
if (isTopLevel && fqName == null) {
|
||||
throw IllegalArgumentException("fqName shouldn't be null for top level functions")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFqName() = fqName
|
||||
|
||||
override fun getName() = StringRef.toString(nameRef)
|
||||
|
||||
+6
-6
@@ -25,12 +25,12 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import com.intellij.psi.PsiElement
|
||||
|
||||
class KotlinParameterStubImpl(
|
||||
parent: StubElement<out PsiElement>?,
|
||||
private val fqName: StringRef?,
|
||||
private val name: StringRef?,
|
||||
private val isMutable: Boolean,
|
||||
private val hasValOrVar: Boolean,
|
||||
private val hasDefaultValue: Boolean
|
||||
parent: StubElement<out PsiElement>?,
|
||||
private val fqName: StringRef?,
|
||||
private val name: StringRef?,
|
||||
private val isMutable: Boolean,
|
||||
private val hasValOrVar: Boolean,
|
||||
private val hasDefaultValue: Boolean
|
||||
) : KotlinStubBaseImpl<KtParameter>(parent, KtStubElementTypes.VALUE_PARAMETER), KotlinParameterStub {
|
||||
override fun getName(): String? {
|
||||
return StringRef.toString(name)
|
||||
|
||||
@@ -30,7 +30,8 @@ import java.util.ArrayList
|
||||
|
||||
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 {
|
||||
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 name = getPropertyName(property)
|
||||
"$name=$value"
|
||||
}
|
||||
catch (e: Exception) {
|
||||
} catch (e: Exception) {
|
||||
LOGGER.error(e)
|
||||
null
|
||||
}
|
||||
@@ -80,6 +80,11 @@ open class KotlinStubBaseImpl<T : KtElementImplStub<*>>(parent: StubElement<*>?,
|
||||
companion object {
|
||||
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
|
||||
|
||||
class KotlinUserTypeStubImpl(
|
||||
parent: StubElement<out PsiElement>?
|
||||
parent: StubElement<out PsiElement>?
|
||||
) : KotlinStubBaseImpl<KtUserType>(parent, KtStubElementTypes.USER_TYPE), KotlinUserTypeStub
|
||||
|
||||
@@ -19,7 +19,7 @@ package org.jetbrains.kotlin.psi.stubs.impl
|
||||
import com.intellij.util.io.StringRef
|
||||
|
||||
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])!! }
|
||||
}
|
||||
}
|
||||
|
||||
+26
-20
@@ -45,25 +45,27 @@ import org.jetbrains.kotlin.types.TypeConstructor
|
||||
* This class has its own synthetic declaration inside.
|
||||
*/
|
||||
class SyntheticClassOrObjectDescriptor(
|
||||
c: LazyClassContext,
|
||||
parentClassOrObject: KtPureClassOrObject,
|
||||
containingDeclaration: DeclarationDescriptor,
|
||||
name: Name,
|
||||
source: SourceElement,
|
||||
outerScope: LexicalScope,
|
||||
private val modality: Modality,
|
||||
private val visibility: Visibility,
|
||||
constructorVisibility: Visibility,
|
||||
private val kind: ClassKind,
|
||||
private val isCompanionObject: Boolean
|
||||
c: LazyClassContext,
|
||||
parentClassOrObject: KtPureClassOrObject,
|
||||
containingDeclaration: DeclarationDescriptor,
|
||||
name: Name,
|
||||
source: SourceElement,
|
||||
outerScope: LexicalScope,
|
||||
private val modality: Modality,
|
||||
private val visibility: Visibility,
|
||||
constructorVisibility: Visibility,
|
||||
private val kind: ClassKind,
|
||||
private val isCompanionObject: Boolean
|
||||
) : ClassDescriptorBase(c.storageManager, containingDeclaration, name, source, false), ClassDescriptorWithResolutionScopes {
|
||||
val syntheticDeclaration: KtPureClassOrObject = SyntheticDeclaration(parentClassOrObject, name.asString())
|
||||
|
||||
private val thisDescriptor: SyntheticClassOrObjectDescriptor get() = this // code readability
|
||||
private val typeConstructor = SyntheticTypeConstructor(c.storageManager)
|
||||
private val resolutionScopesSupport = ClassResolutionScopesSupport(thisDescriptor, c.storageManager, { outerScope })
|
||||
private val syntheticSupertypes = mutableListOf<KotlinType>().apply { c.syntheticResolveExtension.addSyntheticSupertypes(thisDescriptor, this) }
|
||||
private val unsubstitutedMemberScope = LazyClassMemberScope(c, SyntheticClassMemberDeclarationProvider(syntheticDeclaration), this, c.trace)
|
||||
private val syntheticSupertypes =
|
||||
mutableListOf<KotlinType>().apply { c.syntheticResolveExtension.addSyntheticSupertypes(thisDescriptor, this) }
|
||||
private val unsubstitutedMemberScope =
|
||||
LazyClassMemberScope(c, SyntheticClassMemberDeclarationProvider(syntheticDeclaration), this, c.trace)
|
||||
private val unsubstitutedPrimaryConstructor = createUnsubstitutedPrimaryConstructor(constructorVisibility)
|
||||
|
||||
override val annotations: Annotations get() = Annotations.EMPTY
|
||||
@@ -97,11 +99,15 @@ class SyntheticClassOrObjectDescriptor(
|
||||
|
||||
override fun getScopeForClassHeaderResolution(): LexicalScope = resolutionScopesSupport.scopeForClassHeaderResolution()
|
||||
override fun getScopeForConstructorHeaderResolution(): LexicalScope = resolutionScopesSupport.scopeForConstructorHeaderResolution()
|
||||
override fun getScopeForCompanionObjectHeaderResolution(): LexicalScope = resolutionScopesSupport.scopeForCompanionObjectHeaderResolution()
|
||||
override fun getScopeForMemberDeclarationResolution(): LexicalScope = resolutionScopesSupport.scopeForMemberDeclarationResolution()
|
||||
override fun getScopeForStaticMemberDeclarationResolution(): LexicalScope = resolutionScopesSupport.scopeForStaticMemberDeclarationResolution()
|
||||
override fun getScopeForCompanionObjectHeaderResolution(): LexicalScope =
|
||||
resolutionScopesSupport.scopeForCompanionObjectHeaderResolution()
|
||||
|
||||
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
|
||||
|
||||
@@ -121,7 +127,7 @@ class SyntheticClassOrObjectDescriptor(
|
||||
}
|
||||
|
||||
private class SyntheticClassMemberDeclarationProvider(
|
||||
override val correspondingClassOrObject: KtPureClassOrObject
|
||||
override val correspondingClassOrObject: KtPureClassOrObject
|
||||
) : ClassMemberDeclarationProvider {
|
||||
override val ownerInfo: KtClassLikeInfo? = null
|
||||
override fun getDeclarations(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): List<KtDeclaration> = emptyList()
|
||||
@@ -134,8 +140,8 @@ class SyntheticClassOrObjectDescriptor(
|
||||
}
|
||||
|
||||
internal inner class SyntheticDeclaration(
|
||||
private val _parent: KtPureElement,
|
||||
private val _name: String
|
||||
private val _parent: KtPureElement,
|
||||
private val _name: String
|
||||
) : KtPureClassOrObject {
|
||||
fun descriptor() = thisDescriptor
|
||||
|
||||
|
||||
@@ -28,14 +28,13 @@ import org.jetbrains.kotlin.utils.Printer
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.flatMapToNullable
|
||||
|
||||
class AllUnderImportScope(
|
||||
descriptor: DeclarationDescriptor,
|
||||
excludedImportNames: Collection<FqName>
|
||||
descriptor: DeclarationDescriptor,
|
||||
excludedImportNames: Collection<FqName>
|
||||
) : BaseImportingScope(null) {
|
||||
|
||||
private val scopes: List<MemberScope> = if (descriptor is ClassDescriptor) {
|
||||
listOf(descriptor.staticScope, descriptor.unsubstitutedInnerClassesScope)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
assert(descriptor is PackageViewDescriptor) {
|
||||
"Must be class or package view descriptor: $descriptor"
|
||||
}
|
||||
@@ -44,8 +43,7 @@ class AllUnderImportScope(
|
||||
|
||||
private val excludedNames: Set<Name> = if (excludedImportNames.isEmpty()) { // optimization
|
||||
emptySet<Name>()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val fqName = DescriptorUtils.getFqNameSafe(descriptor)
|
||||
// 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()
|
||||
@@ -54,21 +52,20 @@ class AllUnderImportScope(
|
||||
override fun computeImportedNames(): Set<Name>? = scopes.flatMapToNullable(hashSetOf(), MemberScope::computeAllNames)
|
||||
|
||||
override fun getContributedDescriptors(
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean,
|
||||
changeNamesForAliased: Boolean
|
||||
kindFilter: DescriptorKindFilter,
|
||||
nameFilter: (Name) -> Boolean,
|
||||
changeNamesForAliased: Boolean
|
||||
): Collection<DeclarationDescriptor> {
|
||||
val nameFilterToUse = if (excludedNames.isEmpty()) { // optimization
|
||||
nameFilter
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
{ it !in excludedNames && nameFilter(it) }
|
||||
}
|
||||
|
||||
val noPackagesKindFilter = kindFilter.withoutKinds(DescriptorKindFilter.PACKAGES_MASK)
|
||||
return scopes
|
||||
.flatMap { it.getContributedDescriptors(noPackagesKindFilter, nameFilterToUse) }
|
||||
.filter { it !is PackageViewDescriptor } // subpackages are not imported
|
||||
.flatMap { it.getContributedDescriptors(noPackagesKindFilter, nameFilterToUse) }
|
||||
.filter { it !is PackageViewDescriptor } // subpackages are not imported
|
||||
}
|
||||
|
||||
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? {
|
||||
|
||||
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import java.util.*
|
||||
|
||||
class CompositeBindingContext private constructor(
|
||||
private val delegates: LinkedHashSet<BindingContext>
|
||||
private val delegates: LinkedHashSet<BindingContext>
|
||||
) : BindingContext {
|
||||
override fun getType(expression: KtExpression): KotlinType? {
|
||||
return delegates.asSequence().map { it.getType(expression) }.firstOrNull { it != null }
|
||||
@@ -67,7 +67,7 @@ class CompositeBindingContext private constructor(
|
||||
}
|
||||
|
||||
private class CompositeDiagnostics(
|
||||
private val delegates: List<Diagnostics>
|
||||
private val delegates: List<Diagnostics>
|
||||
) : Diagnostics {
|
||||
|
||||
override fun iterator(): Iterator<Diagnostic> {
|
||||
|
||||
@@ -34,22 +34,18 @@ object DataClassDescriptorResolver {
|
||||
|
||||
private val COMPONENT_FUNCTION_NAME_PREFIX = "component"
|
||||
|
||||
fun createComponentName(index: Int): Name
|
||||
= Name.identifier(COMPONENT_FUNCTION_NAME_PREFIX + index)
|
||||
fun createComponentName(index: Int): Name = Name.identifier(COMPONENT_FUNCTION_NAME_PREFIX + index)
|
||||
|
||||
fun getComponentIndex(componentName: String): Int
|
||||
= componentName.substring(COMPONENT_FUNCTION_NAME_PREFIX.length).toInt()
|
||||
fun getComponentIndex(componentName: String): Int = componentName.substring(COMPONENT_FUNCTION_NAME_PREFIX.length).toInt()
|
||||
|
||||
fun isComponentLike(name: Name): Boolean
|
||||
= isComponentLike(name.asString())
|
||||
fun isComponentLike(name: Name): Boolean = isComponentLike(name.asString())
|
||||
|
||||
private fun isComponentLike(name: String): Boolean {
|
||||
if (!name.startsWith(COMPONENT_FUNCTION_NAME_PREFIX)) return false
|
||||
|
||||
try {
|
||||
getComponentIndex(name)
|
||||
}
|
||||
catch (e: NumberFormatException) {
|
||||
} catch (e: NumberFormatException) {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -57,58 +53,58 @@ object DataClassDescriptorResolver {
|
||||
}
|
||||
|
||||
fun createEqualsFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor =
|
||||
doCreateFunctionFromAny(classDescriptor, EQUALS_METHOD_NAME)
|
||||
doCreateFunctionFromAny(classDescriptor, EQUALS_METHOD_NAME)
|
||||
|
||||
fun createHashCodeFunctionDescriptor(classDescriptor: ClassDescriptor): SimpleFunctionDescriptor =
|
||||
doCreateFunctionFromAny(classDescriptor, HASH_CODE_METHOD_NAME)
|
||||
doCreateFunctionFromAny(classDescriptor, HASH_CODE_METHOD_NAME)
|
||||
|
||||
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 {
|
||||
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())
|
||||
.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS).single()
|
||||
.getContributedFunctions(name, NoLookupLocation.FROM_BUILTINS).single()
|
||||
|
||||
functionDescriptor.initialize(
|
||||
null,
|
||||
classDescriptor.thisAsReceiverParameter,
|
||||
functionFromAny.typeParameters,
|
||||
functionFromAny.valueParameters.map { it.copy(functionDescriptor, it.name, it.index) },
|
||||
functionFromAny.returnType,
|
||||
Modality.OPEN,
|
||||
Visibilities.PUBLIC
|
||||
null,
|
||||
classDescriptor.thisAsReceiverParameter,
|
||||
functionFromAny.typeParameters,
|
||||
functionFromAny.valueParameters.map { it.copy(functionDescriptor, it.name, it.index) },
|
||||
functionFromAny.returnType,
|
||||
Modality.OPEN,
|
||||
Visibilities.PUBLIC
|
||||
)
|
||||
|
||||
return functionDescriptor
|
||||
}
|
||||
|
||||
fun createComponentFunctionDescriptor(
|
||||
parameterIndex: Int,
|
||||
property: PropertyDescriptor,
|
||||
parameter: ValueParameterDescriptor,
|
||||
classDescriptor: ClassDescriptor,
|
||||
trace: BindingTrace
|
||||
parameterIndex: Int,
|
||||
property: PropertyDescriptor,
|
||||
parameter: ValueParameterDescriptor,
|
||||
classDescriptor: ClassDescriptor,
|
||||
trace: BindingTrace
|
||||
): SimpleFunctionDescriptor {
|
||||
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||
classDescriptor,
|
||||
Annotations.EMPTY,
|
||||
createComponentName(parameterIndex),
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
parameter.source
|
||||
classDescriptor,
|
||||
Annotations.EMPTY,
|
||||
createComponentName(parameterIndex),
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
parameter.source
|
||||
)
|
||||
|
||||
functionDescriptor.initialize(
|
||||
null,
|
||||
classDescriptor.thisAsReceiverParameter,
|
||||
emptyList<TypeParameterDescriptor>(),
|
||||
emptyList<ValueParameterDescriptor>(),
|
||||
property.type,
|
||||
Modality.FINAL,
|
||||
property.visibility
|
||||
null,
|
||||
classDescriptor.thisAsReceiverParameter,
|
||||
emptyList<TypeParameterDescriptor>(),
|
||||
emptyList<ValueParameterDescriptor>(),
|
||||
property.type,
|
||||
Modality.FINAL,
|
||||
property.visibility
|
||||
)
|
||||
functionDescriptor.isOperator = true
|
||||
|
||||
@@ -117,16 +113,16 @@ object DataClassDescriptorResolver {
|
||||
}
|
||||
|
||||
fun createCopyFunctionDescriptor(
|
||||
constructorParameters: Collection<ValueParameterDescriptor>,
|
||||
classDescriptor: ClassDescriptor,
|
||||
trace: BindingTrace
|
||||
constructorParameters: Collection<ValueParameterDescriptor>,
|
||||
classDescriptor: ClassDescriptor,
|
||||
trace: BindingTrace
|
||||
): SimpleFunctionDescriptor {
|
||||
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||
classDescriptor,
|
||||
Annotations.EMPTY,
|
||||
COPY_METHOD_NAME,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
classDescriptor.source
|
||||
classDescriptor,
|
||||
Annotations.EMPTY,
|
||||
COPY_METHOD_NAME,
|
||||
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||
classDescriptor.source
|
||||
)
|
||||
|
||||
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
|
||||
val declaresDefaultValue = propertyDescriptor != null
|
||||
val parameterDescriptor = ValueParameterDescriptorImpl(
|
||||
functionDescriptor, null, parameter.index, parameter.annotations, parameter.name, parameter.type, declaresDefaultValue,
|
||||
parameter.isCrossinline, parameter.isNoinline, parameter.varargElementType, parameter.source
|
||||
functionDescriptor, null, parameter.index, parameter.annotations, parameter.name, parameter.type, declaresDefaultValue,
|
||||
parameter.isCrossinline, parameter.isNoinline, parameter.varargElementType, parameter.source
|
||||
)
|
||||
parameterDescriptors.add(parameterDescriptor)
|
||||
if (declaresDefaultValue) {
|
||||
@@ -146,13 +142,13 @@ object DataClassDescriptorResolver {
|
||||
}
|
||||
|
||||
functionDescriptor.initialize(
|
||||
null,
|
||||
classDescriptor.thisAsReceiverParameter,
|
||||
emptyList<TypeParameterDescriptor>(),
|
||||
parameterDescriptors,
|
||||
classDescriptor.defaultType,
|
||||
Modality.FINAL,
|
||||
Visibilities.PUBLIC
|
||||
null,
|
||||
classDescriptor.thisAsReceiverParameter,
|
||||
emptyList<TypeParameterDescriptor>(),
|
||||
parameterDescriptors,
|
||||
classDescriptor.defaultType,
|
||||
Modality.FINAL,
|
||||
Visibilities.PUBLIC
|
||||
)
|
||||
|
||||
trace.record(BindingContext.DATA_CLASS_COPY_FUNCTION, classDescriptor, functionDescriptor)
|
||||
|
||||
@@ -38,8 +38,8 @@ import org.jetbrains.kotlin.utils.keysToMap
|
||||
import java.util.*
|
||||
|
||||
class DeclarationResolver(
|
||||
private val annotationResolver: AnnotationResolver,
|
||||
private val trace: BindingTrace
|
||||
private val annotationResolver: AnnotationResolver,
|
||||
private val trace: BindingTrace
|
||||
) {
|
||||
|
||||
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()) {
|
||||
if (fqName.isRoot) continue
|
||||
|
||||
// TODO: report error on expected class and actual val, or vice versa
|
||||
val (expected, actual) =
|
||||
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)) {
|
||||
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>()
|
||||
|
||||
descriptors.addIfNotNull(topLevelDescriptorProvider.getPackageFragment(fqName))
|
||||
|
||||
@@ -45,29 +45,29 @@ import org.jetbrains.kotlin.types.typeUtil.*
|
||||
import java.util.*
|
||||
|
||||
internal class DeclarationsCheckerBuilder(
|
||||
private val descriptorResolver: DescriptorResolver,
|
||||
private val originalModifiersChecker: ModifiersChecker,
|
||||
private val annotationChecker: AnnotationChecker,
|
||||
private val identifierChecker: IdentifierChecker,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val typeSpecificityComparator: TypeSpecificityComparator,
|
||||
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
|
||||
private val descriptorResolver: DescriptorResolver,
|
||||
private val originalModifiersChecker: ModifiersChecker,
|
||||
private val annotationChecker: AnnotationChecker,
|
||||
private val identifierChecker: IdentifierChecker,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val typeSpecificityComparator: TypeSpecificityComparator,
|
||||
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
|
||||
) {
|
||||
fun withTrace(trace: BindingTrace) = DeclarationsChecker(
|
||||
descriptorResolver, originalModifiersChecker, annotationChecker, identifierChecker, trace, languageVersionSettings,
|
||||
typeSpecificityComparator, diagnosticSuppressor
|
||||
descriptorResolver, originalModifiersChecker, annotationChecker, identifierChecker, trace, languageVersionSettings,
|
||||
typeSpecificityComparator, diagnosticSuppressor
|
||||
)
|
||||
}
|
||||
|
||||
class DeclarationsChecker(
|
||||
private val descriptorResolver: DescriptorResolver,
|
||||
modifiersChecker: ModifiersChecker,
|
||||
private val annotationChecker: AnnotationChecker,
|
||||
private val identifierChecker: IdentifierChecker,
|
||||
private val trace: BindingTrace,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
typeSpecificityComparator: TypeSpecificityComparator,
|
||||
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
|
||||
private val descriptorResolver: DescriptorResolver,
|
||||
modifiersChecker: ModifiersChecker,
|
||||
private val annotationChecker: AnnotationChecker,
|
||||
private val identifierChecker: IdentifierChecker,
|
||||
private val trace: BindingTrace,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
typeSpecificityComparator: TypeSpecificityComparator,
|
||||
private val diagnosticSuppressor: PlatformDiagnosticSuppressor
|
||||
) {
|
||||
|
||||
private val modifiersChecker = modifiersChecker.withTrace(trace)
|
||||
@@ -102,9 +102,9 @@ class DeclarationsChecker(
|
||||
}
|
||||
|
||||
val destructuringDeclarations = bodiesResolveContext.destructuringDeclarationEntries.entries
|
||||
.map { (entry, _) -> entry.parent }
|
||||
.filterIsInstance<KtDestructuringDeclaration>()
|
||||
.distinct()
|
||||
.map { (entry, _) -> entry.parent }
|
||||
.filterIsInstance<KtDestructuringDeclaration>()
|
||||
.distinct()
|
||||
|
||||
for (multiDeclaration in destructuringDeclarations) {
|
||||
modifiersChecker.checkModifiersForDestructuringDeclaration(multiDeclaration)
|
||||
@@ -143,7 +143,7 @@ class DeclarationsChecker(
|
||||
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"))
|
||||
}
|
||||
|
||||
@@ -151,7 +151,7 @@ class DeclarationsChecker(
|
||||
for (typeParameter in typeAliasDescriptor.declaredTypeParameters) {
|
||||
if (typeParameter !in usedTypeAliasParameters) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
@@ -180,31 +180,35 @@ class DeclarationsChecker(
|
||||
}
|
||||
|
||||
if (rhs.arguments.map { it.type.constructor.declarationDescriptor as? TypeParameterDescriptor } !=
|
||||
typeAliasDescriptor.declaredTypeParameters) {
|
||||
typeAliasDescriptor.declaredTypeParameters) {
|
||||
trace.report(ACTUAL_TYPE_ALIAS_WITH_COMPLEX_SUBSTITUTION.on(declaration))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
private fun getUsedTypeAliasParameters(type: KotlinType, typeAlias: TypeAliasDescriptor): Set<TypeParameterDescriptor> =
|
||||
type.constituentTypes().mapNotNullTo(HashSet()) {
|
||||
val descriptor = it.constructor.declarationDescriptor as? TypeParameterDescriptor
|
||||
descriptor?.takeIf { it.containingDeclaration == typeAlias }
|
||||
}
|
||||
type.constituentTypes().mapNotNullTo(HashSet()) {
|
||||
val descriptor = it.constructor.declarationDescriptor as? TypeParameterDescriptor
|
||||
descriptor?.takeIf { it.containingDeclaration == typeAlias }
|
||||
}
|
||||
|
||||
private class TypeAliasDeclarationCheckingReportStrategy(
|
||||
private val trace: BindingTrace,
|
||||
typeAliasDescriptor: TypeAliasDescriptor,
|
||||
declaration: KtTypeAlias
|
||||
private val trace: BindingTrace,
|
||||
typeAliasDescriptor: TypeAliasDescriptor,
|
||||
declaration: KtTypeAlias
|
||||
) : TypeAliasExpansionReportStrategy {
|
||||
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) {
|
||||
// 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))
|
||||
}
|
||||
|
||||
@@ -212,7 +216,12 @@ class DeclarationsChecker(
|
||||
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
|
||||
if (!argument.containsTypeAliasParameters() && !bound.containsTypeAliasParameters()) {
|
||||
trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(typeReference, bound, argument, typeParameter))
|
||||
@@ -272,8 +281,7 @@ class DeclarationsChecker(
|
||||
val classDescriptor = constructorDescriptor.containingDeclaration
|
||||
if (classDescriptor.kind == ClassKind.ENUM_CLASS) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
@@ -301,7 +309,8 @@ class DeclarationsChecker(
|
||||
is KtClass -> {
|
||||
checkClassButNotObject(classOrObject, classDescriptor)
|
||||
descriptorResolver.checkNamesInConstraints(
|
||||
classOrObject, classDescriptor, classDescriptor.scopeForClassHeaderResolution, trace)
|
||||
classOrObject, classDescriptor, classDescriptor.scopeForClassHeaderResolution, trace
|
||||
)
|
||||
}
|
||||
is KtObjectDeclaration -> {
|
||||
checkObject(classOrObject, classDescriptor)
|
||||
@@ -346,32 +355,31 @@ class DeclarationsChecker(
|
||||
}
|
||||
|
||||
private fun checkOnlyOneTypeParameterBound(
|
||||
descriptor: TypeParameterDescriptor, declaration: KtTypeParameter, owner: KtTypeParameterListOwner
|
||||
descriptor: TypeParameterDescriptor, declaration: KtTypeParameter, owner: KtTypeParameterListOwner
|
||||
) {
|
||||
val upperBounds = descriptor.upperBounds
|
||||
val (boundsWhichAreTypeParameters, otherBounds) = upperBounds
|
||||
.map(KotlinType::constructor)
|
||||
.partition { constructor -> constructor.declarationDescriptor is TypeParameterDescriptor }
|
||||
.let { pair -> pair.first.toSet() to pair.second.toSet() }
|
||||
.map(KotlinType::constructor)
|
||||
.partition { constructor -> constructor.declarationDescriptor is TypeParameterDescriptor }
|
||||
.let { pair -> pair.first.toSet() to pair.second.toSet() }
|
||||
if (boundsWhichAreTypeParameters.size > 1 || (boundsWhichAreTypeParameters.size == 1 && otherBounds.isNotEmpty())) {
|
||||
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),
|
||||
// report the diagnostic on that bound
|
||||
|
||||
val allBounds: List<Pair<KtTypeReference, KotlinType?>> =
|
||||
owner.typeConstraints
|
||||
.filter { constraint ->
|
||||
constraint.subjectTypeParameterName?.getReferencedNameAsName() == declaration.nameAsName
|
||||
}
|
||||
.mapNotNull { constraint -> constraint.boundTypeReference }
|
||||
.map { typeReference -> typeReference to trace.bindingContext.get(TYPE, typeReference) }
|
||||
owner.typeConstraints
|
||||
.filter { constraint ->
|
||||
constraint.subjectTypeParameterName?.getReferencedNameAsName() == declaration.nameAsName
|
||||
}
|
||||
.mapNotNull { constraint -> constraint.boundTypeReference }
|
||||
.map { typeReference -> typeReference to trace.bindingContext.get(TYPE, typeReference) }
|
||||
|
||||
val problematicBound =
|
||||
allBounds.firstOrNull { bound -> bound.second?.constructor != boundsWhichAreTypeParameters.first() }
|
||||
allBounds.firstOrNull { bound -> bound.second?.constructor != boundsWhichAreTypeParameters.first() }
|
||||
|
||||
problematicBound?.first ?: declaration
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
// Otherwise report the diagnostic on the type parameter declaration
|
||||
declaration
|
||||
}
|
||||
@@ -400,17 +408,20 @@ class DeclarationsChecker(
|
||||
if (conflictingTypes.size <= 1) continue
|
||||
|
||||
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) {
|
||||
val delegationSpecifierList = sourceElement.getSuperTypeList() ?: continue
|
||||
trace.report(INCONSISTENT_TYPE_PARAMETER_VALUES.on(
|
||||
trace.report(
|
||||
INCONSISTENT_TYPE_PARAMETER_VALUES.on(
|
||||
delegationSpecifierList, typeParameterDescriptor, containingDeclaration, conflictingTypes
|
||||
))
|
||||
}
|
||||
else if (sourceElement is KtTypeParameter) {
|
||||
trace.report(INCONSISTENT_TYPE_PARAMETER_BOUNDS.on(
|
||||
)
|
||||
)
|
||||
} else if (sourceElement is KtTypeParameter) {
|
||||
trace.report(
|
||||
INCONSISTENT_TYPE_PARAMETER_BOUNDS.on(
|
||||
sourceElement, typeParameterDescriptor, containingDeclaration, conflictingTypes
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -521,8 +532,7 @@ class DeclarationsChecker(
|
||||
for (parameter in aClass.primaryConstructorParameters) {
|
||||
if (!parameter.hasValOrVar()) {
|
||||
trace.report(MISSING_VAL_ON_ANNOTATION_PARAMETER.on(parameter))
|
||||
}
|
||||
else if (parameter.isMutable) {
|
||||
} else if (parameter.isMutable) {
|
||||
trace.report(VAR_ANNOTATION_PARAMETER.on(parameter))
|
||||
}
|
||||
}
|
||||
@@ -537,8 +547,7 @@ class DeclarationsChecker(
|
||||
if (member != null && member.hasModifier(KtTokens.OPEN_KEYWORD)) {
|
||||
if (classDescriptor.kind == ClassKind.OBJECT) {
|
||||
trace.report(NON_FINAL_MEMBER_IN_OBJECT.on(member))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
trace.report(NON_FINAL_MEMBER_IN_FINAL_CLASS.on(member))
|
||||
}
|
||||
}
|
||||
@@ -594,9 +603,9 @@ class DeclarationsChecker(
|
||||
}
|
||||
|
||||
private fun checkMemberProperty(
|
||||
property: KtProperty,
|
||||
propertyDescriptor: PropertyDescriptor,
|
||||
classDescriptor: ClassDescriptor
|
||||
property: KtProperty,
|
||||
propertyDescriptor: PropertyDescriptor,
|
||||
classDescriptor: ClassDescriptor
|
||||
) {
|
||||
val modifierList = property.modifierList
|
||||
|
||||
@@ -607,8 +616,7 @@ class DeclarationsChecker(
|
||||
trace.report(ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS.on(property, property.name ?: "", classDescriptor))
|
||||
return
|
||||
}
|
||||
}
|
||||
else if (classDescriptor.kind == ClassKind.INTERFACE &&
|
||||
} else if (classDescriptor.kind == ClassKind.INTERFACE &&
|
||||
modifierList.hasModifier(KtTokens.OPEN_KEYWORD) &&
|
||||
propertyDescriptor.modality == Modality.ABSTRACT) {
|
||||
trace.report(REDUNDANT_OPEN_IN_INTERFACE.on(property))
|
||||
@@ -659,35 +667,33 @@ class DeclarationsChecker(
|
||||
!backingFieldRequired -> trace.report(PROPERTY_INITIALIZER_NO_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) {
|
||||
trace.report(DELEGATED_PROPERTY_IN_INTERFACE.on(delegate))
|
||||
}
|
||||
else if (isExpect) {
|
||||
} else if (isExpect) {
|
||||
trace.report(EXPECTED_DELEGATED_PROPERTY.on(delegate))
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val isUninitialized = trace.bindingContext.get(BindingContext.IS_UNINITIALIZED, propertyDescriptor) ?: false
|
||||
val isExternal = propertyDescriptor.isEffectivelyExternal()
|
||||
if (backingFieldRequired && !inInterface && !propertyDescriptor.isLateInit && !isExpect && isUninitialized && !isExternal) {
|
||||
if (propertyDescriptor.extensionReceiverParameter != null && !hasAccessorImplementation) {
|
||||
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) {
|
||||
trace.report(MUST_BE_INITIALIZED.on(property))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property))
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (property.typeReference == null && !languageVersionSettings.supportsFeature(LanguageFeature.ShortSyntaxForPropertyGetters)) {
|
||||
trace.report(Errors.UNSUPPORTED_FEATURE.on(property, LanguageFeature.ShortSyntaxForPropertyGetters to languageVersionSettings))
|
||||
}
|
||||
else if (noExplicitTypeOrGetterType(property)) {
|
||||
} else if (property.typeReference == null && !languageVersionSettings.supportsFeature(LanguageFeature.ShortSyntaxForPropertyGetters)) {
|
||||
trace.report(
|
||||
Errors.UNSUPPORTED_FEATURE.on(
|
||||
property,
|
||||
LanguageFeature.ShortSyntaxForPropertyGetters to languageVersionSettings
|
||||
)
|
||||
)
|
||||
} else if (noExplicitTypeOrGetterType(property)) {
|
||||
trace.report(PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(property))
|
||||
}
|
||||
|
||||
@@ -703,7 +709,7 @@ class DeclarationsChecker(
|
||||
}
|
||||
|
||||
private fun noExplicitTypeOrGetterType(property: KtProperty) =
|
||||
property.typeReference == null
|
||||
property.typeReference == null
|
||||
&& (property.getter == null || (property.getter!!.hasBlockBody() && property.getter!!.returnTypeReference == null))
|
||||
|
||||
fun checkFunction(function: KtNamedFunction, functionDescriptor: SimpleFunctionDescriptor) {
|
||||
@@ -744,8 +750,7 @@ class DeclarationsChecker(
|
||||
diagnosticSuppressor.shouldReportNoBody(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 &&
|
||||
diagnosticSuppressor.shouldReportNoBody(functionDescriptor)) {
|
||||
trace.report(NON_MEMBER_FUNCTION_NO_BODY.on(function, functionDescriptor))
|
||||
@@ -779,16 +784,15 @@ class DeclarationsChecker(
|
||||
if (declaration.typeReference == null) {
|
||||
if (it.isNothing() && !declaration.hasModifier(KtTokens.OVERRIDE_KEYWORD)) {
|
||||
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 }) {
|
||||
trace.report(IMPLICIT_INTERSECTION_TYPE.on(target, it))
|
||||
}
|
||||
}
|
||||
else if (it.isNothing() && it is AbbreviatedType) {
|
||||
} else if (it.isNothing() && it is AbbreviatedType) {
|
||||
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) {
|
||||
modifiersChecker.checkModifiersForDeclaration(accessor, accessorDescriptor)
|
||||
identifierChecker.checkDeclaration(accessor, trace)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
modifiersChecker.runDeclarationCheckers(property, accessorDescriptor)
|
||||
}
|
||||
}
|
||||
@@ -816,9 +819,9 @@ class DeclarationsChecker(
|
||||
}
|
||||
|
||||
private fun checkAccessor(
|
||||
propertyDescriptor: PropertyDescriptor,
|
||||
accessor: KtPropertyAccessor?,
|
||||
accessorDescriptor: PropertyAccessorDescriptor?
|
||||
propertyDescriptor: PropertyDescriptor,
|
||||
accessor: KtPropertyAccessor?,
|
||||
accessorDescriptor: PropertyAccessorDescriptor?
|
||||
) {
|
||||
if (accessor == null || accessorDescriptor == null) return
|
||||
if (propertyDescriptor.isExpect && accessor.hasBody()) {
|
||||
@@ -827,29 +830,25 @@ class DeclarationsChecker(
|
||||
|
||||
val accessorModifierList = accessor.modifierList ?: return
|
||||
val tokens = modifiersChecker.getTokensCorrespondingToModifiers(
|
||||
accessorModifierList,
|
||||
setOf(KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.PRIVATE_KEYWORD, KtTokens.INTERNAL_KEYWORD)
|
||||
accessorModifierList,
|
||||
setOf(KtTokens.PUBLIC_KEYWORD, KtTokens.PROTECTED_KEYWORD, KtTokens.PRIVATE_KEYWORD, KtTokens.INTERNAL_KEYWORD)
|
||||
)
|
||||
if (accessor.isGetter) {
|
||||
if (accessorDescriptor.visibility != propertyDescriptor.visibility) {
|
||||
reportVisibilityModifierDiagnostics(tokens.values, Errors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
reportVisibilityModifierDiagnostics(tokens.values, Errors.REDUNDANT_MODIFIER_IN_GETTER)
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (propertyDescriptor.isOverridable
|
||||
&& accessorDescriptor.visibility == Visibilities.PRIVATE
|
||||
&& propertyDescriptor.visibility != Visibilities.PRIVATE) {
|
||||
if (propertyDescriptor.modality == Modality.ABSTRACT) {
|
||||
reportVisibilityModifierDiagnostics(tokens.values, Errors.PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
reportVisibilityModifierDiagnostics(tokens.values, Errors.PRIVATE_SETTER_FOR_OPEN_PROPERTY)
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val compare = Visibilities.compare(accessorDescriptor.visibility, propertyDescriptor.visibility)
|
||||
if (compare == null || compare > 0) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
assert(DescriptorUtils.isInterface(enumClass)) { "Enum entry should be declared in enum class: " + enumEntryClass }
|
||||
}
|
||||
}
|
||||
@@ -922,7 +920,10 @@ class DeclarationsChecker(
|
||||
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) {
|
||||
val containingDeclaration = overridden.containingDeclaration
|
||||
if (containingDeclaration !is ClassDescriptor) continue
|
||||
|
||||
@@ -33,14 +33,14 @@ import org.jetbrains.kotlin.types.isError
|
||||
import org.jetbrains.kotlin.utils.keysToMapExceptNulls
|
||||
|
||||
class DelegationResolver<T : CallableMemberDescriptor> private constructor(
|
||||
private val classOrObject: KtPureClassOrObject,
|
||||
private val ownerDescriptor: ClassDescriptor,
|
||||
private val existingMembers: Collection<CallableDescriptor>,
|
||||
private val trace: BindingTrace,
|
||||
private val memberExtractor: MemberExtractor<T>,
|
||||
private val typeResolver: TypeResolver,
|
||||
private val delegationFilter: DelegationFilter,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
private val classOrObject: KtPureClassOrObject,
|
||||
private val ownerDescriptor: ClassDescriptor,
|
||||
private val existingMembers: Collection<CallableDescriptor>,
|
||||
private val trace: BindingTrace,
|
||||
private val memberExtractor: MemberExtractor<T>,
|
||||
private val typeResolver: TypeResolver,
|
||||
private val delegationFilter: DelegationFilter,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
|
||||
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> =
|
||||
generateDelegationCandidates(delegatedInterfaceType).filter { candidate ->
|
||||
!isOverridingAnyOf(candidate, existingMembers) &&
|
||||
!checkClashWithOtherDelegatedMember(candidate, existingDelegates)
|
||||
}
|
||||
generateDelegationCandidates(delegatedInterfaceType).filter { candidate ->
|
||||
!isOverridingAnyOf(candidate, existingMembers) &&
|
||||
!checkClashWithOtherDelegatedMember(candidate, existingDelegates)
|
||||
}
|
||||
|
||||
private fun generateDelegationCandidates(delegatedInterfaceType: KotlinType): Collection<T> =
|
||||
getDelegatableMembers(delegatedInterfaceType).map { memberDescriptor ->
|
||||
val newModality = if (memberDescriptor.modality == Modality.ABSTRACT) Modality.OPEN else memberDescriptor.modality
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
memberDescriptor.newCopyBuilder()
|
||||
.setOwner(ownerDescriptor)
|
||||
.setDispatchReceiverParameter(ownerDescriptor.thisAsReceiverParameter)
|
||||
.setModality(newModality)
|
||||
.setVisibility(Visibilities.INHERITED)
|
||||
.setKind(DELEGATION)
|
||||
.setCopyOverrides(false)
|
||||
.build() as T
|
||||
}
|
||||
getDelegatableMembers(delegatedInterfaceType).map { memberDescriptor ->
|
||||
val newModality = if (memberDescriptor.modality == Modality.ABSTRACT) Modality.OPEN else memberDescriptor.modality
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
memberDescriptor.newCopyBuilder()
|
||||
.setOwner(ownerDescriptor)
|
||||
.setDispatchReceiverParameter(ownerDescriptor.thisAsReceiverParameter)
|
||||
.setModality(newModality)
|
||||
.setVisibility(Visibilities.INHERITED)
|
||||
.setKind(DELEGATION)
|
||||
.setCopyOverrides(false)
|
||||
.build() as T
|
||||
}
|
||||
|
||||
private fun checkClashWithOtherDelegatedMember(candidate: T, delegatedMembers: Collection<T>): Boolean {
|
||||
val alreadyDelegated = delegatedMembers.firstOrNull { isOverridableBy(it, candidate) }
|
||||
@@ -92,16 +92,16 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
|
||||
|
||||
|
||||
private fun getDelegatableMembers(interfaceType: KotlinType): Collection<T> =
|
||||
memberExtractor.getMembersByType(interfaceType).filter { descriptor ->
|
||||
descriptor.isOverridable &&
|
||||
(descriptor.kind.isReal || !descriptor.overridesClassMembersOnly()) &&
|
||||
delegationFilter.filter(descriptor, languageVersionSettings)
|
||||
}
|
||||
memberExtractor.getMembersByType(interfaceType).filter { descriptor ->
|
||||
descriptor.isOverridable &&
|
||||
(descriptor.kind.isReal || !descriptor.overridesClassMembersOnly()) &&
|
||||
delegationFilter.filter(descriptor, languageVersionSettings)
|
||||
}
|
||||
|
||||
private fun T.overridesClassMembersOnly() =
|
||||
DescriptorUtils.getAllOverriddenDeclarations(this).all {
|
||||
DescriptorUtils.isClass(it.containingDeclaration)
|
||||
}
|
||||
DescriptorUtils.getAllOverriddenDeclarations(this).all {
|
||||
DescriptorUtils.isClass(it.containingDeclaration)
|
||||
}
|
||||
|
||||
interface MemberExtractor<out T : CallableMemberDescriptor> {
|
||||
fun getMembersByType(type: KotlinType): Collection<T>
|
||||
@@ -113,26 +113,35 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
|
||||
|
||||
companion object {
|
||||
fun <T : CallableMemberDescriptor> generateDelegatedMembers(
|
||||
classOrObject: KtPureClassOrObject,
|
||||
ownerDescriptor: ClassDescriptor,
|
||||
existingMembers: Collection<CallableDescriptor>,
|
||||
trace: BindingTrace,
|
||||
memberExtractor: MemberExtractor<T>,
|
||||
typeResolver: TypeResolver,
|
||||
delegationFilter: DelegationFilter,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
classOrObject: KtPureClassOrObject,
|
||||
ownerDescriptor: ClassDescriptor,
|
||||
existingMembers: Collection<CallableDescriptor>,
|
||||
trace: BindingTrace,
|
||||
memberExtractor: MemberExtractor<T>,
|
||||
typeResolver: TypeResolver,
|
||||
delegationFilter: DelegationFilter,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): Collection<T> =
|
||||
DelegationResolver(classOrObject, ownerDescriptor, existingMembers, trace, memberExtractor, typeResolver, delegationFilter, languageVersionSettings)
|
||||
.generateDelegatedMembers()
|
||||
DelegationResolver(
|
||||
classOrObject,
|
||||
ownerDescriptor,
|
||||
existingMembers,
|
||||
trace,
|
||||
memberExtractor,
|
||||
typeResolver,
|
||||
delegationFilter,
|
||||
languageVersionSettings
|
||||
)
|
||||
.generateDelegatedMembers()
|
||||
|
||||
private fun isOverridingAnyOf(
|
||||
candidate: CallableMemberDescriptor,
|
||||
possiblyOverriddenBy: Collection<CallableDescriptor>
|
||||
candidate: CallableMemberDescriptor,
|
||||
possiblyOverriddenBy: Collection<CallableDescriptor>
|
||||
): Boolean =
|
||||
possiblyOverriddenBy.any { isOverridableBy(it, candidate) }
|
||||
possiblyOverriddenBy.any { isOverridableBy(it, candidate) }
|
||||
|
||||
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
|
||||
// descriptor = Foo
|
||||
@@ -140,34 +149,34 @@ class DelegationResolver<T : CallableMemberDescriptor> private constructor(
|
||||
// delegateExpressionType = typeof(baz)
|
||||
// return Map<member of Foo, corresponding member of typeOf(baz)>
|
||||
fun getDelegates(
|
||||
descriptor: ClassDescriptor,
|
||||
toInterface: ClassDescriptor,
|
||||
delegateExpressionType: KotlinType? = null
|
||||
descriptor: ClassDescriptor,
|
||||
toInterface: ClassDescriptor,
|
||||
delegateExpressionType: KotlinType? = null
|
||||
): Map<CallableMemberDescriptor, CallableMemberDescriptor> {
|
||||
if (delegateExpressionType?.isDynamic() ?: false) return emptyMap()
|
||||
|
||||
val delegatedMembers = descriptor.defaultType.memberScope.getContributedDescriptors().asSequence()
|
||||
.filterIsInstance<CallableMemberDescriptor>()
|
||||
.filter { it.kind == CallableMemberDescriptor.Kind.DELEGATION }
|
||||
.asIterable()
|
||||
.sortedWith(MemberComparator.INSTANCE)
|
||||
.filterIsInstance<CallableMemberDescriptor>()
|
||||
.filter { it.kind == CallableMemberDescriptor.Kind.DELEGATION }
|
||||
.asIterable()
|
||||
.sortedWith(MemberComparator.INSTANCE)
|
||||
|
||||
return delegatedMembers
|
||||
.keysToMapExceptNulls { delegatingMember ->
|
||||
val actualDelegates = DescriptorUtils.getAllOverriddenDescriptors(delegatingMember)
|
||||
.filter { it.containingDeclaration == toInterface }
|
||||
.map { overriddenDescriptor ->
|
||||
val scope = (delegateExpressionType ?: toInterface.defaultType).memberScope
|
||||
val name = overriddenDescriptor.name
|
||||
.keysToMapExceptNulls { delegatingMember ->
|
||||
val actualDelegates = DescriptorUtils.getAllOverriddenDescriptors(delegatingMember)
|
||||
.filter { it.containingDeclaration == toInterface }
|
||||
.map { overriddenDescriptor ->
|
||||
val scope = (delegateExpressionType ?: toInterface.defaultType).memberScope
|
||||
val name = overriddenDescriptor.name
|
||||
|
||||
// this is the actual member of delegateExpressionType that we are delegating to
|
||||
(scope.getContributedFunctions(name, NoLookupLocation.WHEN_CHECK_OVERRIDES) +
|
||||
scope.getContributedVariables(name, NoLookupLocation.WHEN_CHECK_OVERRIDES))
|
||||
.firstOrNull { it == overriddenDescriptor || OverridingUtil.overrides(it, overriddenDescriptor) }
|
||||
}
|
||||
// this is the actual member of delegateExpressionType that we are delegating to
|
||||
(scope.getContributedFunctions(name, NoLookupLocation.WHEN_CHECK_OVERRIDES) +
|
||||
scope.getContributedVariables(name, NoLookupLocation.WHEN_CHECK_OVERRIDES))
|
||||
.firstOrNull { it == overriddenDescriptor || OverridingUtil.overrides(it, overriddenDescriptor) }
|
||||
}
|
||||
|
||||
actualDelegates.firstOrNull()
|
||||
}
|
||||
actualDelegates.firstOrNull()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,14 +47,16 @@ object DescriptorToSourceUtils {
|
||||
result.add(descriptor)
|
||||
}
|
||||
|
||||
@JvmStatic fun getEffectiveReferencedDescriptors(descriptor: DeclarationDescriptor): Collection<DeclarationDescriptor> {
|
||||
@JvmStatic
|
||||
fun getEffectiveReferencedDescriptors(descriptor: DeclarationDescriptor): Collection<DeclarationDescriptor> {
|
||||
val result = ArrayList<DeclarationDescriptor>()
|
||||
collectEffectiveReferencedDescriptors(result, descriptor.original)
|
||||
return result
|
||||
}
|
||||
|
||||
// TODO Fix in descriptor
|
||||
@JvmStatic private fun getSourceForExtensionReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor): PsiElement? {
|
||||
@JvmStatic
|
||||
private fun getSourceForExtensionReceiverParameterDescriptor(descriptor: ReceiverParameterDescriptor): PsiElement? {
|
||||
// Only for extension receivers
|
||||
if (descriptor.source != SourceElement.NO_SOURCE || descriptor.value !is ExtensionReceiver) return null
|
||||
val containingDeclaration = descriptor.containingDeclaration as? CallableDescriptor ?: return null
|
||||
@@ -62,7 +64,8 @@ object DescriptorToSourceUtils {
|
||||
return psi.receiverTypeReference
|
||||
}
|
||||
|
||||
@JvmStatic fun getSourceFromDescriptor(descriptor: DeclarationDescriptor): PsiElement? {
|
||||
@JvmStatic
|
||||
fun getSourceFromDescriptor(descriptor: DeclarationDescriptor): PsiElement? {
|
||||
if (descriptor is ReceiverParameterDescriptor) {
|
||||
getSourceForExtensionReceiverParameterDescriptor(descriptor)?.let { return it }
|
||||
}
|
||||
@@ -70,7 +73,8 @@ object DescriptorToSourceUtils {
|
||||
return (descriptor as? DeclarationDescriptorWithSource)?.source?.getPsi()
|
||||
}
|
||||
|
||||
@JvmStatic fun getSourceFromAnnotation(descriptor: AnnotationDescriptor): KtAnnotationEntry? {
|
||||
@JvmStatic
|
||||
fun getSourceFromAnnotation(descriptor: AnnotationDescriptor): 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
|
||||
// with multiple declarations), returns null. It can't find declarations in builtins or decompiled code.
|
||||
// In IDE, use DescriptorToSourceUtilsIde instead.
|
||||
@JvmStatic fun descriptorToDeclaration(descriptor: DeclarationDescriptor): PsiElement? {
|
||||
@JvmStatic
|
||||
fun descriptorToDeclaration(descriptor: DeclarationDescriptor): PsiElement? {
|
||||
val effectiveReferencedDescriptors = getEffectiveReferencedDescriptors(descriptor)
|
||||
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
|
||||
// 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
|
||||
|
||||
@@ -38,16 +38,17 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
|
||||
return result and checkFunction(constructor, constructorDescriptor)
|
||||
}
|
||||
|
||||
fun checkDeclarationWithVisibility(modifierListOwner: KtModifierListOwner,
|
||||
descriptor: DeclarationDescriptorWithVisibility,
|
||||
visibility: Visibility
|
||||
) : Boolean {
|
||||
fun checkDeclarationWithVisibility(
|
||||
modifierListOwner: KtModifierListOwner,
|
||||
descriptor: DeclarationDescriptorWithVisibility,
|
||||
visibility: Visibility
|
||||
): Boolean {
|
||||
return when {
|
||||
modifierListOwner is KtFunction &&
|
||||
descriptor is FunctionDescriptor -> checkFunction(modifierListOwner, descriptor, visibility)
|
||||
descriptor is FunctionDescriptor -> checkFunction(modifierListOwner, descriptor, visibility)
|
||||
|
||||
modifierListOwner is KtProperty &&
|
||||
descriptor is PropertyDescriptor -> checkProperty(modifierListOwner, descriptor, visibility)
|
||||
descriptor is PropertyDescriptor -> checkProperty(modifierListOwner, descriptor, visibility)
|
||||
|
||||
else -> true
|
||||
}
|
||||
@@ -60,48 +61,66 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
|
||||
val typeAliasVisibility = typeAliasDescriptor.effectiveVisibility()
|
||||
val restricting = expandedType.leastPermissiveDescriptor(typeAliasVisibility)
|
||||
if (restricting != null) {
|
||||
trace.report(Errors.EXPOSED_TYPEALIAS_EXPANDED_TYPE.on(typeAlias.nameIdentifier ?: typeAlias,
|
||||
typeAliasVisibility, restricting, restricting.effectiveVisibility()))
|
||||
trace.report(
|
||||
Errors.EXPOSED_TYPEALIAS_EXPANDED_TYPE.on(
|
||||
typeAlias.nameIdentifier ?: typeAlias,
|
||||
typeAliasVisibility, restricting, restricting.effectiveVisibility()
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun checkFunction(function: KtFunction,
|
||||
functionDescriptor: FunctionDescriptor,
|
||||
// for checking situation with modified basic visibility
|
||||
visibility: Visibility = functionDescriptor.visibility
|
||||
fun checkFunction(
|
||||
function: KtFunction,
|
||||
functionDescriptor: FunctionDescriptor,
|
||||
// for checking situation with modified basic visibility
|
||||
visibility: Visibility = functionDescriptor.visibility
|
||||
): Boolean {
|
||||
val functionVisibility = functionDescriptor.effectiveVisibility(visibility)
|
||||
var result = true
|
||||
if (function !is KtConstructor<*>) {
|
||||
val restricting = functionDescriptor.returnType?.leastPermissiveDescriptor(functionVisibility)
|
||||
if (restricting != null) {
|
||||
trace.report(Errors.EXPOSED_FUNCTION_RETURN_TYPE.on(function.nameIdentifier ?: function, functionVisibility,
|
||||
restricting, restricting.effectiveVisibility()))
|
||||
trace.report(
|
||||
Errors.EXPOSED_FUNCTION_RETURN_TYPE.on(
|
||||
function.nameIdentifier ?: function, functionVisibility,
|
||||
restricting, restricting.effectiveVisibility()
|
||||
)
|
||||
)
|
||||
result = false
|
||||
}
|
||||
}
|
||||
functionDescriptor.valueParameters.forEachIndexed { i, parameterDescriptor ->
|
||||
val restricting = parameterDescriptor.type.leastPermissiveDescriptor(functionVisibility)
|
||||
if (restricting != null && i < function.valueParameters.size) {
|
||||
trace.report(Errors.EXPOSED_PARAMETER_TYPE.on(function.valueParameters[i], functionVisibility,
|
||||
restricting, restricting.effectiveVisibility()))
|
||||
trace.report(
|
||||
Errors.EXPOSED_PARAMETER_TYPE.on(
|
||||
function.valueParameters[i], functionVisibility,
|
||||
restricting, restricting.effectiveVisibility()
|
||||
)
|
||||
)
|
||||
result = false
|
||||
}
|
||||
}
|
||||
return result and checkMemberReceiver(function.receiverTypeReference, functionDescriptor)
|
||||
}
|
||||
|
||||
fun checkProperty(property: KtProperty,
|
||||
propertyDescriptor: PropertyDescriptor,
|
||||
// for checking situation with modified basic visibility
|
||||
visibility: Visibility = propertyDescriptor.visibility
|
||||
fun checkProperty(
|
||||
property: KtProperty,
|
||||
propertyDescriptor: PropertyDescriptor,
|
||||
// for checking situation with modified basic visibility
|
||||
visibility: Visibility = propertyDescriptor.visibility
|
||||
): Boolean {
|
||||
val propertyVisibility = propertyDescriptor.effectiveVisibility(visibility)
|
||||
val restricting = propertyDescriptor.type.leastPermissiveDescriptor(propertyVisibility)
|
||||
var result = true
|
||||
if (restricting != null) {
|
||||
trace.report(Errors.EXPOSED_PROPERTY_TYPE.on(property.nameIdentifier ?: property, propertyVisibility,
|
||||
restricting, restricting.effectiveVisibility()))
|
||||
trace.report(
|
||||
Errors.EXPOSED_PROPERTY_TYPE.on(
|
||||
property.nameIdentifier ?: property, propertyVisibility,
|
||||
restricting, restricting.effectiveVisibility()
|
||||
)
|
||||
)
|
||||
result = false
|
||||
}
|
||||
return result and checkMemberReceiver(property.receiverTypeReference, propertyDescriptor)
|
||||
@@ -113,8 +132,12 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
|
||||
val memberVisibility = memberDescriptor.effectiveVisibility()
|
||||
val restricting = receiverParameterDescriptor.type.leastPermissiveDescriptor(memberVisibility)
|
||||
if (restricting != null) {
|
||||
trace.report(Errors.EXPOSED_RECEIVER_TYPE.on(typeReference, memberVisibility,
|
||||
restricting, restricting.effectiveVisibility()))
|
||||
trace.report(
|
||||
Errors.EXPOSED_RECEIVER_TYPE.on(
|
||||
typeReference, memberVisibility,
|
||||
restricting, restricting.effectiveVisibility()
|
||||
)
|
||||
)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
@@ -135,12 +158,19 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
|
||||
val restricting = superType.leastPermissiveDescriptor(classVisibility)
|
||||
if (restricting != null) {
|
||||
if (isInterface) {
|
||||
trace.report(Errors.EXPOSED_SUPER_INTERFACE.on(delegationList[i], classVisibility,
|
||||
restricting, restricting.effectiveVisibility()))
|
||||
}
|
||||
else {
|
||||
trace.report(Errors.EXPOSED_SUPER_CLASS.on(delegationList[i], classVisibility,
|
||||
restricting, restricting.effectiveVisibility()))
|
||||
trace.report(
|
||||
Errors.EXPOSED_SUPER_INTERFACE.on(
|
||||
delegationList[i], classVisibility,
|
||||
restricting, restricting.effectiveVisibility()
|
||||
)
|
||||
)
|
||||
} else {
|
||||
trace.report(
|
||||
Errors.EXPOSED_SUPER_CLASS.on(
|
||||
delegationList[i], classVisibility,
|
||||
restricting, restricting.effectiveVisibility()
|
||||
)
|
||||
)
|
||||
}
|
||||
result = false
|
||||
}
|
||||
@@ -157,8 +187,12 @@ class ExposedVisibilityChecker(private val trace: DiagnosticSink = DO_NOTHING) {
|
||||
for (upperBound in typeParameterDescriptor.upperBounds) {
|
||||
val restricting = upperBound.leastPermissiveDescriptor(classVisibility)
|
||||
if (restricting != null) {
|
||||
trace.report(Errors.EXPOSED_TYPE_PARAMETER_BOUND.on(typeParameterList[i], classVisibility,
|
||||
restricting, restricting.effectiveVisibility()))
|
||||
trace.report(
|
||||
Errors.EXPOSED_TYPE_PARAMETER_BOUND.on(
|
||||
typeParameterList[i], classVisibility,
|
||||
restricting, restricting.effectiveVisibility()
|
||||
)
|
||||
)
|
||||
result = false
|
||||
break
|
||||
}
|
||||
|
||||
@@ -34,27 +34,27 @@ import org.jetbrains.kotlin.resolve.lazy.descriptors.LazyScriptDescriptor
|
||||
import java.util.*
|
||||
|
||||
class LazyTopDownAnalyzer(
|
||||
private val trace: BindingTrace,
|
||||
private val declarationResolver: DeclarationResolver,
|
||||
private val overrideResolver: OverrideResolver,
|
||||
private val overloadResolver: OverloadResolver,
|
||||
private val varianceChecker: VarianceChecker,
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
private val lazyDeclarationResolver: LazyDeclarationResolver,
|
||||
private val bodyResolver: BodyResolver,
|
||||
private val topLevelDescriptorProvider: TopLevelDescriptorProvider,
|
||||
private val fileScopeProvider: FileScopeProvider,
|
||||
private val declarationScopeProvider: DeclarationScopeProvider,
|
||||
private val qualifiedExpressionResolver: QualifiedExpressionResolver,
|
||||
private val identifierChecker: IdentifierChecker,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val deprecationResolver: DeprecationResolver,
|
||||
private val classifierUsageCheckers: Iterable<ClassifierUsageChecker>
|
||||
private val trace: BindingTrace,
|
||||
private val declarationResolver: DeclarationResolver,
|
||||
private val overrideResolver: OverrideResolver,
|
||||
private val overloadResolver: OverloadResolver,
|
||||
private val varianceChecker: VarianceChecker,
|
||||
private val moduleDescriptor: ModuleDescriptor,
|
||||
private val lazyDeclarationResolver: LazyDeclarationResolver,
|
||||
private val bodyResolver: BodyResolver,
|
||||
private val topLevelDescriptorProvider: TopLevelDescriptorProvider,
|
||||
private val fileScopeProvider: FileScopeProvider,
|
||||
private val declarationScopeProvider: DeclarationScopeProvider,
|
||||
private val qualifiedExpressionResolver: QualifiedExpressionResolver,
|
||||
private val identifierChecker: IdentifierChecker,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val deprecationResolver: DeprecationResolver,
|
||||
private val classifierUsageCheckers: Iterable<ClassifierUsageChecker>
|
||||
) {
|
||||
fun analyzeDeclarations(
|
||||
topDownAnalysisMode: TopDownAnalysisMode,
|
||||
declarations: Collection<PsiElement>,
|
||||
outerDataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY
|
||||
topDownAnalysisMode: TopDownAnalysisMode,
|
||||
declarations: Collection<PsiElement>,
|
||||
outerDataFlowInfo: DataFlowInfo = DataFlowInfo.EMPTY
|
||||
): TopDownAnalysisContext {
|
||||
val c = TopDownAnalysisContext(topDownAnalysisMode, outerDataFlowInfo, declarationScopeProvider)
|
||||
|
||||
@@ -82,8 +82,8 @@ class LazyTopDownAnalyzer(
|
||||
|
||||
override fun visitScript(script: KtScript) {
|
||||
c.scripts.put(
|
||||
script,
|
||||
lazyDeclarationResolver.getScriptDescriptor(script, KotlinLookupLocation(script)) as LazyScriptDescriptor
|
||||
script,
|
||||
lazyDeclarationResolver.getScriptDescriptor(script, KotlinLookupLocation(script)) as LazyScriptDescriptor
|
||||
)
|
||||
registerDeclarations(script.declarations)
|
||||
}
|
||||
@@ -109,8 +109,10 @@ class LazyTopDownAnalyzer(
|
||||
}
|
||||
|
||||
override fun visitClassOrObject(classOrObject: KtClassOrObject) {
|
||||
val location = if (classOrObject.isTopLevel()) KotlinLookupLocation(classOrObject) else NoLookupLocation.WHEN_RESOLVE_DECLARATION
|
||||
val descriptor = lazyDeclarationResolver.getClassDescriptor(classOrObject, location) as ClassDescriptorWithResolutionScopes
|
||||
val location =
|
||||
if (classOrObject.isTopLevel()) KotlinLookupLocation(classOrObject) else NoLookupLocation.WHEN_RESOLVE_DECLARATION
|
||||
val descriptor =
|
||||
lazyDeclarationResolver.getClassDescriptor(classOrObject, location) as ClassDescriptorWithResolutionScopes
|
||||
|
||||
c.declaredClasses.put(classOrObject, descriptor)
|
||||
registerDeclarations(classOrObject.declarations)
|
||||
@@ -127,12 +129,10 @@ class LazyTopDownAnalyzer(
|
||||
trace.report(MANY_COMPANION_OBJECTS.on(jetDeclaration))
|
||||
}
|
||||
companionObjectAlreadyFound = true
|
||||
}
|
||||
else if (jetDeclaration is KtSecondaryConstructor) {
|
||||
} else if (jetDeclaration is KtSecondaryConstructor) {
|
||||
if (DescriptorUtils.isSingletonOrAnonymousObject(classDescriptor)) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
@@ -147,13 +147,19 @@ class LazyTopDownAnalyzer(
|
||||
private fun registerPrimaryConstructorParameters(klass: KtClass) {
|
||||
for (jetParameter in klass.primaryConstructorParameters) {
|
||||
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) {
|
||||
c.secondaryConstructors.put(constructor, lazyDeclarationResolver.resolveToDescriptor(constructor) as ClassConstructorDescriptor)
|
||||
c.secondaryConstructors.put(
|
||||
constructor,
|
||||
lazyDeclarationResolver.resolveToDescriptor(constructor) as ClassConstructorDescriptor
|
||||
)
|
||||
}
|
||||
|
||||
override fun visitEnumEntry(enumEntry: KtEnumEntry) {
|
||||
@@ -165,7 +171,8 @@ class LazyTopDownAnalyzer(
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -237,7 +244,11 @@ class LazyTopDownAnalyzer(
|
||||
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) {
|
||||
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) {
|
||||
val descriptor = lazyDeclarationResolver.resolveToDescriptor(property) as PropertyDescriptor
|
||||
|
||||
@@ -269,9 +284,10 @@ class LazyTopDownAnalyzer(
|
||||
}
|
||||
|
||||
private fun createPropertiesFromDestructuringDeclarations(
|
||||
c: TopDownAnalysisContext,
|
||||
topLevelFqNames: Multimap<FqName, KtElement>,
|
||||
destructuringDeclarations: List<KtDestructuringDeclaration>) {
|
||||
c: TopDownAnalysisContext,
|
||||
topLevelFqNames: Multimap<FqName, KtElement>,
|
||||
destructuringDeclarations: List<KtDestructuringDeclaration>
|
||||
) {
|
||||
for (destructuringDeclaration in destructuringDeclarations) {
|
||||
for (entry in destructuringDeclaration.entries) {
|
||||
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)) {
|
||||
val fqName = declaration.fqName
|
||||
if (fqName != null) {
|
||||
|
||||
@@ -52,93 +52,123 @@ object ModifierCheckerCore {
|
||||
COMPATIBLE_FOR_CLASSES_ONLY
|
||||
}
|
||||
|
||||
private val defaultVisibilityTargets = EnumSet.of(CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
|
||||
MEMBER_FUNCTION, TOP_LEVEL_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER,
|
||||
MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, CONSTRUCTOR, TYPEALIAS)
|
||||
private val defaultVisibilityTargets = EnumSet.of(
|
||||
CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
|
||||
MEMBER_FUNCTION, TOP_LEVEL_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER,
|
||||
MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, CONSTRUCTOR, TYPEALIAS
|
||||
)
|
||||
|
||||
val possibleTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>(
|
||||
ENUM_KEYWORD to EnumSet.of(ENUM_CLASS),
|
||||
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),
|
||||
FINAL_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS, OBJECT, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
SEALED_KEYWORD to EnumSet.of(CLASS_ONLY),
|
||||
INNER_KEYWORD to EnumSet.of(CLASS_ONLY),
|
||||
OVERRIDE_KEYWORD to EnumSet.of(MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
PRIVATE_KEYWORD to defaultVisibilityTargets,
|
||||
PUBLIC_KEYWORD to defaultVisibilityTargets,
|
||||
INTERNAL_KEYWORD to defaultVisibilityTargets,
|
||||
PROTECTED_KEYWORD to EnumSet.of(CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
|
||||
MEMBER_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, MEMBER_PROPERTY, CONSTRUCTOR, TYPEALIAS),
|
||||
IN_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
|
||||
OUT_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
|
||||
REIFIED_KEYWORD to EnumSet.of(TYPE_PARAMETER),
|
||||
VARARG_KEYWORD to EnumSet.of(VALUE_PARAMETER, PROPERTY_PARAMETER),
|
||||
COMPANION_KEYWORD to EnumSet.of(OBJECT),
|
||||
LATEINIT_KEYWORD to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, LOCAL_VARIABLE),
|
||||
DATA_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS),
|
||||
INLINE_KEYWORD to EnumSet.of(FUNCTION, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER),
|
||||
NOINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
|
||||
TAILREC_KEYWORD to EnumSet.of(FUNCTION),
|
||||
SUSPEND_KEYWORD to EnumSet.of(MEMBER_FUNCTION, TOP_LEVEL_FUNCTION),
|
||||
EXTERNAL_KEYWORD to EnumSet.of(FUNCTION, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER, CLASS),
|
||||
ANNOTATION_KEYWORD to EnumSet.of(ANNOTATION_CLASS),
|
||||
CROSSINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
|
||||
CONST_KEYWORD to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY),
|
||||
OPERATOR_KEYWORD to EnumSet.of(FUNCTION),
|
||||
INFIX_KEYWORD to EnumSet.of(FUNCTION),
|
||||
HEADER_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
|
||||
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)
|
||||
ENUM_KEYWORD to EnumSet.of(ENUM_CLASS),
|
||||
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),
|
||||
FINAL_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS, OBJECT, MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
SEALED_KEYWORD to EnumSet.of(CLASS_ONLY),
|
||||
INNER_KEYWORD to EnumSet.of(CLASS_ONLY),
|
||||
OVERRIDE_KEYWORD to EnumSet.of(MEMBER_PROPERTY, MEMBER_FUNCTION),
|
||||
PRIVATE_KEYWORD to defaultVisibilityTargets,
|
||||
PUBLIC_KEYWORD to defaultVisibilityTargets,
|
||||
INTERNAL_KEYWORD to defaultVisibilityTargets,
|
||||
PROTECTED_KEYWORD to EnumSet.of(
|
||||
CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS,
|
||||
MEMBER_FUNCTION, PROPERTY_GETTER, PROPERTY_SETTER, MEMBER_PROPERTY, CONSTRUCTOR, TYPEALIAS
|
||||
),
|
||||
IN_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
|
||||
OUT_KEYWORD to EnumSet.of(TYPE_PARAMETER, TYPE_PROJECTION),
|
||||
REIFIED_KEYWORD to EnumSet.of(TYPE_PARAMETER),
|
||||
VARARG_KEYWORD to EnumSet.of(VALUE_PARAMETER, PROPERTY_PARAMETER),
|
||||
COMPANION_KEYWORD to EnumSet.of(OBJECT),
|
||||
LATEINIT_KEYWORD to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY, LOCAL_VARIABLE),
|
||||
DATA_KEYWORD to EnumSet.of(CLASS_ONLY, LOCAL_CLASS),
|
||||
INLINE_KEYWORD to EnumSet.of(FUNCTION, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER),
|
||||
NOINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
|
||||
TAILREC_KEYWORD to EnumSet.of(FUNCTION),
|
||||
SUSPEND_KEYWORD to EnumSet.of(MEMBER_FUNCTION, TOP_LEVEL_FUNCTION),
|
||||
EXTERNAL_KEYWORD to EnumSet.of(FUNCTION, PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER, CLASS),
|
||||
ANNOTATION_KEYWORD to EnumSet.of(ANNOTATION_CLASS),
|
||||
CROSSINLINE_KEYWORD to EnumSet.of(VALUE_PARAMETER),
|
||||
CONST_KEYWORD to EnumSet.of(MEMBER_PROPERTY, TOP_LEVEL_PROPERTY),
|
||||
OPERATOR_KEYWORD to EnumSet.of(FUNCTION),
|
||||
INFIX_KEYWORD to EnumSet.of(FUNCTION),
|
||||
HEADER_KEYWORD to EnumSet.of(TOP_LEVEL_FUNCTION, TOP_LEVEL_PROPERTY, CLASS_ONLY, OBJECT, INTERFACE, ENUM_CLASS, ANNOTATION_CLASS),
|
||||
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(
|
||||
SUSPEND_KEYWORD to listOf(LanguageFeature.Coroutines),
|
||||
INLINE_KEYWORD to listOf(LanguageFeature.InlineProperties),
|
||||
HEADER_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
||||
IMPL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
||||
EXPECT_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
||||
ACTUAL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
||||
LATEINIT_KEYWORD to listOf(LanguageFeature.LateinitTopLevelProperties, LanguageFeature.LateinitLocalVariables)
|
||||
SUSPEND_KEYWORD to listOf(LanguageFeature.Coroutines),
|
||||
INLINE_KEYWORD to listOf(LanguageFeature.InlineProperties),
|
||||
HEADER_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
||||
IMPL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
||||
EXPECT_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
||||
ACTUAL_KEYWORD to listOf(LanguageFeature.MultiPlatformProjects),
|
||||
LATEINIT_KEYWORD to listOf(LanguageFeature.LateinitTopLevelProperties, LanguageFeature.LateinitLocalVariables)
|
||||
)
|
||||
|
||||
private val featureDependenciesTargets = mapOf(
|
||||
LanguageFeature.InlineProperties to setOf(PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER),
|
||||
LanguageFeature.LateinitLocalVariables to setOf(LOCAL_VARIABLE),
|
||||
LanguageFeature.LateinitTopLevelProperties to setOf(TOP_LEVEL_PROPERTY)
|
||||
LanguageFeature.InlineProperties to setOf(PROPERTY, PROPERTY_GETTER, PROPERTY_SETTER),
|
||||
LanguageFeature.LateinitLocalVariables to setOf(LOCAL_VARIABLE),
|
||||
LanguageFeature.LateinitTopLevelProperties to setOf(TOP_LEVEL_PROPERTY)
|
||||
)
|
||||
|
||||
// NOTE: deprecated targets must be possible!
|
||||
private val deprecatedTargetMap = mapOf<KtModifierKeywordToken, Set<KotlinTarget>>()
|
||||
|
||||
private val deprecatedModifierMap = mapOf(
|
||||
HEADER_KEYWORD to EXPECT_KEYWORD,
|
||||
IMPL_KEYWORD to ACTUAL_KEYWORD
|
||||
HEADER_KEYWORD to EXPECT_KEYWORD,
|
||||
IMPL_KEYWORD to ACTUAL_KEYWORD
|
||||
)
|
||||
|
||||
// NOTE: redundant targets must be possible!
|
||||
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>(
|
||||
INNER_KEYWORD to or(always(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS),
|
||||
ifSupported(LanguageFeature.InnerClassInEnumEntryClass, ENUM_ENTRY)),
|
||||
OVERRIDE_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, INTERFACE, ENUM_CLASS, 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),
|
||||
PRIVATE_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, INTERFACE, ENUM_CLASS, ENUM_ENTRY, FILE),
|
||||
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)
|
||||
INNER_KEYWORD to or(
|
||||
always(CLASS_ONLY, LOCAL_CLASS, ENUM_CLASS),
|
||||
ifSupported(LanguageFeature.InnerClassInEnumEntryClass, ENUM_ENTRY)
|
||||
),
|
||||
OVERRIDE_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, INTERFACE, ENUM_CLASS, 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),
|
||||
PRIVATE_KEYWORD to always(CLASS_ONLY, LOCAL_CLASS, OBJECT, OBJECT_LITERAL, INTERFACE, ENUM_CLASS, ENUM_ENTRY, FILE),
|
||||
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>>()
|
||||
|
||||
fun isPossibleParentTarget(
|
||||
modifier: KtModifierKeywordToken,
|
||||
parentTarget: KotlinTarget,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
modifier: KtModifierKeywordToken,
|
||||
parentTarget: KotlinTarget,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): Boolean {
|
||||
deprecatedParentTargetMap[modifier]?.let {
|
||||
if (parentTarget in it) return false
|
||||
@@ -198,15 +228,17 @@ object ModifierCheckerCore {
|
||||
}
|
||||
|
||||
private fun redundantRegister(
|
||||
sufficient: KtModifierKeywordToken,
|
||||
redundant: KtModifierKeywordToken
|
||||
sufficient: KtModifierKeywordToken,
|
||||
redundant: KtModifierKeywordToken
|
||||
): Map<Pair<KtModifierKeywordToken, KtModifierKeywordToken>, Compatibility> {
|
||||
return mapOf(Pair(sufficient, redundant) to Compatibility.REDUNDANT,
|
||||
Pair(redundant, sufficient) to Compatibility.REVERSE_REDUNDANT)
|
||||
return mapOf(
|
||||
Pair(sufficient, redundant) to Compatibility.REDUNDANT,
|
||||
Pair(redundant, sufficient) to Compatibility.REVERSE_REDUNDANT
|
||||
)
|
||||
}
|
||||
|
||||
private fun compatibilityRegister(
|
||||
compatibility: Compatibility, vararg list: KtModifierKeywordToken
|
||||
compatibility: Compatibility, vararg list: KtModifierKeywordToken
|
||||
): Map<Pair<KtModifierKeywordToken, KtModifierKeywordToken>, Compatibility> {
|
||||
val result = hashMapOf<Pair<KtModifierKeywordToken, KtModifierKeywordToken>, Compatibility>()
|
||||
for (first in list) {
|
||||
@@ -220,7 +252,7 @@ object ModifierCheckerCore {
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
@@ -229,29 +261,31 @@ object ModifierCheckerCore {
|
||||
private fun compatibility(first: KtModifierKeywordToken, second: KtModifierKeywordToken): Compatibility {
|
||||
return if (first == second) {
|
||||
Compatibility.REPEATED
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
mutualCompatibility[Pair(first, second)] ?: Compatibility.COMPATIBLE
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkCompatibility(trace: BindingTrace,
|
||||
firstNode: ASTNode,
|
||||
secondNode: ASTNode,
|
||||
owner: PsiElement,
|
||||
incorrectNodes: MutableSet<ASTNode>) {
|
||||
private fun checkCompatibility(
|
||||
trace: BindingTrace,
|
||||
firstNode: ASTNode,
|
||||
secondNode: ASTNode,
|
||||
owner: PsiElement,
|
||||
incorrectNodes: MutableSet<ASTNode>
|
||||
) {
|
||||
val first = firstNode.elementType as KtModifierKeywordToken
|
||||
val second = secondNode.elementType as KtModifierKeywordToken
|
||||
val compatibility = compatibility(first, second)
|
||||
when (compatibility) {
|
||||
Compatibility.COMPATIBLE -> {}
|
||||
Compatibility.COMPATIBLE -> {
|
||||
}
|
||||
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 ->
|
||||
trace.report(Errors.REDUNDANT_MODIFIER.on(secondNode.psi, second, first))
|
||||
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 -> {
|
||||
trace.report(Errors.DEPRECATED_MODIFIER_PAIR.on(firstNode.psi, first, second))
|
||||
trace.report(Errors.DEPRECATED_MODIFIER_PAIR.on(secondNode.psi, second, first))
|
||||
@@ -285,18 +319,30 @@ object ModifierCheckerCore {
|
||||
deprecatedModifierReplacement != null ->
|
||||
trace.report(Errors.DEPRECATED_MODIFIER.on(node.psi, modifier, deprecatedModifierReplacement))
|
||||
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 } ->
|
||||
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
|
||||
}
|
||||
|
||||
private fun checkLanguageLevelSupport(
|
||||
trace: BindingTrace,
|
||||
node: ASTNode,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
actualTargets: List<KotlinTarget>
|
||||
trace: BindingTrace,
|
||||
node: ASTNode,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
actualTargets: List<KotlinTarget>
|
||||
): Boolean {
|
||||
val modifier = node.elementType as KtModifierKeywordToken
|
||||
|
||||
@@ -313,8 +359,7 @@ object ModifierCheckerCore {
|
||||
|
||||
if (featureSupport == LanguageFeature.State.DISABLED) {
|
||||
trace.report(Errors.UNSUPPORTED_FEATURE.on(node.psi, diagnosticData))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
trace.report(Errors.EXPERIMENTAL_FEATURE_ERROR.on(node.psi, diagnosticData))
|
||||
}
|
||||
return false
|
||||
@@ -330,7 +375,12 @@ object ModifierCheckerCore {
|
||||
|
||||
|
||||
// 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 actualParents: List<KotlinTarget> = when (parentDescriptor) {
|
||||
is ClassDescriptor -> KotlinTarget.classActualTargets(parentDescriptor)
|
||||
@@ -341,23 +391,35 @@ object ModifierCheckerCore {
|
||||
}
|
||||
val deprecatedParents = deprecatedParentTargetMap[modifier]
|
||||
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
|
||||
}
|
||||
val possibleParentPredicate = possibleParentTargetPredicateMap[modifier] ?: 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
|
||||
}
|
||||
|
||||
private val MODIFIER_KEYWORD_SET = TokenSet.orSet(KtTokens.SOFT_KEYWORDS, TokenSet.create(KtTokens.IN_KEYWORD))
|
||||
|
||||
private fun checkModifierList(
|
||||
list: KtModifierList,
|
||||
trace: BindingTrace,
|
||||
parentDescriptor: DeclarationDescriptor?,
|
||||
actualTargets: List<KotlinTarget>,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
list: KtModifierList,
|
||||
trace: BindingTrace,
|
||||
parentDescriptor: DeclarationDescriptor?,
|
||||
actualTargets: List<KotlinTarget>,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
// It's a list of all nodes with error already reported
|
||||
// General strategy: report no more than one error but any number of warnings
|
||||
@@ -381,10 +443,10 @@ object ModifierCheckerCore {
|
||||
}
|
||||
|
||||
fun check(
|
||||
listOwner: KtModifierListOwner,
|
||||
trace: BindingTrace,
|
||||
descriptor: DeclarationDescriptor?,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
listOwner: KtModifierListOwner,
|
||||
trace: BindingTrace,
|
||||
descriptor: DeclarationDescriptor?,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
if (listOwner is KtDeclarationWithBody) {
|
||||
// JetFunction or JetPropertyAccessor
|
||||
@@ -410,18 +472,19 @@ private fun always(target: KotlinTarget, vararg targets: KotlinTarget) = object
|
||||
private val targetSet = EnumSet.of(target, *targets)
|
||||
|
||||
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 val targetSet = EnumSet.of(target, *targets)
|
||||
private fun ifSupported(languageFeature: LanguageFeature, target: KotlinTarget, vararg targets: KotlinTarget) =
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
private fun or(p1: TargetAllowedPredicate, p2: TargetAllowedPredicate) = object : TargetAllowedPredicate {
|
||||
override fun isAllowed(target: KotlinTarget, languageVersionSettings: LanguageVersionSettings) =
|
||||
p1.isAllowed(target, languageVersionSettings) ||
|
||||
p2.isAllowed(target, languageVersionSettings)
|
||||
p1.isAllowed(target, languageVersionSettings) ||
|
||||
p2.isAllowed(target, languageVersionSettings)
|
||||
}
|
||||
|
||||
+12
-8
@@ -31,9 +31,9 @@ import org.jetbrains.kotlin.utils.DFS
|
||||
object NonExpansiveInheritanceRestrictionChecker {
|
||||
@JvmStatic
|
||||
fun check(
|
||||
declaration: KtClass,
|
||||
classDescriptor: ClassDescriptor,
|
||||
diagnosticHolder: DiagnosticSink
|
||||
declaration: KtClass,
|
||||
classDescriptor: ClassDescriptor,
|
||||
diagnosticHolder: DiagnosticSink
|
||||
) {
|
||||
val typeConstructor = classDescriptor.typeConstructor
|
||||
if (typeConstructor.parameters.isEmpty()) return
|
||||
@@ -104,11 +104,14 @@ object NonExpansiveInheritanceRestrictionChecker {
|
||||
|
||||
for (typeParameter in typeParameters) {
|
||||
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
|
||||
// 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.
|
||||
@@ -116,7 +119,8 @@ object NonExpansiveInheritanceRestrictionChecker {
|
||||
val bounds = hashSetOf<KotlinType>()
|
||||
|
||||
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)
|
||||
|
||||
if (!typeProjection.isStarProjection) {
|
||||
@@ -138,7 +142,7 @@ object NonExpansiveInheritanceRestrictionChecker {
|
||||
|
||||
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>
|
||||
val expansiveEdges: Set<ExpansiveEdge<T>>
|
||||
}
|
||||
|
||||
@@ -42,9 +42,9 @@ import org.jetbrains.kotlin.utils.addToStdlib.assertedCast
|
||||
import java.util.*
|
||||
|
||||
class OverrideResolver(
|
||||
private val trace: BindingTrace,
|
||||
private val overridesBackwardCompatibilityHelper: OverridesBackwardCompatibilityHelper,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
private val trace: BindingTrace,
|
||||
private val overridesBackwardCompatibilityHelper: OverridesBackwardCompatibilityHelper,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
|
||||
fun check(c: TopDownAnalysisContext) {
|
||||
@@ -106,14 +106,17 @@ class OverrideResolver(
|
||||
// don't care
|
||||
}
|
||||
|
||||
override fun abstractMemberWithMoreSpecificType(abstractMember: CallableMemberDescriptor, concreteMember: CallableMemberDescriptor) {
|
||||
override fun abstractMemberWithMoreSpecificType(
|
||||
abstractMember: CallableMemberDescriptor,
|
||||
concreteMember: CallableMemberDescriptor
|
||||
) {
|
||||
shouldImplement.add(abstractMember)
|
||||
}
|
||||
}
|
||||
|
||||
private inner class CollectErrorInformationForInheritedMembersStrategy(
|
||||
private val klass: KtClassOrObject,
|
||||
private val classDescriptor: ClassDescriptor
|
||||
private val klass: KtClassOrObject,
|
||||
private val classDescriptor: ClassDescriptor
|
||||
) : CheckInheritedSignaturesReportStrategy, CheckOverrideReportStrategy {
|
||||
|
||||
private val abstractNoImpl = linkedSetOf<CallableMemberDescriptor>()
|
||||
@@ -147,24 +150,25 @@ class OverrideResolver(
|
||||
if (descriptor1 is PropertyDescriptor && descriptor2 is PropertyDescriptor) {
|
||||
if (descriptor1.isVar || descriptor2.isVar) {
|
||||
reportInheritanceConflictIfRequired(VAR_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
reportInheritanceConflictIfRequired(PROPERTY_TYPE_MISMATCH_ON_INHERITANCE, descriptor1, descriptor2)
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
|
||||
private fun reportInheritanceConflictIfRequired(
|
||||
diagnosticFactory: DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor>,
|
||||
descriptor1: CallableMemberDescriptor,
|
||||
descriptor2: CallableMemberDescriptor
|
||||
diagnosticFactory: DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor>,
|
||||
descriptor1: CallableMemberDescriptor,
|
||||
descriptor2: CallableMemberDescriptor
|
||||
) {
|
||||
if (!onceErrorsReported.contains(diagnosticFactory)) {
|
||||
onceErrorsReported.add(diagnosticFactory)
|
||||
@@ -177,19 +181,21 @@ class OverrideResolver(
|
||||
}
|
||||
|
||||
override fun returnTypeMismatchOnOverride(
|
||||
overriding: CallableMemberDescriptor,
|
||||
overridden: CallableMemberDescriptor
|
||||
overriding: CallableMemberDescriptor,
|
||||
overridden: CallableMemberDescriptor
|
||||
) {
|
||||
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(
|
||||
overriding: PropertyDescriptor,
|
||||
overridden: PropertyDescriptor
|
||||
overriding: PropertyDescriptor,
|
||||
overridden: PropertyDescriptor
|
||||
) {
|
||||
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) {
|
||||
@@ -197,14 +203,16 @@ class OverrideResolver(
|
||||
}
|
||||
|
||||
private fun reportDelegationProblemIfRequired(
|
||||
diagnosticFactory: DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor>,
|
||||
relevantDiagnosticFromInheritance: DiagnosticFactoryWithPsiElement<*, *>?,
|
||||
delegate: CallableMemberDescriptor,
|
||||
overridden: CallableMemberDescriptor
|
||||
diagnosticFactory: DiagnosticFactory2<KtClassOrObject, CallableMemberDescriptor, CallableMemberDescriptor>,
|
||||
relevantDiagnosticFromInheritance: DiagnosticFactoryWithPsiElement<*, *>?,
|
||||
delegate: CallableMemberDescriptor,
|
||||
overridden: CallableMemberDescriptor
|
||||
) {
|
||||
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)
|
||||
trace.report(diagnosticFactory.on(klass, delegate, overridden))
|
||||
}
|
||||
@@ -214,8 +222,7 @@ class OverrideResolver(
|
||||
val canHaveAbstractMembers = classCanHaveAbstractFakeOverride(classDescriptor)
|
||||
if (abstractInBaseClassNoImpl.isNotEmpty() && !canHaveAbstractMembers) {
|
||||
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()))
|
||||
}
|
||||
|
||||
@@ -223,8 +230,7 @@ class OverrideResolver(
|
||||
multipleImplementations.removeAll(conflictingReturnTypes)
|
||||
if (!conflictingInterfaceMembers.isEmpty()) {
|
||||
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()))
|
||||
}
|
||||
}
|
||||
@@ -246,8 +252,7 @@ class OverrideResolver(
|
||||
if (declared.kind == CallableMemberDescriptor.Kind.SYNTHESIZED) {
|
||||
if (DataClassDescriptorResolver.isComponentLike(declared.name)) {
|
||||
checkOverrideForComponentFunction(declared)
|
||||
}
|
||||
else if (declared.name == DataClassDescriptorResolver.COPY_METHOD_NAME) {
|
||||
} else if (declared.name == DataClassDescriptorResolver.COPY_METHOD_NAME) {
|
||||
checkOverrideForCopyFunction(declared)
|
||||
}
|
||||
return
|
||||
@@ -257,7 +262,8 @@ class OverrideResolver(
|
||||
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 hasOverrideNode = modifierList != null && modifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD)
|
||||
@@ -288,8 +294,7 @@ class OverrideResolver(
|
||||
typeMismatchError = true
|
||||
if (overridden.isVar) {
|
||||
trace.report(VAR_TYPE_MISMATCH_ON_OVERRIDE.on(member, declared, overridden))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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))
|
||||
}
|
||||
|
||||
@@ -310,8 +318,7 @@ class OverrideResolver(
|
||||
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()
|
||||
trace.report(VIRTUAL_MEMBER_HIDDEN.on(member, declared, overridden, overridden.containingDeclaration))
|
||||
}
|
||||
@@ -354,8 +361,7 @@ class OverrideResolver(
|
||||
val dataModifier = findDataModifierForDataClass(copyFunction.containingDeclaration)
|
||||
if (languageVersionSettings.supportsFeature(LanguageFeature.ProhibitDataClassesOverridingCopy)) {
|
||||
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))
|
||||
}
|
||||
}
|
||||
@@ -397,15 +403,15 @@ class OverrideResolver(
|
||||
|
||||
if (isDeclaration) {
|
||||
checkNameAndDefaultForDeclaredParameter(parameterFromSubclass, multipleDefaultsInSuper)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
checkNameAndDefaultForFakeOverrideParameter(declared, parameterFromSubclass, multipleDefaultsInSuper)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()) {
|
||||
trace.report(DEFAULT_VALUE_NOT_ALLOWED_IN_OVERRIDE.on(parameter))
|
||||
@@ -418,22 +424,25 @@ class OverrideResolver(
|
||||
for (parameterFromSuperclass in descriptor.overriddenDescriptors) {
|
||||
if (shouldReportParameterNameOverrideWarning(descriptor, parameterFromSuperclass)) {
|
||||
|
||||
trace.report(PARAMETER_NAME_CHANGED_ON_OVERRIDE.on(
|
||||
trace.report(
|
||||
PARAMETER_NAME_CHANGED_ON_OVERRIDE.on(
|
||||
parameter,
|
||||
parameterFromSuperclass.containingDeclaration.containingDeclaration as ClassDescriptor,
|
||||
parameterFromSuperclass)
|
||||
parameterFromSuperclass
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkNameAndDefaultForFakeOverrideParameter(
|
||||
containingFunction: CallableMemberDescriptor,
|
||||
descriptor: ValueParameterDescriptor,
|
||||
multipleDefaultsInSuper: Boolean
|
||||
containingFunction: CallableMemberDescriptor,
|
||||
descriptor: ValueParameterDescriptor,
|
||||
multipleDefaultsInSuper: Boolean
|
||||
) {
|
||||
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) {
|
||||
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) {
|
||||
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,
|
||||
containingFunction.overriddenDescriptors,
|
||||
parameterFromSuperclass.index + 1)
|
||||
parameterFromSuperclass.index + 1
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -468,11 +479,24 @@ class OverrideResolver(
|
||||
for (descriptor in memberDescriptor.overriddenDescriptors) {
|
||||
val compare = Visibilities.compare(visibility, descriptor.visibility)
|
||||
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
|
||||
}
|
||||
else if (compare < 0) {
|
||||
trace.report(CANNOT_WEAKEN_ACCESS_PRIVILEGE.on(declaration, descriptor.visibility, descriptor, descriptor.containingDeclaration))
|
||||
} else if (compare < 0) {
|
||||
trace.report(
|
||||
CANNOT_WEAKEN_ACCESS_PRIVILEGE.on(
|
||||
declaration,
|
||||
descriptor.visibility,
|
||||
descriptor,
|
||||
descriptor.containingDeclaration
|
||||
)
|
||||
)
|
||||
return
|
||||
}
|
||||
}
|
||||
@@ -481,8 +505,8 @@ class OverrideResolver(
|
||||
companion object {
|
||||
|
||||
fun resolveUnknownVisibilities(
|
||||
descriptors: Collection<CallableMemberDescriptor>,
|
||||
trace: BindingTrace
|
||||
descriptors: Collection<CallableMemberDescriptor>,
|
||||
trace: BindingTrace
|
||||
) {
|
||||
for (descriptor in descriptors) {
|
||||
OverridingUtil.resolveUnknownVisibilityForMember(descriptor, createCannotInferVisibilityReporter(trace))
|
||||
@@ -515,9 +539,9 @@ class OverrideResolver(
|
||||
}
|
||||
|
||||
private fun checkInheritedAndDelegatedSignatures(
|
||||
classDescriptor: ClassDescriptor,
|
||||
inheritedReportStrategy: CheckInheritedSignaturesReportStrategy,
|
||||
overrideReportStrategyForDelegates: CheckOverrideReportStrategy?
|
||||
classDescriptor: ClassDescriptor,
|
||||
inheritedReportStrategy: CheckInheritedSignaturesReportStrategy,
|
||||
overrideReportStrategyForDelegates: CheckOverrideReportStrategy?
|
||||
) {
|
||||
for (member in DescriptorUtils.getAllDescriptors(classDescriptor.defaultType.memberScope)) {
|
||||
if (member is CallableMemberDescriptor) {
|
||||
@@ -527,9 +551,9 @@ class OverrideResolver(
|
||||
}
|
||||
|
||||
private fun checkInheritedAndDelegatedSignatures(
|
||||
descriptor: CallableMemberDescriptor,
|
||||
reportingStrategy: CheckInheritedSignaturesReportStrategy,
|
||||
overrideReportStrategyForDelegates: CheckOverrideReportStrategy?
|
||||
descriptor: CallableMemberDescriptor,
|
||||
reportingStrategy: CheckInheritedSignaturesReportStrategy,
|
||||
overrideReportStrategyForDelegates: CheckOverrideReportStrategy?
|
||||
) {
|
||||
val kind = descriptor.kind
|
||||
if (kind != FAKE_OVERRIDE && kind != DELEGATION) return
|
||||
@@ -545,9 +569,11 @@ class OverrideResolver(
|
||||
|
||||
val allOverriddenDeclarations = ContainerUtil.flatten(overriddenDeclarationsByDirectParent.values)
|
||||
val allFilteredOverriddenDeclarations = OverridingUtil.filterOutOverridden(
|
||||
Sets.newLinkedHashSet(allOverriddenDeclarations))
|
||||
Sets.newLinkedHashSet(allOverriddenDeclarations)
|
||||
)
|
||||
|
||||
val relevantDirectlyOverridden = getRelevantDirectlyOverridden(overriddenDeclarationsByDirectParent, allFilteredOverriddenDeclarations)
|
||||
val relevantDirectlyOverridden =
|
||||
getRelevantDirectlyOverridden(overriddenDeclarationsByDirectParent, allFilteredOverriddenDeclarations)
|
||||
|
||||
checkInheritedDescriptorsGroup(descriptor, relevantDirectlyOverridden, reportingStrategy)
|
||||
|
||||
@@ -560,8 +586,8 @@ class OverrideResolver(
|
||||
}
|
||||
|
||||
val (concreteOverridden, abstractOverridden) = relevantDirectlyOverridden
|
||||
.filter { !isOrOverridesSynthesized(it) }
|
||||
.partition { it.modality != Modality.ABSTRACT }
|
||||
.filter { !isOrOverridesSynthesized(it) }
|
||||
.partition { it.modality != Modality.ABSTRACT }
|
||||
|
||||
val numImplementations = concreteOverridden.size
|
||||
|
||||
@@ -587,8 +613,8 @@ class OverrideResolver(
|
||||
}
|
||||
|
||||
private fun checkMissingOverridesByJava8Restrictions(
|
||||
relevantDirectlyOverridden: Set<CallableMemberDescriptor>,
|
||||
reportingStrategy: CheckInheritedSignaturesReportStrategy
|
||||
relevantDirectlyOverridden: Set<CallableMemberDescriptor>,
|
||||
reportingStrategy: CheckInheritedSignaturesReportStrategy
|
||||
) {
|
||||
// Java 8:
|
||||
// -- class should implement an abstract member of a super-class,
|
||||
@@ -608,8 +634,7 @@ class OverrideResolver(
|
||||
if (overridden.modality === Modality.ABSTRACT) {
|
||||
overridesAbstractInBaseClass = overridden
|
||||
}
|
||||
}
|
||||
else if (containingDeclaration.kind == ClassKind.INTERFACE) {
|
||||
} else if (containingDeclaration.kind == ClassKind.INTERFACE) {
|
||||
overriddenInterfaceMembers.add(overridden)
|
||||
if (overridden.modality !== Modality.ABSTRACT) {
|
||||
overridesNonAbstractInterfaceMember = true
|
||||
@@ -629,14 +654,14 @@ class OverrideResolver(
|
||||
}
|
||||
|
||||
private fun collectAbstractMethodsWithMoreSpecificReturnType(
|
||||
abstractOverridden: List<CallableMemberDescriptor>,
|
||||
implementation: CallableMemberDescriptor
|
||||
abstractOverridden: List<CallableMemberDescriptor>,
|
||||
implementation: CallableMemberDescriptor
|
||||
): List<CallableMemberDescriptor> =
|
||||
abstractOverridden.filter { abstractMember -> !isReturnTypeOkForOverride(abstractMember, implementation) }
|
||||
abstractOverridden.filter { abstractMember -> !isReturnTypeOkForOverride(abstractMember, implementation) }
|
||||
|
||||
private fun getRelevantDirectlyOverridden(
|
||||
overriddenByParent: MutableMap<CallableMemberDescriptor, Set<CallableMemberDescriptor>>,
|
||||
allFilteredOverriddenDeclarations: Set<CallableMemberDescriptor>
|
||||
overriddenByParent: MutableMap<CallableMemberDescriptor, Set<CallableMemberDescriptor>>,
|
||||
allFilteredOverriddenDeclarations: Set<CallableMemberDescriptor>
|
||||
): Set<CallableMemberDescriptor> {
|
||||
/* Let the following class hierarchy is declared:
|
||||
|
||||
@@ -678,9 +703,9 @@ class OverrideResolver(
|
||||
}
|
||||
|
||||
private fun isRelevant(
|
||||
declarationSet: Set<CallableMemberDescriptor>,
|
||||
allDeclarationSets: Collection<Set<CallableMemberDescriptor>>,
|
||||
allFilteredOverriddenDeclarations: Set<CallableMemberDescriptor>
|
||||
declarationSet: Set<CallableMemberDescriptor>,
|
||||
allDeclarationSets: Collection<Set<CallableMemberDescriptor>>,
|
||||
allFilteredOverriddenDeclarations: Set<CallableMemberDescriptor>
|
||||
): Boolean {
|
||||
for (otherSet in allDeclarationSets) {
|
||||
if (otherSet === declarationSet) continue
|
||||
@@ -691,7 +716,7 @@ class OverrideResolver(
|
||||
}
|
||||
|
||||
private fun collectOverriddenDeclarations(
|
||||
directOverriddenDescriptors: Collection<CallableMemberDescriptor>
|
||||
directOverriddenDescriptors: Collection<CallableMemberDescriptor>
|
||||
): MutableMap<CallableMemberDescriptor, Set<CallableMemberDescriptor>> {
|
||||
val overriddenDeclarationsByDirectParent = Maps.newLinkedHashMap<CallableMemberDescriptor, Set<CallableMemberDescriptor>>()
|
||||
for (descriptor in directOverriddenDescriptors) {
|
||||
@@ -703,9 +728,9 @@ class OverrideResolver(
|
||||
}
|
||||
|
||||
private fun checkInheritedDescriptorsGroup(
|
||||
descriptor: CallableMemberDescriptor,
|
||||
overriddenDescriptors: Collection<CallableMemberDescriptor>,
|
||||
reportingStrategy: CheckInheritedSignaturesReportStrategy
|
||||
descriptor: CallableMemberDescriptor,
|
||||
overriddenDescriptors: Collection<CallableMemberDescriptor>,
|
||||
reportingStrategy: CheckInheritedSignaturesReportStrategy
|
||||
) {
|
||||
if (overriddenDescriptors.size <= 1) return
|
||||
|
||||
@@ -713,12 +738,12 @@ class OverrideResolver(
|
||||
|
||||
for (overriddenDescriptor in overriddenDescriptors) {
|
||||
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)) {
|
||||
reportingStrategy.typeMismatchOnInheritance(propertyDescriptor, overriddenPropertyDescriptor)
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (!isReturnTypeOkForOverride(overriddenDescriptor, descriptor)) {
|
||||
reportingStrategy.typeMismatchOnInheritance(descriptor, overriddenDescriptor)
|
||||
}
|
||||
@@ -727,8 +752,8 @@ class OverrideResolver(
|
||||
}
|
||||
|
||||
private fun checkOverridesForMemberMarkedOverride(
|
||||
declared: CallableMemberDescriptor,
|
||||
reportError: CheckOverrideReportForDeclaredMemberStrategy
|
||||
declared: CallableMemberDescriptor,
|
||||
reportError: CheckOverrideReportForDeclaredMemberStrategy
|
||||
) {
|
||||
val overriddenDescriptors = declared.overriddenDescriptors
|
||||
|
||||
@@ -743,17 +768,16 @@ class OverrideResolver(
|
||||
val invisibleOverriddenDescriptor = findInvisibleOverriddenDescriptor(declared, declaringClass)
|
||||
if (invisibleOverriddenDescriptor != null) {
|
||||
reportError.cannotOverrideInvisibleMember(declared, invisibleOverriddenDescriptor)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
reportError.nothingToOverride(declared)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkOverridesForMember(
|
||||
memberDescriptor: CallableMemberDescriptor,
|
||||
overriddenDescriptors: Collection<CallableMemberDescriptor>,
|
||||
reportError: CheckOverrideReportStrategy
|
||||
memberDescriptor: CallableMemberDescriptor,
|
||||
overriddenDescriptors: Collection<CallableMemberDescriptor>,
|
||||
reportError: CheckOverrideReportStrategy
|
||||
) {
|
||||
val propertyMemberDescriptor = if (memberDescriptor is PropertyDescriptor) memberDescriptor else null
|
||||
|
||||
@@ -769,8 +793,7 @@ class OverrideResolver(
|
||||
if (!isPropertyTypeOkForOverride(overriddenProperty, propertyMemberDescriptor)) {
|
||||
reportError.propertyTypeMismatchOnOverride(propertyMemberDescriptor, overriddenProperty)
|
||||
}
|
||||
}
|
||||
else if (!isReturnTypeOkForOverride(overridden, memberDescriptor)) {
|
||||
} else if (!isReturnTypeOkForOverride(overridden, memberDescriptor)) {
|
||||
reportError.returnTypeMismatchOnOverride(memberDescriptor, overridden)
|
||||
}
|
||||
|
||||
@@ -781,8 +804,8 @@ class OverrideResolver(
|
||||
}
|
||||
|
||||
private fun isReturnTypeOkForOverride(
|
||||
superDescriptor: CallableDescriptor,
|
||||
subDescriptor: CallableDescriptor
|
||||
superDescriptor: CallableDescriptor,
|
||||
subDescriptor: CallableDescriptor
|
||||
): Boolean {
|
||||
val typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor) ?: return false
|
||||
|
||||
@@ -796,8 +819,8 @@ class OverrideResolver(
|
||||
}
|
||||
|
||||
private fun prepareTypeSubstitutor(
|
||||
superDescriptor: CallableDescriptor,
|
||||
subDescriptor: CallableDescriptor
|
||||
superDescriptor: CallableDescriptor,
|
||||
subDescriptor: CallableDescriptor
|
||||
): TypeSubstitutor? {
|
||||
val superTypeParameters = superDescriptor.typeParameters
|
||||
val subTypeParameters = subDescriptor.typeParameters
|
||||
@@ -812,8 +835,8 @@ class OverrideResolver(
|
||||
}
|
||||
|
||||
private fun isPropertyTypeOkForOverride(
|
||||
superDescriptor: PropertyDescriptor,
|
||||
subDescriptor: PropertyDescriptor
|
||||
superDescriptor: PropertyDescriptor,
|
||||
subDescriptor: PropertyDescriptor
|
||||
): Boolean {
|
||||
val typeSubstitutor = prepareTypeSubstitutor(superDescriptor, subDescriptor) ?: return false
|
||||
|
||||
@@ -821,8 +844,7 @@ class OverrideResolver(
|
||||
|
||||
return if (superDescriptor.isVar) {
|
||||
KotlinTypeChecker.DEFAULT.equalTypes(subDescriptor.type, substitutedSuperReturnType)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
KotlinTypeChecker.DEFAULT.isSubtypeOf(subDescriptor.type, substitutedSuperReturnType)
|
||||
}
|
||||
}
|
||||
@@ -840,8 +862,8 @@ class OverrideResolver(
|
||||
}
|
||||
|
||||
private fun findInvisibleOverriddenDescriptor(
|
||||
declared: CallableMemberDescriptor,
|
||||
declaringClass: ClassDescriptor
|
||||
declared: CallableMemberDescriptor,
|
||||
declaringClass: ClassDescriptor
|
||||
): CallableMemberDescriptor? {
|
||||
for (supertype in declaringClass.typeConstructor.supertypes) {
|
||||
val all = Sets.newLinkedHashSet<CallableMemberDescriptor>()
|
||||
@@ -850,8 +872,10 @@ class OverrideResolver(
|
||||
for (fromSuper in all) {
|
||||
if (OverridingUtil.DEFAULT.isOverridableBy(fromSuper, declared, null).result == OVERRIDABLE) {
|
||||
if (OverridingUtil.isVisibleForOverride(declared, fromSuper)) {
|
||||
throw IllegalStateException("Descriptor " + fromSuper + " is overridable by " + declared +
|
||||
" and visible but does not appear in its getOverriddenDescriptors()")
|
||||
throw IllegalStateException(
|
||||
"Descriptor " + fromSuper + " is overridable by " + declared +
|
||||
" and visible but does not appear in its getOverriddenDescriptors()"
|
||||
)
|
||||
}
|
||||
return fromSuper
|
||||
}
|
||||
@@ -861,12 +885,12 @@ class OverrideResolver(
|
||||
}
|
||||
|
||||
fun shouldReportParameterNameOverrideWarning(
|
||||
parameterFromSubclass: ValueParameterDescriptor,
|
||||
parameterFromSuperclass: ValueParameterDescriptor
|
||||
parameterFromSubclass: ValueParameterDescriptor,
|
||||
parameterFromSuperclass: ValueParameterDescriptor
|
||||
): Boolean {
|
||||
return parameterFromSubclass.containingDeclaration.hasStableParameterNames() &&
|
||||
parameterFromSuperclass.containingDeclaration.hasStableParameterNames() &&
|
||||
parameterFromSuperclass.name != parameterFromSubclass.name
|
||||
parameterFromSuperclass.containingDeclaration.hasStableParameterNames() &&
|
||||
parameterFromSuperclass.name != parameterFromSubclass.name
|
||||
}
|
||||
|
||||
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>?>
|
||||
}
|
||||
|
||||
interface TypeArgumentBinding<out P: PsiElement> : TypeHolderArgument<TypeBinding<P>>
|
||||
interface TypeArgumentBinding<out P : PsiElement> : TypeHolderArgument<TypeBinding<P>>
|
||||
|
||||
fun KtTypeReference.createTypeBinding(trace: BindingContext): TypeBinding<KtTypeElement>? {
|
||||
val type = trace[BindingContext.TYPE, this]
|
||||
@@ -51,7 +51,7 @@ private fun createTypeBindingFromPsi(trace: BindingContext, psiElement: KtTypeEl
|
||||
ExplicitTypeBinding(trace, psiElement, type)
|
||||
}
|
||||
|
||||
fun KtCallableDeclaration.createTypeBindingForReturnType(trace: BindingContext): TypeBinding<PsiElement>? {
|
||||
fun KtCallableDeclaration.createTypeBindingForReturnType(trace: BindingContext): TypeBinding<PsiElement>? {
|
||||
val jetTypeReference = typeReference
|
||||
if (jetTypeReference != null) return jetTypeReference.createTypeBinding(trace)
|
||||
|
||||
@@ -61,16 +61,16 @@ fun KtCallableDeclaration.createTypeBindingForReturnType(trace: BindingContext):
|
||||
return descriptor.returnType?.let { NoTypeElementBinding(trace, this, it) }
|
||||
}
|
||||
|
||||
private class TypeArgumentBindingImpl<out P: PsiElement>(
|
||||
override val projection: TypeProjection,
|
||||
override val typeParameter: TypeParameterDescriptor?,
|
||||
override val holder: TypeBinding<P>
|
||||
private class TypeArgumentBindingImpl<out P : PsiElement>(
|
||||
override val projection: TypeProjection,
|
||||
override val typeParameter: TypeParameterDescriptor?,
|
||||
override val holder: TypeBinding<P>
|
||||
) : TypeArgumentBinding<P>
|
||||
|
||||
private class ExplicitTypeBinding(
|
||||
private val trace: BindingContext,
|
||||
override val psiElement: KtTypeElement,
|
||||
override val type: KotlinType
|
||||
private val trace: BindingContext,
|
||||
override val psiElement: KtTypeElement,
|
||||
override val type: KotlinType
|
||||
) : TypeBinding<KtTypeElement> {
|
||||
override val isInAbbreviation: Boolean get() = false
|
||||
|
||||
@@ -80,7 +80,7 @@ private class ExplicitTypeBinding(
|
||||
assert(type.getAbbreviatedType() == null) { "Non-abbreviated type expected: $type" }
|
||||
val isErrorBinding = run {
|
||||
val sizeIsEqual = psiTypeArguments.size == type.arguments.size
|
||||
&& psiTypeArguments.size == type.constructor.parameters.size
|
||||
&& psiTypeArguments.size == type.constructor.parameters.size
|
||||
type.isError || !sizeIsEqual
|
||||
}
|
||||
|
||||
@@ -93,59 +93,57 @@ private class ExplicitTypeBinding(
|
||||
val nextJetType = trace[BindingContext.TYPE, jetTypeReference] ?: return@map null
|
||||
|
||||
return@map TypeArgumentBindingImpl(
|
||||
TypeProjectionImpl(nextJetType),
|
||||
null,
|
||||
createTypeBindingFromPsi(trace, jetTypeElement, nextJetType)
|
||||
TypeProjectionImpl(nextJetType),
|
||||
null,
|
||||
createTypeBindingFromPsi(trace, jetTypeElement, nextJetType)
|
||||
)
|
||||
}
|
||||
|
||||
val typeProjection = type.arguments[index]
|
||||
return@map TypeArgumentBindingImpl(
|
||||
typeProjection,
|
||||
type.constructor.parameters[index],
|
||||
createTypeBindingFromPsi(trace, jetTypeElement, typeProjection.type)
|
||||
typeProjection,
|
||||
type.constructor.parameters[index],
|
||||
createTypeBindingFromPsi(trace, jetTypeElement, typeProjection.type)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class AbbreviatedTypeBinding(
|
||||
override val type: KotlinType,
|
||||
override val psiElement: KtTypeElement
|
||||
): TypeBinding<KtTypeElement> {
|
||||
override val type: KotlinType,
|
||||
override val psiElement: KtTypeElement
|
||||
) : TypeBinding<KtTypeElement> {
|
||||
override val isInAbbreviation: Boolean get() = true
|
||||
|
||||
override val arguments: List<TypeArgumentBinding<KtTypeElement>?>
|
||||
get() = createTypeArgumentBindingsWithSinglePsiElement(type) {
|
||||
argumentType ->
|
||||
get() = createTypeArgumentBindingsWithSinglePsiElement(type) { argumentType ->
|
||||
AbbreviatedTypeBinding(argumentType, psiElement)
|
||||
}
|
||||
}
|
||||
|
||||
private class NoTypeElementBinding<out P : PsiElement>(
|
||||
private val trace: BindingContext,
|
||||
override val psiElement: P,
|
||||
override val type: KotlinType
|
||||
): TypeBinding<P> {
|
||||
private val trace: BindingContext,
|
||||
override val psiElement: P,
|
||||
override val type: KotlinType
|
||||
) : TypeBinding<P> {
|
||||
override val isInAbbreviation: Boolean get() = false
|
||||
|
||||
override val arguments: List<TypeArgumentBinding<P>?>
|
||||
get() = createTypeArgumentBindingsWithSinglePsiElement(type) {
|
||||
argumentType ->
|
||||
get() = createTypeArgumentBindingsWithSinglePsiElement(type) { argumentType ->
|
||||
NoTypeElementBinding(trace, psiElement, argumentType)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun <P : PsiElement> createTypeArgumentBindingsWithSinglePsiElement(
|
||||
type: KotlinType,
|
||||
createBinding: (KotlinType) -> TypeBinding<P>
|
||||
) : List<TypeArgumentBinding<P>> {
|
||||
type: KotlinType,
|
||||
createBinding: (KotlinType) -> TypeBinding<P>
|
||||
): List<TypeArgumentBinding<P>> {
|
||||
val isErrorBinding = type.isError || type.constructor.parameters.size != type.arguments.size
|
||||
return type.arguments.mapIndexed { index, typeProjection ->
|
||||
TypeArgumentBindingImpl(
|
||||
typeProjection,
|
||||
if (isErrorBinding) null else type.constructor.parameters[index],
|
||||
createBinding(typeProjection.type)
|
||||
typeProjection,
|
||||
if (isErrorBinding) null else type.constructor.parameters[index],
|
||||
createBinding(typeProjection.type)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@ import org.jetbrains.kotlin.psi.KtPropertyAccessor
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class VariableAsPropertyInfo(
|
||||
val propertyGetter: KtPropertyAccessor?,
|
||||
val propertySetter: KtPropertyAccessor?,
|
||||
val variableType: KotlinType?,
|
||||
val hasBody: Boolean,
|
||||
val hasDelegate: Boolean
|
||||
val propertyGetter: KtPropertyAccessor?,
|
||||
val propertySetter: KtPropertyAccessor?,
|
||||
val variableType: KotlinType?,
|
||||
val hasBody: Boolean,
|
||||
val hasDelegate: Boolean
|
||||
) {
|
||||
companion object {
|
||||
fun createFromDestructuringDeclarationEntry(type: KotlinType): VariableAsPropertyInfo {
|
||||
|
||||
+1
-1
@@ -114,7 +114,7 @@ class VariableTypeAndInitializerResolver(
|
||||
if (!variable.hasInitializer() || variable.isVar) return
|
||||
variableDescriptor.setCompileTimeInitializer(
|
||||
storageManager.createRecursionTolerantNullableLazyValue(
|
||||
computeInitializer@{
|
||||
computeInitializer@ {
|
||||
if (!DescriptorUtils.shouldRecordInitializerForProperty(
|
||||
variableDescriptor,
|
||||
variableType
|
||||
|
||||
@@ -57,19 +57,19 @@ import org.jetbrains.kotlin.types.expressions.DataFlowAnalyzer
|
||||
import java.util.*
|
||||
|
||||
class CallCompleter(
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val candidateResolver: CandidateResolver,
|
||||
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
||||
private val callCheckers: Iterable<CallChecker>,
|
||||
private val builtIns: KotlinBuiltIns,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val deprecationResolver: DeprecationResolver,
|
||||
private val effectSystem: EffectSystem
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val candidateResolver: CandidateResolver,
|
||||
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
||||
private val callCheckers: Iterable<CallChecker>,
|
||||
private val builtIns: KotlinBuiltIns,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val deprecationResolver: DeprecationResolver,
|
||||
private val effectSystem: EffectSystem
|
||||
) {
|
||||
fun <D : CallableDescriptor> completeCall(
|
||||
context: BasicCallResolutionContext,
|
||||
results: OverloadResolutionResultsImpl<D>,
|
||||
tracing: TracingStrategy
|
||||
context: BasicCallResolutionContext,
|
||||
results: OverloadResolutionResultsImpl<D>,
|
||||
tracing: TracingStrategy
|
||||
): OverloadResolutionResultsImpl<D> {
|
||||
|
||||
val resolvedCall = if (results.isSingleResult) results.resultingCall else null
|
||||
@@ -87,8 +87,8 @@ class CallCompleter(
|
||||
else
|
||||
resolvedCall.call.calleeExpression
|
||||
val reportOn =
|
||||
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
|
||||
else resolvedCall.call.callElement
|
||||
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
|
||||
else resolvedCall.call.callElement
|
||||
|
||||
val callCheckerContext = CallCheckerContext(context, languageVersionSettings, deprecationResolver)
|
||||
for (callChecker in callCheckers) {
|
||||
@@ -107,30 +107,34 @@ class CallCompleter(
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> completeAllCandidates(
|
||||
context: BasicCallResolutionContext,
|
||||
results: OverloadResolutionResultsImpl<D>
|
||||
context: BasicCallResolutionContext,
|
||||
results: OverloadResolutionResultsImpl<D>
|
||||
) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val candidates = (if (context.collectAllCandidates) {
|
||||
results.allCandidates!!
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
results.resultingCalls
|
||||
}) as Collection<MutableResolvedCall<D>>
|
||||
|
||||
val temporaryBindingTrace = TemporaryBindingTrace.create(context.trace, "Trace to complete a candidate that is not a resulting call")
|
||||
candidates.filterNot { resolvedCall -> resolvedCall.isCompleted }.forEach {
|
||||
resolvedCall ->
|
||||
val temporaryBindingTrace =
|
||||
TemporaryBindingTrace.create(context.trace, "Trace to complete a candidate that is not a resulting call")
|
||||
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(
|
||||
resolvedCall: MutableResolvedCall<D>?,
|
||||
results: OverloadResolutionResultsImpl<D>,
|
||||
context: BasicCallResolutionContext,
|
||||
tracing: TracingStrategy
|
||||
resolvedCall: MutableResolvedCall<D>?,
|
||||
results: OverloadResolutionResultsImpl<D>,
|
||||
context: BasicCallResolutionContext,
|
||||
tracing: TracingStrategy
|
||||
) {
|
||||
if (resolvedCall == null || resolvedCall.isCompleted || resolvedCall.constraintSystem == null) {
|
||||
completeArguments(context, results)
|
||||
@@ -149,24 +153,23 @@ class CallCompleter(
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> MutableResolvedCall<D>.completeConstraintSystem(
|
||||
expectedType: KotlinType,
|
||||
trace: BindingTrace
|
||||
expectedType: KotlinType,
|
||||
trace: BindingTrace
|
||||
) {
|
||||
val returnType = candidateDescriptor.returnType
|
||||
|
||||
val expectedReturnType =
|
||||
if (call.isCallableReference()) {
|
||||
// TODO: compute generic type argument for R in the kotlin.Function<R> supertype (KT-12963)
|
||||
if (!TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) expectedType.getReturnTypeFromFunctionType()
|
||||
else TypeUtils.NO_EXPECTED_TYPE
|
||||
}
|
||||
else expectedType
|
||||
if (call.isCallableReference()) {
|
||||
// TODO: compute generic type argument for R in the kotlin.Function<R> supertype (KT-12963)
|
||||
if (!TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) expectedType.getReturnTypeFromFunctionType()
|
||||
else TypeUtils.NO_EXPECTED_TYPE
|
||||
} else expectedType
|
||||
|
||||
fun ConstraintSystem.Builder.typeInSystem(type: KotlinType?): KotlinType? =
|
||||
type?.let {
|
||||
val substitutor = typeVariableSubstitutors[call.toHandle()] ?: error("No substitutor for call: $call")
|
||||
substitutor.substitute(it, Variance.INVARIANT)
|
||||
}
|
||||
type?.let {
|
||||
val substitutor = typeVariableSubstitutors[call.toHandle()] ?: error("No substitutor for call: $call")
|
||||
substitutor.substitute(it, Variance.INVARIANT)
|
||||
}
|
||||
|
||||
fun updateSystemIfNeeded(buildSystemWithAdditionalConstraints: (ConstraintSystem.Builder) -> ConstraintSystem?) {
|
||||
val system = buildSystemWithAdditionalConstraints(constraintSystem!!.toBuilder())
|
||||
@@ -181,8 +184,7 @@ class CallCompleter(
|
||||
if (returnTypeInSystem != null) {
|
||||
builder.addSubtypeConstraint(returnTypeInSystem, expectedReturnType, EXPECTED_TYPE_POSITION.position())
|
||||
builder.build()
|
||||
}
|
||||
else null
|
||||
} else null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -206,17 +208,21 @@ class CallCompleter(
|
||||
builder.addSubtypeConstraint(returnTypeInSystem, builtIns.unitType, EXPECTED_TYPE_POSITION.position())
|
||||
val system = builder.build()
|
||||
if (system.status.isSuccessful()) system else null
|
||||
}
|
||||
else null
|
||||
} else null
|
||||
}
|
||||
}
|
||||
|
||||
if (call.isCallableReference() && !TypeUtils.noExpectedType(expectedType) && expectedType.isFunctionType) {
|
||||
updateSystemIfNeeded { builder ->
|
||||
candidateDescriptor.valueParameters.zip(expectedType.getValueParameterTypesFromFunctionType()).forEach { (parameter, argument) ->
|
||||
val valueParameterInSystem = builder.typeInSystem(parameter.type)
|
||||
builder.addSubtypeConstraint(valueParameterInSystem, argument.type, VALUE_PARAMETER_POSITION.position(parameter.index))
|
||||
}
|
||||
candidateDescriptor.valueParameters.zip(expectedType.getValueParameterTypesFromFunctionType())
|
||||
.forEach { (parameter, argument) ->
|
||||
val valueParameterInSystem = builder.typeInSystem(parameter.type)
|
||||
builder.addSubtypeConstraint(
|
||||
valueParameterInSystem,
|
||||
argument.type,
|
||||
VALUE_PARAMETER_POSITION.position(parameter.index)
|
||||
)
|
||||
}
|
||||
|
||||
builder.build()
|
||||
}
|
||||
@@ -231,8 +237,8 @@ class CallCompleter(
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> MutableResolvedCall<D>.updateResolutionStatusFromConstraintSystem(
|
||||
context: BasicCallResolutionContext,
|
||||
tracing: TracingStrategy
|
||||
context: BasicCallResolutionContext,
|
||||
tracing: TracingStrategy
|
||||
) {
|
||||
val contextWithResolvedCall = CallCandidateResolutionContext.createForCallBeingAnalyzed(this, context, tracing)
|
||||
val valueArgumentsCheckingResult = candidateResolver.checkAllValueArguments(contextWithResolvedCall, RESOLVE_FUNCTION_ARGUMENTS)
|
||||
@@ -248,8 +254,8 @@ class CallCompleter(
|
||||
val receiverType = extensionReceiver?.type
|
||||
|
||||
val errorData = InferenceErrorData.create(
|
||||
candidateDescriptor, constraintSystem!!, valueArgumentsCheckingResult.argumentTypes,
|
||||
receiverType, context.expectedType, context.call
|
||||
candidateDescriptor, constraintSystem!!, valueArgumentsCheckingResult.argumentTypes,
|
||||
receiverType, context.expectedType, context.call
|
||||
)
|
||||
tracing.typeInferenceFailed(context, errorData)
|
||||
|
||||
@@ -257,8 +263,8 @@ class CallCompleter(
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> completeArguments(
|
||||
context: BasicCallResolutionContext,
|
||||
results: OverloadResolutionResultsImpl<D>
|
||||
context: BasicCallResolutionContext,
|
||||
results: OverloadResolutionResultsImpl<D>
|
||||
) {
|
||||
if (context.checkArguments != CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS) return
|
||||
|
||||
@@ -268,8 +274,7 @@ class CallCompleter(
|
||||
val resolvedCall = results.resultingCall
|
||||
getArgumentMapping = { argument -> resolvedCall.getArgumentMapping(argument) }
|
||||
getDataFlowInfoForArgument = { argument -> resolvedCall.dataFlowInfoForArguments.getInfo(argument) }
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
getArgumentMapping = { ArgumentUnmapped }
|
||||
getDataFlowInfoForArgument = { context.dataFlowInfo }
|
||||
}
|
||||
@@ -278,21 +283,22 @@ class CallCompleter(
|
||||
val argumentMapping = getArgumentMapping(valueArgument!!)
|
||||
val (expectedType, callPosition) = when (argumentMapping) {
|
||||
is ArgumentMatch -> Pair(
|
||||
getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument, context),
|
||||
CallPosition.ValueArgumentPosition(results.resultingCall, argumentMapping.valueParameter, valueArgument))
|
||||
getEffectiveExpectedType(argumentMapping.valueParameter, valueArgument, context),
|
||||
CallPosition.ValueArgumentPosition(results.resultingCall, argumentMapping.valueParameter, valueArgument)
|
||||
)
|
||||
else -> Pair(TypeUtils.NO_EXPECTED_TYPE, CallPosition.Unknown)
|
||||
}
|
||||
val newContext =
|
||||
context.replaceDataFlowInfo(getDataFlowInfoForArgument(valueArgument))
|
||||
.replaceExpectedType(expectedType)
|
||||
.replaceCallPosition(callPosition)
|
||||
context.replaceDataFlowInfo(getDataFlowInfoForArgument(valueArgument))
|
||||
.replaceExpectedType(expectedType)
|
||||
.replaceCallPosition(callPosition)
|
||||
completeOneArgument(valueArgument, newContext)
|
||||
}
|
||||
}
|
||||
|
||||
private fun completeOneArgument(
|
||||
valueArgument: ValueArgument,
|
||||
context: BasicCallResolutionContext
|
||||
valueArgument: ValueArgument,
|
||||
context: BasicCallResolutionContext
|
||||
) {
|
||||
if (valueArgument.isExternal()) return
|
||||
|
||||
@@ -307,8 +313,7 @@ class CallCompleter(
|
||||
val resolvedCall = results.resultingCall
|
||||
updatedType = if (resolvedCall.hasInferredReturnType()) {
|
||||
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.),
|
||||
@@ -336,24 +341,24 @@ class CallCompleter(
|
||||
}
|
||||
|
||||
private fun completeCallForArgument(
|
||||
expression: KtExpression,
|
||||
context: BasicCallResolutionContext
|
||||
expression: KtExpression,
|
||||
context: BasicCallResolutionContext
|
||||
): OverloadResolutionResultsImpl<*>? {
|
||||
val cachedData = getResolutionResultsCachedData(expression, context) ?: return null
|
||||
val (cachedResolutionResults, cachedContext, tracing) = cachedData
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
private fun updateRecordedTypeForArgument(
|
||||
updatedType: KotlinType?,
|
||||
recordedType: KotlinType?,
|
||||
argumentExpression: KtExpression,
|
||||
statementFilter: StatementFilter,
|
||||
trace: BindingTrace
|
||||
updatedType: KotlinType?,
|
||||
recordedType: KotlinType?,
|
||||
argumentExpression: KtExpression,
|
||||
statementFilter: StatementFilter,
|
||||
trace: BindingTrace
|
||||
): KotlinType? {
|
||||
//workaround for KT-8218
|
||||
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
|
||||
|
||||
class CallExpressionResolver(
|
||||
private val callResolver: CallResolver,
|
||||
private val constantExpressionEvaluator: ConstantExpressionEvaluator,
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
||||
private val builtIns: KotlinBuiltIns,
|
||||
private val qualifiedExpressionResolver: QualifiedExpressionResolver,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
private val callResolver: CallResolver,
|
||||
private val constantExpressionEvaluator: ConstantExpressionEvaluator,
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val dataFlowAnalyzer: DataFlowAnalyzer,
|
||||
private val builtIns: KotlinBuiltIns,
|
||||
private val qualifiedExpressionResolver: QualifiedExpressionResolver,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
private lateinit var expressionTypingServices: ExpressionTypingServices
|
||||
|
||||
@@ -84,13 +84,16 @@ class CallExpressionResolver(
|
||||
}
|
||||
|
||||
private fun getResolvedCallForFunction(
|
||||
call: Call,
|
||||
context: ResolutionContext<*>,
|
||||
checkArguments: CheckArgumentTypesMode,
|
||||
initialDataFlowInfoForArguments: DataFlowInfo
|
||||
call: Call,
|
||||
context: ResolutionContext<*>,
|
||||
checkArguments: CheckArgumentTypesMode,
|
||||
initialDataFlowInfoForArguments: DataFlowInfo
|
||||
): Pair<Boolean, ResolvedCall<FunctionDescriptor>?> {
|
||||
val results = callResolver.resolveFunctionCall(BasicCallResolutionContext.create(
|
||||
context, call, checkArguments, DataFlowInfoForArgumentsImpl(initialDataFlowInfoForArguments, call)))
|
||||
val results = callResolver.resolveFunctionCall(
|
||||
BasicCallResolutionContext.create(
|
||||
context, call, checkArguments, DataFlowInfoForArgumentsImpl(initialDataFlowInfoForArguments, call)
|
||||
)
|
||||
)
|
||||
return if (!results.isNothing)
|
||||
Pair(true, OverloadResolutionResultsUtil.getResultingCall(results, context))
|
||||
else
|
||||
@@ -98,23 +101,25 @@ class CallExpressionResolver(
|
||||
}
|
||||
|
||||
private fun getVariableType(
|
||||
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
|
||||
callOperationNode: ASTNode?, context: ExpressionTypingContext
|
||||
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
|
||||
callOperationNode: ASTNode?, context: ExpressionTypingContext
|
||||
): Pair<Boolean, KotlinType?> {
|
||||
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 contextForVariable = BasicCallResolutionContext.create(
|
||||
context.replaceTraceAndCache(temporaryForVariable),
|
||||
call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS)
|
||||
context.replaceTraceAndCache(temporaryForVariable),
|
||||
call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS
|
||||
)
|
||||
val resolutionResult = callResolver.resolveSimpleProperty(contextForVariable)
|
||||
|
||||
// if the expression is a receiver in a qualified expression, it should be resolved after the selector is resolved
|
||||
val isLHSOfDot = KtPsiUtil.isLHSOfDot(nameExpression)
|
||||
if (!resolutionResult.isNothing && resolutionResult.resultCode != CANDIDATES_WITH_WRONG_RECEIVER) {
|
||||
val isQualifier = isLHSOfDot &&
|
||||
resolutionResult.isSingleResult &&
|
||||
resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject
|
||||
resolutionResult.isSingleResult &&
|
||||
resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject
|
||||
if (!isQualifier) {
|
||||
temporaryForVariable.commit()
|
||||
return Pair(true, if (resolutionResult.isSingleResult) resolutionResult.resultingDescriptor.returnType else null)
|
||||
@@ -122,25 +127,30 @@ class CallExpressionResolver(
|
||||
}
|
||||
|
||||
temporaryForVariable.commit()
|
||||
return Pair(!resolutionResult.isNothing,
|
||||
if (resolutionResult.isSingleResult) resolutionResult.resultingDescriptor.returnType else null)
|
||||
return Pair(
|
||||
!resolutionResult.isNothing,
|
||||
if (resolutionResult.isSingleResult) resolutionResult.resultingDescriptor.returnType else null
|
||||
)
|
||||
}
|
||||
|
||||
fun getSimpleNameExpressionTypeInfo(
|
||||
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
|
||||
callOperationNode: ASTNode?, context: ExpressionTypingContext
|
||||
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
|
||||
callOperationNode: ASTNode?, context: ExpressionTypingContext
|
||||
) = getSimpleNameExpressionTypeInfo(nameExpression, receiver, callOperationNode, context, context.dataFlowInfo)
|
||||
|
||||
private fun getSimpleNameExpressionTypeInfo(
|
||||
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
|
||||
callOperationNode: ASTNode?, context: ExpressionTypingContext,
|
||||
initialDataFlowInfoForArguments: DataFlowInfo
|
||||
nameExpression: KtSimpleNameExpression, receiver: Receiver?,
|
||||
callOperationNode: ASTNode?, context: ExpressionTypingContext,
|
||||
initialDataFlowInfoForArguments: DataFlowInfo
|
||||
): KotlinTypeInfo {
|
||||
|
||||
val temporaryForVariable = TemporaryTraceAndCache.create(
|
||||
context, "trace to resolve as variable", nameExpression)
|
||||
val (notNothing, type) = getVariableType(nameExpression, receiver, callOperationNode,
|
||||
context.replaceTraceAndCache(temporaryForVariable))
|
||||
context, "trace to resolve as variable", nameExpression
|
||||
)
|
||||
val (notNothing, type) = getVariableType(
|
||||
nameExpression, receiver, callOperationNode,
|
||||
context.replaceTraceAndCache(temporaryForVariable)
|
||||
)
|
||||
|
||||
if (notNothing) {
|
||||
temporaryForVariable.commit()
|
||||
@@ -149,10 +159,12 @@ class CallExpressionResolver(
|
||||
|
||||
val call = CallMaker.makeCall(nameExpression, receiver, callOperationNode, nameExpression, emptyList())
|
||||
val temporaryForFunction = TemporaryTraceAndCache.create(
|
||||
context, "trace to resolve as function", nameExpression)
|
||||
context, "trace to resolve as function", nameExpression
|
||||
)
|
||||
val newContext = context.replaceTraceAndCache(temporaryForFunction)
|
||||
val (resolveResult, resolvedCall) = getResolvedCallForFunction(
|
||||
call, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, initialDataFlowInfoForArguments)
|
||||
call, newContext, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS, initialDataFlowInfoForArguments
|
||||
)
|
||||
if (resolveResult) {
|
||||
val functionDescriptor = resolvedCall?.resultingDescriptor
|
||||
if (functionDescriptor !is ConstructorDescriptor) {
|
||||
@@ -173,11 +185,12 @@ class CallExpressionResolver(
|
||||
}
|
||||
|
||||
fun getCallExpressionTypeInfo(
|
||||
callExpression: KtCallExpression, receiver: ReceiverValue?,
|
||||
callOperationNode: ASTNode?, context: ExpressionTypingContext
|
||||
callExpression: KtCallExpression, receiver: ReceiverValue?,
|
||||
callOperationNode: ASTNode?, context: ExpressionTypingContext
|
||||
): KotlinTypeInfo {
|
||||
val typeInfo = getCallExpressionTypeInfoWithoutFinalTypeCheck(
|
||||
callExpression, receiver, callOperationNode, context, context.dataFlowInfo)
|
||||
callExpression, receiver, callOperationNode, context, context.dataFlowInfo
|
||||
)
|
||||
if (context.contextDependency == INDEPENDENT) {
|
||||
dataFlowAnalyzer.checkType(typeInfo.type, callExpression, context)
|
||||
}
|
||||
@@ -189,19 +202,21 @@ class CallExpressionResolver(
|
||||
* Determines the result type and data flow information after the call.
|
||||
*/
|
||||
private fun getCallExpressionTypeInfoWithoutFinalTypeCheck(
|
||||
callExpression: KtCallExpression, receiver: Receiver?,
|
||||
callOperationNode: ASTNode?, context: ExpressionTypingContext,
|
||||
initialDataFlowInfoForArguments: DataFlowInfo
|
||||
callExpression: KtCallExpression, receiver: Receiver?,
|
||||
callOperationNode: ASTNode?, context: ExpressionTypingContext,
|
||||
initialDataFlowInfoForArguments: DataFlowInfo
|
||||
): KotlinTypeInfo {
|
||||
val call = CallMaker.makeCall(receiver, callOperationNode, callExpression)
|
||||
|
||||
val temporaryForFunction = TemporaryTraceAndCache.create(
|
||||
context, "trace to resolve as function call", callExpression)
|
||||
context, "trace to resolve as function call", callExpression
|
||||
)
|
||||
val (resolveResult, resolvedCall) = getResolvedCallForFunction(
|
||||
call,
|
||||
context.replaceTraceAndCache(temporaryForFunction),
|
||||
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||
initialDataFlowInfoForArguments)
|
||||
call,
|
||||
context.replaceTraceAndCache(temporaryForFunction),
|
||||
CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||
initialDataFlowInfoForArguments
|
||||
)
|
||||
if (resolveResult) {
|
||||
val functionDescriptor = resolvedCall?.resultingDescriptor
|
||||
temporaryForFunction.commit()
|
||||
@@ -246,9 +261,12 @@ class CallExpressionResolver(
|
||||
val calleeExpression = callExpression.calleeExpression
|
||||
if (calleeExpression is KtSimpleNameExpression && callExpression.typeArgumentList == null) {
|
||||
val temporaryForVariable = TemporaryTraceAndCache.create(
|
||||
context, "trace to resolve as variable with 'invoke' call", callExpression)
|
||||
val (notNothing, type) = getVariableType(calleeExpression, receiver, callOperationNode,
|
||||
context.replaceTraceAndCache(temporaryForVariable))
|
||||
context, "trace to resolve as variable with 'invoke' call", callExpression
|
||||
)
|
||||
val (notNothing, type) = getVariableType(
|
||||
calleeExpression, receiver, callOperationNode,
|
||||
context.replaceTraceAndCache(temporaryForVariable)
|
||||
)
|
||||
val qualifier = temporaryForVariable.trace.get(BindingContext.QUALIFIER, calleeExpression)
|
||||
if (notNothing && (qualifier == null || qualifier !is PackageQualifier)) {
|
||||
|
||||
@@ -258,14 +276,18 @@ class CallExpressionResolver(
|
||||
}
|
||||
|
||||
temporaryForVariable.commit()
|
||||
context.trace.report(FUNCTION_EXPECTED.on(calleeExpression, calleeExpression,
|
||||
type ?: ErrorUtils.createErrorType("")))
|
||||
context.trace.report(
|
||||
FUNCTION_EXPECTED.on(
|
||||
calleeExpression, calleeExpression,
|
||||
type ?: ErrorUtils.createErrorType("")
|
||||
)
|
||||
)
|
||||
argumentTypeResolver.analyzeArgumentsAndRecordTypes(
|
||||
BasicCallResolutionContext.create(
|
||||
context, call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||
DataFlowInfoForArgumentsImpl(initialDataFlowInfoForArguments, call)
|
||||
),
|
||||
ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS
|
||||
BasicCallResolutionContext.create(
|
||||
context, call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS,
|
||||
DataFlowInfoForArgumentsImpl(initialDataFlowInfoForArguments, call)
|
||||
),
|
||||
ResolveArgumentsMode.RESOLVE_FUNCTION_ARGUMENTS
|
||||
)
|
||||
return noTypeInfo(context)
|
||||
}
|
||||
@@ -275,41 +297,41 @@ class CallExpressionResolver(
|
||||
}
|
||||
|
||||
private fun KtQualifiedExpression.elementChain(context: ExpressionTypingContext) =
|
||||
qualifiedExpressionResolver.resolveQualifierInExpressionAndUnroll(this, context) {
|
||||
nameExpression ->
|
||||
val resolutionResult = resolveSimpleName(context, nameExpression)
|
||||
qualifiedExpressionResolver.resolveQualifierInExpressionAndUnroll(this, context) { nameExpression ->
|
||||
val resolutionResult = resolveSimpleName(context, nameExpression)
|
||||
|
||||
if (resolutionResult.isSingleResult && resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject) {
|
||||
false
|
||||
}
|
||||
else when (resolutionResult.resultCode) {
|
||||
NAME_NOT_FOUND, CANDIDATES_WITH_WRONG_RECEIVER -> false
|
||||
else -> !context.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) || resolutionResult.isSuccess
|
||||
}
|
||||
if (resolutionResult.isSingleResult && resolutionResult.resultingDescriptor is FakeCallableDescriptorForObject) {
|
||||
false
|
||||
} else when (resolutionResult.resultCode) {
|
||||
NAME_NOT_FOUND, CANDIDATES_WITH_WRONG_RECEIVER -> false
|
||||
else -> !context.languageVersionSettings.supportsFeature(LanguageFeature.NewInference) || resolutionResult.isSuccess
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveSimpleName(
|
||||
context: ExpressionTypingContext, expression: KtSimpleNameExpression
|
||||
context: ExpressionTypingContext, expression: KtSimpleNameExpression
|
||||
): OverloadResolutionResults<VariableDescriptor> {
|
||||
val temporaryForVariable = TemporaryTraceAndCache.create(context, "trace to resolve as local variable or property", expression)
|
||||
val call = CallMaker.makePropertyCall(null, null, expression)
|
||||
val contextForVariable = BasicCallResolutionContext.create(
|
||||
context.replaceTraceAndCache(temporaryForVariable), call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS
|
||||
context.replaceTraceAndCache(temporaryForVariable), call, CheckArgumentTypesMode.CHECK_VALUE_ARGUMENTS
|
||||
)
|
||||
return callResolver.resolveSimpleProperty(contextForVariable)
|
||||
}
|
||||
|
||||
private fun getUnsafeSelectorTypeInfo(
|
||||
receiver: Receiver,
|
||||
callOperationNode: ASTNode?,
|
||||
selectorExpression: KtExpression?,
|
||||
context: ExpressionTypingContext,
|
||||
initialDataFlowInfoForArguments: DataFlowInfo
|
||||
receiver: Receiver,
|
||||
callOperationNode: ASTNode?,
|
||||
selectorExpression: KtExpression?,
|
||||
context: ExpressionTypingContext,
|
||||
initialDataFlowInfoForArguments: DataFlowInfo
|
||||
): KotlinTypeInfo = when (selectorExpression) {
|
||||
is KtCallExpression -> getCallExpressionTypeInfoWithoutFinalTypeCheck(
|
||||
selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments)
|
||||
selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments
|
||||
)
|
||||
is KtSimpleNameExpression -> getSimpleNameExpressionTypeInfo(
|
||||
selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments)
|
||||
selectorExpression, receiver, callOperationNode, context, initialDataFlowInfoForArguments
|
||||
)
|
||||
is KtExpression -> {
|
||||
expressionTypingServices.getTypeInfo(selectorExpression, context)
|
||||
context.trace.report(ILLEGAL_SELECTOR.on(selectorExpression))
|
||||
@@ -323,14 +345,14 @@ class CallExpressionResolver(
|
||||
var initialDataFlowInfoForArguments = context.dataFlowInfo
|
||||
val receiverDataFlowValue = (receiver as? ReceiverValue)?.let { DataFlowValueFactory.createDataFlowValue(it, context) }
|
||||
val receiverCanBeNull = receiverDataFlowValue != null &&
|
||||
initialDataFlowInfoForArguments.getStableNullability(receiverDataFlowValue).canBeNull()
|
||||
initialDataFlowInfoForArguments.getStableNullability(receiverDataFlowValue).canBeNull()
|
||||
if (receiverDataFlowValue != null && element.safe) {
|
||||
// Additional "receiver != null" information should be applied if we consider a safe call
|
||||
if (receiverCanBeNull) {
|
||||
initialDataFlowInfoForArguments = initialDataFlowInfoForArguments.disequate(
|
||||
receiverDataFlowValue, DataFlowValue.nullValue(builtIns), languageVersionSettings)
|
||||
}
|
||||
else if (receiver is ReceiverValue) {
|
||||
receiverDataFlowValue, DataFlowValue.nullValue(builtIns), languageVersionSettings
|
||||
)
|
||||
} else if (receiver is ReceiverValue) {
|
||||
reportUnnecessarySafeCall(context.trace, receiver.type, element.node, receiver)
|
||||
}
|
||||
}
|
||||
@@ -361,8 +383,7 @@ class CallExpressionResolver(
|
||||
val value = constantExpressionEvaluator.evaluateExpression(qualified, context.trace, context.expectedType)
|
||||
return if (value != null && value.isPure) {
|
||||
dataFlowAnalyzer.createCompileTimeConstantTypeInfo(value, qualified, context)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (context.contextDependency == INDEPENDENT) {
|
||||
dataFlowAnalyzer.checkType(selectorTypeInfo.type, qualified, context)
|
||||
}
|
||||
@@ -409,20 +430,19 @@ class CallExpressionResolver(
|
||||
val receiverType = receiverTypeInfo.type ?: ErrorUtils.createErrorType("Type for " + element.receiver.text)
|
||||
|
||||
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 lastStage = qualifiedExpression === expression
|
||||
// Drop NO_EXPECTED_TYPE / INDEPENDENT at last stage
|
||||
val contextForSelector = (if (lastStage) context else currentContext).replaceDataFlowInfo(
|
||||
if (receiver is ReceiverValue && TypeUtils.isNullableType(receiver.type) && !element.safe) {
|
||||
// Call with nullable receiver: take data flow info from branch point
|
||||
branchPointDataFlowInfo
|
||||
}
|
||||
else {
|
||||
// Take data flow info from the current receiver
|
||||
receiverTypeInfo.dataFlowInfo
|
||||
}
|
||||
if (receiver is ReceiverValue && TypeUtils.isNullableType(receiver.type) && !element.safe) {
|
||||
// Call with nullable receiver: take data flow info from branch point
|
||||
branchPointDataFlowInfo
|
||||
} else {
|
||||
// Take data flow info from the current receiver
|
||||
receiverTypeInfo.dataFlowInfo
|
||||
}
|
||||
)
|
||||
|
||||
val selectorTypeInfo = getSafeOrUnsafeSelectorTypeInfo(receiver, element, contextForSelector)
|
||||
@@ -432,8 +452,9 @@ class CallExpressionResolver(
|
||||
branchPointDataFlowInfo = selectorTypeInfo.dataFlowInfo
|
||||
}
|
||||
|
||||
resultTypeInfo = checkSelectorTypeInfo(qualifiedExpression, selectorTypeInfo, contextForSelector).
|
||||
replaceDataFlowInfo(branchPointDataFlowInfo)
|
||||
resultTypeInfo = checkSelectorTypeInfo(qualifiedExpression, selectorTypeInfo, contextForSelector).replaceDataFlowInfo(
|
||||
branchPointDataFlowInfo
|
||||
)
|
||||
if (!lastStage) {
|
||||
recordResultTypeInfo(qualifiedExpression, resultTypeInfo, contextForSelector)
|
||||
}
|
||||
@@ -444,9 +465,9 @@ class CallExpressionResolver(
|
||||
}
|
||||
|
||||
private fun resolveDeferredReceiverInQualifiedExpression(
|
||||
qualifier: Qualifier,
|
||||
selectorExpression: KtExpression?,
|
||||
context: ExpressionTypingContext
|
||||
qualifier: Qualifier,
|
||||
selectorExpression: KtExpression?,
|
||||
context: ExpressionTypingContext
|
||||
) {
|
||||
val calleeExpression = KtPsiUtil.deparenthesize(selectorExpression.getCalleeExpressionIfAny())
|
||||
val selectorDescriptor = (calleeExpression as? KtReferenceExpression)?.let {
|
||||
@@ -469,33 +490,31 @@ class CallExpressionResolver(
|
||||
if (parent != null) {
|
||||
return isUnderAnnotationClassDeclaration(trace, parent)
|
||||
}
|
||||
}
|
||||
else if (parent is KtParameter) {
|
||||
} else if (parent is KtParameter) {
|
||||
return isUnderAnnotationClassDeclaration(trace, parent)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isUnderAnnotationClassDeclaration(trace: BindingTrace, parent: PsiElement) =
|
||||
parent.getParentOfType<KtClass>(true)?.let {
|
||||
DescriptorUtils.isAnnotationClass(trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, it))
|
||||
} ?: false
|
||||
parent.getParentOfType<KtClass>(true)?.let {
|
||||
DescriptorUtils.isAnnotationClass(trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, it))
|
||||
} ?: false
|
||||
|
||||
fun reportUnnecessarySafeCall(
|
||||
trace: BindingTrace, type: KotlinType,
|
||||
callOperationNode: ASTNode, explicitReceiver: Receiver?
|
||||
trace: BindingTrace, type: KotlinType,
|
||||
callOperationNode: ASTNode, explicitReceiver: Receiver?
|
||||
) = trace.report(
|
||||
if (explicitReceiver is ExpressionReceiver && explicitReceiver.expression is KtSuperExpression) {
|
||||
UNEXPECTED_SAFE_CALL.on(callOperationNode.psi)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
UNNECESSARY_SAFE_CALL.on(callOperationNode.psi, type)
|
||||
}
|
||||
)
|
||||
|
||||
private fun checkNestedClassAccess(
|
||||
expression: KtQualifiedExpression,
|
||||
context: ExpressionTypingContext
|
||||
expression: KtQualifiedExpression,
|
||||
context: ExpressionTypingContext
|
||||
) {
|
||||
val selectorExpression = expression.selectorExpression ?: return
|
||||
|
||||
|
||||
@@ -80,13 +80,13 @@ fun replaceReturnTypeForCallable(type: KotlinType, given: KotlinType): KotlinTyp
|
||||
fun replaceReturnTypeByUnknown(type: KotlinType) = replaceReturnTypeForCallable(type, DONT_CARE)
|
||||
|
||||
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) =
|
||||
type.arguments.dropLast(1)
|
||||
type.arguments.dropLast(1)
|
||||
|
||||
fun getReturnTypeForCallable(type: KotlinType) =
|
||||
type.arguments.last().type
|
||||
type.arguments.last().type
|
||||
|
||||
private fun CallableDescriptor.hasReturnTypeDependentOnUninferredParams(constraintSystem: ConstraintSystem): Boolean {
|
||||
val returnType = returnType ?: return false
|
||||
@@ -125,8 +125,10 @@ fun getErasedReceiverType(receiverParameterDescriptor: ReceiverParameterDescript
|
||||
receiverType.constructor
|
||||
}
|
||||
|
||||
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(receiverType.annotations, receiverTypeConstructor, fakeTypeArguments,
|
||||
receiverType.isMarkedNullable, ErrorUtils.createErrorScope("Error scope for erased receiver type", /*throwExceptions=*/true))
|
||||
return KotlinTypeFactory.simpleTypeWithNonTrivialMemberScope(
|
||||
receiverType.annotations, receiverTypeConstructor, fakeTypeArguments,
|
||||
receiverType.isMarkedNullable, ErrorUtils.createErrorScope("Error scope for erased receiver type", /*throwExceptions=*/true)
|
||||
)
|
||||
}
|
||||
|
||||
fun isOrOverridesSynthesized(descriptor: CallableMemberDescriptor): Boolean {
|
||||
@@ -163,7 +165,7 @@ fun isInfixCall(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 {
|
||||
if (call.callType !== Call.CallType.INVOKE) return false
|
||||
@@ -183,9 +185,9 @@ fun getSuperCallExpression(call: Call): KtSuperExpression? {
|
||||
}
|
||||
|
||||
fun getEffectiveExpectedType(
|
||||
parameterDescriptor: ValueParameterDescriptor,
|
||||
argument: ValueArgument,
|
||||
context: ResolutionContext<*>
|
||||
parameterDescriptor: ValueParameterDescriptor,
|
||||
argument: ValueArgument,
|
||||
context: ResolutionContext<*>
|
||||
): KotlinType {
|
||||
if (argument.getSpreadElement() != null || shouldCheckAsArray(parameterDescriptor, argument, context)) {
|
||||
if (parameterDescriptor.varargElementType == null) {
|
||||
@@ -203,9 +205,9 @@ fun getEffectiveExpectedType(
|
||||
}
|
||||
|
||||
private fun shouldCheckAsArray(
|
||||
parameterDescriptor: ValueParameterDescriptor,
|
||||
argument: ValueArgument,
|
||||
context: ResolutionContext<*>
|
||||
parameterDescriptor: ValueParameterDescriptor,
|
||||
argument: ValueArgument,
|
||||
context: ResolutionContext<*>
|
||||
): Boolean {
|
||||
if (!context.languageVersionSettings.supportsFeature(LanguageFeature.AssigningArraysToVarargsInNamedFormInAnnotations)) return false
|
||||
|
||||
@@ -223,29 +225,30 @@ fun isArrayOrArrayLiteral(argument: ValueArgument, context: ResolutionContext<*>
|
||||
}
|
||||
|
||||
fun createResolutionCandidatesForConstructors(
|
||||
lexicalScope: LexicalScope,
|
||||
call: Call,
|
||||
typeWithConstructors: KotlinType,
|
||||
useKnownTypeSubstitutor: Boolean,
|
||||
syntheticScopes: SyntheticScopes
|
||||
lexicalScope: LexicalScope,
|
||||
call: Call,
|
||||
typeWithConstructors: KotlinType,
|
||||
useKnownTypeSubstitutor: Boolean,
|
||||
syntheticScopes: SyntheticScopes
|
||||
): List<ResolutionCandidate<ConstructorDescriptor>> {
|
||||
val classWithConstructors = typeWithConstructors.constructor.declarationDescriptor as ClassDescriptor
|
||||
|
||||
val unwrappedType = typeWithConstructors.unwrap()
|
||||
val knownSubstitutor =
|
||||
if (useKnownTypeSubstitutor)
|
||||
TypeSubstitutor.create(
|
||||
(unwrappedType as? AbbreviatedType)?.abbreviation ?: unwrappedType
|
||||
)
|
||||
else null
|
||||
if (useKnownTypeSubstitutor)
|
||||
TypeSubstitutor.create(
|
||||
(unwrappedType as? AbbreviatedType)?.abbreviation ?: unwrappedType
|
||||
)
|
||||
else null
|
||||
|
||||
val typeAliasDescriptor =
|
||||
if (unwrappedType is AbbreviatedType)
|
||||
unwrappedType.abbreviation.constructor.declarationDescriptor as? TypeAliasDescriptor
|
||||
else
|
||||
null
|
||||
if (unwrappedType is AbbreviatedType)
|
||||
unwrappedType.abbreviation.constructor.declarationDescriptor as? TypeAliasDescriptor
|
||||
else
|
||||
null
|
||||
|
||||
val constructors = typeAliasDescriptor?.constructors?.mapNotNull(TypeAliasConstructorDescriptor::withDispatchReceiver) ?: classWithConstructors.constructors
|
||||
val constructors = typeAliasDescriptor?.constructors?.mapNotNull(TypeAliasConstructorDescriptor::withDispatchReceiver)
|
||||
?: classWithConstructors.constructors
|
||||
|
||||
if (constructors.isEmpty()) return emptyList()
|
||||
|
||||
@@ -262,8 +265,7 @@ fun createResolutionCandidatesForConstructors(
|
||||
|
||||
receiverKind = ExplicitReceiverKind.DISPATCH_RECEIVER
|
||||
dispatchReceiver = receiver.value
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
receiverKind = ExplicitReceiverKind.NO_EXPLICIT_RECEIVER
|
||||
dispatchReceiver = null
|
||||
}
|
||||
@@ -276,12 +278,12 @@ fun createResolutionCandidatesForConstructors(
|
||||
}
|
||||
|
||||
fun KtLambdaExpression.getCorrespondingParameterForFunctionArgument(
|
||||
bindingContext: BindingContext
|
||||
bindingContext: BindingContext
|
||||
): ValueParameterDescriptor? {
|
||||
val resolvedCall = KtPsiUtil.getParentCallIfPresent(this)?.getResolvedCall(bindingContext) ?: return null
|
||||
val valueArgument =
|
||||
resolvedCall.call.getValueArgumentForExpression(this)
|
||||
?: return null
|
||||
resolvedCall.call.getValueArgumentForExpression(this)
|
||||
?: return null
|
||||
val mapping = resolvedCall.getArgumentMapping(valueArgument) as? ArgumentMatch ?: return null
|
||||
|
||||
return mapping.valueParameter
|
||||
|
||||
@@ -57,15 +57,15 @@ import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||
import java.util.*
|
||||
|
||||
class CandidateResolver(
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val genericCandidateResolver: GenericCandidateResolver,
|
||||
private val reflectionTypes: ReflectionTypes,
|
||||
private val additionalTypeCheckers: Iterable<AdditionalTypeChecker>,
|
||||
private val smartCastManager: SmartCastManager
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val genericCandidateResolver: GenericCandidateResolver,
|
||||
private val reflectionTypes: ReflectionTypes,
|
||||
private val additionalTypeCheckers: Iterable<AdditionalTypeChecker>,
|
||||
private val smartCastManager: SmartCastManager
|
||||
) {
|
||||
fun <D : CallableDescriptor> performResolutionForCandidateCall(
|
||||
context: CallCandidateResolutionContext<D>,
|
||||
checkArguments: CheckArgumentTypesMode
|
||||
context: CallCandidateResolutionContext<D>,
|
||||
checkArguments: CheckArgumentTypesMode
|
||||
): Unit = with(context) {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
|
||||
|
||||
@@ -107,8 +107,7 @@ class CandidateResolver(
|
||||
&& candidateCall.knownTypeParametersSubstitutor == null
|
||||
) {
|
||||
genericCandidateResolver.inferTypeArguments(this)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
checkAllValueArguments(this, SHAPE_FUNCTION_ARGUMENTS).status
|
||||
}
|
||||
}
|
||||
@@ -117,8 +116,7 @@ class CandidateResolver(
|
||||
val ktTypeArguments = call.typeArguments
|
||||
if (candidateCall.knownTypeParametersSubstitutor != null) {
|
||||
candidateCall.setResultingSubstitutor(candidateCall.knownTypeParametersSubstitutor!!)
|
||||
}
|
||||
else if (ktTypeArguments.isNotEmpty()) {
|
||||
} else if (ktTypeArguments.isNotEmpty()) {
|
||||
// Explicit type arguments passed
|
||||
|
||||
val typeArguments = ArrayList<KotlinType>()
|
||||
@@ -130,9 +128,11 @@ class CandidateResolver(
|
||||
|
||||
val expectedTypeArgumentCount = candidateDescriptor.typeParameters.size
|
||||
for (index in ktTypeArguments.size..expectedTypeArgumentCount - 1) {
|
||||
typeArguments.add(ErrorUtils.createErrorType(
|
||||
typeArguments.add(
|
||||
ErrorUtils.createErrorType(
|
||||
"Explicit type argument expected for " + candidateDescriptor.typeParameters[index].name
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
val substitution = FunctionDescriptorUtil.createSubstitution(candidateDescriptor as FunctionDescriptor, typeArguments)
|
||||
val substitutor = TypeSubstitutor.create(SubstitutionFilteringInternalResolveAnnotations(substitution))
|
||||
@@ -140,8 +140,7 @@ class CandidateResolver(
|
||||
if (expectedTypeArgumentCount != ktTypeArguments.size) {
|
||||
candidateCall.addStatus(WRONG_NUMBER_OF_TYPE_ARGUMENTS_ERROR)
|
||||
tracing.wrongNumberOfTypeArguments(trace, expectedTypeArgumentCount, candidateDescriptor)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
checkGenericBoundsInAFunctionCall(ktTypeArguments, typeArguments, candidateDescriptor, substitutor, trace)
|
||||
}
|
||||
|
||||
@@ -149,31 +148,30 @@ class CandidateResolver(
|
||||
}
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.mapArguments()
|
||||
= check {
|
||||
val argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(
|
||||
call, tracing, candidateCall)
|
||||
if (!argumentMappingStatus.isSuccess) {
|
||||
candidateCall.addStatus(ARGUMENTS_MAPPING_ERROR)
|
||||
}
|
||||
}
|
||||
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.mapArguments() = check {
|
||||
val argumentMappingStatus = ValueArgumentsToParametersMapper.mapValueArgumentsToParameters(
|
||||
call, tracing, candidateCall
|
||||
)
|
||||
if (!argumentMappingStatus.isSuccess) {
|
||||
candidateCall.addStatus(ARGUMENTS_MAPPING_ERROR)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkExpectedCallableType()
|
||||
= check {
|
||||
if (!noExpectedType(expectedType)) {
|
||||
val candidateKCallableType = DoubleColonExpressionResolver.createKCallableTypeForReference(
|
||||
candidateCall.candidateDescriptor,
|
||||
(call.callElement.parent as? KtCallableReferenceExpression)?.receiverExpression?.let {
|
||||
trace.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, it)
|
||||
},
|
||||
reflectionTypes, scope.ownerDescriptor
|
||||
)
|
||||
if (candidateKCallableType == null ||
|
||||
!canBeSubtype(candidateKCallableType, expectedType, candidateCall.candidateDescriptor.typeParameters)) {
|
||||
candidateCall.addStatus(OTHER_ERROR)
|
||||
}
|
||||
}
|
||||
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkExpectedCallableType() = check {
|
||||
if (!noExpectedType(expectedType)) {
|
||||
val candidateKCallableType = DoubleColonExpressionResolver.createKCallableTypeForReference(
|
||||
candidateCall.candidateDescriptor,
|
||||
(call.callElement.parent as? KtCallableReferenceExpression)?.receiverExpression?.let {
|
||||
trace.bindingContext.get(BindingContext.DOUBLE_COLON_LHS, it)
|
||||
},
|
||||
reflectionTypes, scope.ownerDescriptor
|
||||
)
|
||||
if (candidateKCallableType == null ||
|
||||
!canBeSubtype(candidateKCallableType, expectedType, candidateCall.candidateDescriptor.typeParameters)) {
|
||||
candidateCall.addStatus(OTHER_ERROR)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -191,11 +189,12 @@ class CandidateResolver(
|
||||
}
|
||||
|
||||
private fun CallCandidateResolutionContext<*>.checkVisibilityWithDispatchReceiver(
|
||||
receiverArgument: ReceiverValue?,
|
||||
smartCastType: KotlinType?
|
||||
receiverArgument: ReceiverValue?,
|
||||
smartCastType: KotlinType?
|
||||
): ResolutionStatus {
|
||||
val invisibleMember = Visibilities.findInvisibleMember(
|
||||
getReceiverValueWithSmartCast(receiverArgument, smartCastType), candidateDescriptor, scope.ownerDescriptor)
|
||||
getReceiverValueWithSmartCast(receiverArgument, smartCastType), candidateDescriptor, scope.ownerDescriptor
|
||||
)
|
||||
return if (invisibleMember != null) {
|
||||
tracing.invisibleMember(trace, invisibleMember)
|
||||
INVISIBLE_MEMBER_ERROR
|
||||
@@ -205,17 +204,17 @@ class CandidateResolver(
|
||||
}
|
||||
|
||||
private fun CallCandidateResolutionContext<*>.isCandidateVisibleOrExtensionReceiver(
|
||||
receiverArgument: ReceiverValue?,
|
||||
smartCastType: KotlinType?,
|
||||
isDispatchReceiver: Boolean
|
||||
receiverArgument: ReceiverValue?,
|
||||
smartCastType: KotlinType?,
|
||||
isDispatchReceiver: Boolean
|
||||
) = !isDispatchReceiver || isCandidateVisible(receiverArgument, smartCastType)
|
||||
|
||||
private fun CallCandidateResolutionContext<*>.isCandidateVisible(
|
||||
receiverArgument: ReceiverValue?,
|
||||
smartCastType: KotlinType?
|
||||
receiverArgument: ReceiverValue?,
|
||||
smartCastType: KotlinType?
|
||||
) = Visibilities.findInvisibleMember(
|
||||
getReceiverValueWithSmartCast(receiverArgument, smartCastType),
|
||||
candidateDescriptor, scope.ownerDescriptor
|
||||
getReceiverValueWithSmartCast(receiverArgument, smartCastType),
|
||||
candidateDescriptor, scope.ownerDescriptor
|
||||
) == null
|
||||
|
||||
private fun CallCandidateResolutionContext<*>.checkExtensionReceiver() = checkAndReport {
|
||||
@@ -224,17 +223,14 @@ class CandidateResolver(
|
||||
if (receiverParameter != null && receiverArgument == null) {
|
||||
tracing.missingReceiver(candidateCall.trace, receiverParameter)
|
||||
OTHER_ERROR
|
||||
}
|
||||
else if (receiverParameter == null && receiverArgument != null) {
|
||||
} else if (receiverParameter == null && receiverArgument != null) {
|
||||
tracing.noReceiverAllowed(candidateCall.trace)
|
||||
if (call.calleeExpression is KtSimpleNameExpression) {
|
||||
RECEIVER_PRESENCE_ERROR
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
OTHER_ERROR
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
SUCCESS
|
||||
}
|
||||
}
|
||||
@@ -248,8 +244,7 @@ class CandidateResolver(
|
||||
&& DescriptorUtils.isStaticNestedClass(candidateDescriptor.containingDeclaration)
|
||||
) {
|
||||
nestedClass = candidateDescriptor.containingDeclaration
|
||||
}
|
||||
else if (candidateDescriptor is FakeCallableDescriptorForObject) {
|
||||
} else if (candidateDescriptor is FakeCallableDescriptorForObject) {
|
||||
nestedClass = candidateDescriptor.getReferencedObject()
|
||||
}
|
||||
if (nestedClass != null) {
|
||||
@@ -341,8 +336,9 @@ class CandidateResolver(
|
||||
}
|
||||
|
||||
fun <D : CallableDescriptor> checkAllValueArguments(
|
||||
context: CallCandidateResolutionContext<D>,
|
||||
resolveFunctionArgumentBodies: ResolveArgumentsMode): ValueArgumentsCheckingResult {
|
||||
context: CallCandidateResolutionContext<D>,
|
||||
resolveFunctionArgumentBodies: ResolveArgumentsMode
|
||||
): ValueArgumentsCheckingResult {
|
||||
val checkingResult = checkValueArgumentTypes(context, context.candidateCall, resolveFunctionArgumentBodies)
|
||||
var resultStatus = checkingResult.status
|
||||
resultStatus = resultStatus.combine(checkReceivers(context))
|
||||
@@ -351,9 +347,9 @@ class CandidateResolver(
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor, C : CallResolutionContext<C>> checkValueArgumentTypes(
|
||||
context: CallResolutionContext<C>,
|
||||
candidateCall: MutableResolvedCall<D>,
|
||||
resolveFunctionArgumentBodies: ResolveArgumentsMode
|
||||
context: CallResolutionContext<C>,
|
||||
candidateCall: MutableResolvedCall<D>,
|
||||
resolveFunctionArgumentBodies: ResolveArgumentsMode
|
||||
): ValueArgumentsCheckingResult {
|
||||
var resultStatus = SUCCESS
|
||||
val argumentTypes = Lists.newArrayList<KotlinType>()
|
||||
@@ -373,27 +369,26 @@ class CandidateResolver(
|
||||
var resultingType: KotlinType? = type
|
||||
if (type == null || (type.isError && !type.isFunctionPlaceholder)) {
|
||||
matchStatus = ArgumentMatchStatus.ARGUMENT_HAS_NO_TYPE
|
||||
}
|
||||
else if (!noExpectedType(expectedType)) {
|
||||
} else if (!noExpectedType(expectedType)) {
|
||||
if (!ArgumentTypeResolver.isSubtypeOfForArgumentType(type, expectedType)) {
|
||||
val smartCast = smartCastValueArgumentTypeIfPossible(expression, newContext.expectedType, type, newContext)
|
||||
if (smartCast == null) {
|
||||
resultStatus = tryNotNullableArgument(type, expectedType) ?: OTHER_ERROR
|
||||
matchStatus = ArgumentMatchStatus.TYPE_MISMATCH
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
resultingType = smartCast
|
||||
}
|
||||
}
|
||||
else if (ErrorUtils.containsUninferredParameter(expectedType)) {
|
||||
} else if (ErrorUtils.containsUninferredParameter(expectedType)) {
|
||||
matchStatus = ArgumentMatchStatus.MATCH_MODULO_UNINFERRED_TYPES
|
||||
}
|
||||
|
||||
val spreadElement = argument.getSpreadElement()
|
||||
if (spreadElement != null && !type.isFlexible() && type.isMarkedNullable) {
|
||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(expression, type, context)
|
||||
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(dataFlowValue, expectedType, expression, context,
|
||||
call = null, recordExpressionType = false)
|
||||
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(
|
||||
dataFlowValue, expectedType, expression, context,
|
||||
call = null, recordExpressionType = false
|
||||
)
|
||||
if (smartCastResult == null || !smartCastResult.isCorrect) {
|
||||
context.trace.report(Errors.SPREAD_OF_NULLABLE.on(spreadElement))
|
||||
}
|
||||
@@ -407,10 +402,10 @@ class CandidateResolver(
|
||||
}
|
||||
|
||||
private fun smartCastValueArgumentTypeIfPossible(
|
||||
expression: KtExpression,
|
||||
expectedType: KotlinType,
|
||||
actualType: KotlinType,
|
||||
context: ResolutionContext<*>
|
||||
expression: KtExpression,
|
||||
expectedType: KotlinType,
|
||||
actualType: KotlinType,
|
||||
context: ResolutionContext<*>
|
||||
): KotlinType? {
|
||||
val receiverToCast = ExpressionReceiver.create(KtPsiUtil.safeDeparenthesize(expression), actualType, context.trace.bindingContext)
|
||||
val variants = smartCastManager.getSmartCastVariantsExcludingReceiver(context, receiverToCast)
|
||||
@@ -440,8 +435,8 @@ class CandidateResolver(
|
||||
}
|
||||
|
||||
private fun CallCandidateResolutionContext<*>.checkReceiverTypeError(
|
||||
receiverParameterDescriptor: ReceiverParameterDescriptor?,
|
||||
receiverArgument: ReceiverValue?
|
||||
receiverParameterDescriptor: ReceiverParameterDescriptor?,
|
||||
receiverArgument: ReceiverValue?
|
||||
) = checkAndReport {
|
||||
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'.
|
||||
// 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.resultingDescriptor.extensionReceiverParameter,
|
||||
candidateCall.extensionReceiver,
|
||||
candidateCall.explicitReceiverKind.isExtensionReceiver,
|
||||
implicitInvokeCheck = false, isDispatchReceiver = false
|
||||
))
|
||||
)
|
||||
)
|
||||
|
||||
resultStatus = resultStatus.combine(context.checkReceiver(
|
||||
resultStatus = resultStatus.combine(
|
||||
context.checkReceiver(
|
||||
candidateCall,
|
||||
candidateCall.resultingDescriptor.dispatchReceiverParameter, candidateCall.dispatchReceiver,
|
||||
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
|
||||
implicitInvokeCheck = context.call is CallForImplicitInvoke,
|
||||
isDispatchReceiver = true
|
||||
))
|
||||
)
|
||||
)
|
||||
|
||||
if (!context.isDebuggerContext
|
||||
&& candidateCall.dispatchReceiver != null
|
||||
// Do not report error if it's already reported when checked without receiver
|
||||
&& context.isCandidateVisible(receiverArgument = Visibilities.ALWAYS_SUITABLE_RECEIVER, smartCastType = null)) {
|
||||
&& candidateCall.dispatchReceiver != null
|
||||
// Do not report error if it's already reported when checked without receiver
|
||||
&& context.isCandidateVisible(receiverArgument = Visibilities.ALWAYS_SUITABLE_RECEIVER, smartCastType = null)) {
|
||||
resultStatus = resultStatus.combine(
|
||||
context.checkVisibilityWithDispatchReceiver(
|
||||
candidateCall.dispatchReceiver, candidateCall.smartCastDispatchReceiverType))
|
||||
context.checkVisibilityWithDispatchReceiver(
|
||||
candidateCall.dispatchReceiver, candidateCall.smartCastDispatchReceiverType
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return resultStatus
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkReceiver(
|
||||
candidateCall: MutableResolvedCall<D>,
|
||||
receiverParameter: ReceiverParameterDescriptor?,
|
||||
receiverArgument: ReceiverValue?,
|
||||
isExplicitReceiver: Boolean,
|
||||
implicitInvokeCheck: Boolean,
|
||||
isDispatchReceiver: Boolean
|
||||
candidateCall: MutableResolvedCall<D>,
|
||||
receiverParameter: ReceiverParameterDescriptor?,
|
||||
receiverArgument: ReceiverValue?,
|
||||
isExplicitReceiver: Boolean,
|
||||
implicitInvokeCheck: Boolean,
|
||||
isDispatchReceiver: Boolean
|
||||
): ResolutionStatus {
|
||||
if (receiverParameter == null || receiverArgument == null) return SUCCESS
|
||||
val candidateDescriptor = candidateCall.candidateDescriptor
|
||||
@@ -513,14 +514,15 @@ class CandidateResolver(
|
||||
val smartCastSubtypingResult = smartCastManager.getSmartCastReceiverResult(receiverArgument, expectedReceiverParameterType, this)
|
||||
if (smartCastSubtypingResult == null) {
|
||||
tracing.wrongReceiverType(
|
||||
trace, receiverParameter, receiverArgument,
|
||||
this.replaceCallPosition(CallPosition.ExtensionReceiverPosition(candidateCall)))
|
||||
trace, receiverParameter, receiverArgument,
|
||||
this.replaceCallPosition(CallPosition.ExtensionReceiverPosition(candidateCall))
|
||||
)
|
||||
return OTHER_ERROR
|
||||
}
|
||||
|
||||
val notNullReceiverExpected = smartCastSubtypingResult != SmartCastManager.ReceiverSmartCastResult.OK
|
||||
val smartCastNeeded =
|
||||
notNullReceiverExpected || !isCandidateVisibleOrExtensionReceiver(receiverArgument, null, isDispatchReceiver)
|
||||
notNullReceiverExpected || !isCandidateVisibleOrExtensionReceiver(receiverArgument, null, isDispatchReceiver)
|
||||
var reportUnsafeCall = false
|
||||
|
||||
var nullableImplicitInvokeReceiver = false
|
||||
@@ -547,26 +549,23 @@ class CandidateResolver(
|
||||
if (dataFlowValue.immanentNullability.canBeNonNull()) {
|
||||
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
|
||||
|
||||
val smartCastResult = SmartCastManager.checkAndRecordPossibleCast(
|
||||
dataFlowValue, expectedReceiverParameterType,
|
||||
{ possibleSmartCast -> isCandidateVisibleOrExtensionReceiver(receiverArgument, possibleSmartCast, isDispatchReceiver) },
|
||||
expression, this, candidateCall.call, recordExpressionType = true
|
||||
dataFlowValue, expectedReceiverParameterType,
|
||||
{ possibleSmartCast -> isCandidateVisibleOrExtensionReceiver(receiverArgument, possibleSmartCast, isDispatchReceiver) },
|
||||
expression, this, candidateCall.call, recordExpressionType = true
|
||||
)
|
||||
|
||||
if (smartCastResult == null) {
|
||||
if (notNullReceiverExpected) {
|
||||
reportUnsafeCall = true
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (isDispatchReceiver) {
|
||||
candidateCall.setSmartCastDispatchReceiverType(smartCastResult.resultType)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
candidateCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType)
|
||||
}
|
||||
if (!smartCastResult.isCorrect) {
|
||||
@@ -589,11 +588,11 @@ class CandidateResolver(
|
||||
inner class ValueArgumentsCheckingResult(val status: ResolutionStatus, val argumentTypes: List<KotlinType>)
|
||||
|
||||
private fun CallCandidateResolutionContext<*>.checkGenericBoundsInAFunctionCall(
|
||||
ktTypeArguments: List<KtTypeProjection>,
|
||||
typeArguments: List<KotlinType>,
|
||||
functionDescriptor: CallableDescriptor,
|
||||
substitutor: TypeSubstitutor,
|
||||
trace: BindingTrace
|
||||
ktTypeArguments: List<KtTypeProjection>,
|
||||
typeArguments: List<KotlinType>,
|
||||
functionDescriptor: CallableDescriptor,
|
||||
substitutor: TypeSubstitutor,
|
||||
trace: BindingTrace
|
||||
) {
|
||||
if (functionDescriptor is TypeAliasConstructorDescriptor) {
|
||||
checkGenericBoundsInTypeAliasConstructorCall(ktTypeArguments, functionDescriptor, substitutor, trace)
|
||||
@@ -612,10 +611,10 @@ class CandidateResolver(
|
||||
}
|
||||
|
||||
private class TypeAliasSingleStepExpansionReportStrategy(
|
||||
private val callElement: KtElement,
|
||||
typeAlias: TypeAliasDescriptor,
|
||||
ktTypeArguments: List<KtTypeProjection>,
|
||||
private val trace: BindingTrace
|
||||
private val callElement: KtElement,
|
||||
typeAlias: TypeAliasDescriptor,
|
||||
ktTypeArguments: List<KtTypeProjection>,
|
||||
private val trace: BindingTrace
|
||||
) : TypeAliasExpansionReportStrategy {
|
||||
init {
|
||||
assert(!typeAlias.expandedType.isError) { "Incorrect type alias: $typeAlias" }
|
||||
@@ -627,7 +626,11 @@ class CandidateResolver(
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -639,24 +642,28 @@ class CandidateResolver(
|
||||
// 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 argumentElement = argumentsMapping[descriptorForUnsubstitutedArgument]
|
||||
val argumentTypeReferenceElement = argumentElement?.typeReference
|
||||
if (argumentTypeReferenceElement != null) {
|
||||
trace.report(UPPER_BOUND_VIOLATED.on(argumentTypeReferenceElement, bound, argument))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
trace.report(UPPER_BOUND_VIOLATED_IN_TYPEALIAS_EXPANSION.on(callElement, bound, argument, typeParameter))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun CallCandidateResolutionContext<*>.checkGenericBoundsInTypeAliasConstructorCall(
|
||||
ktTypeArguments: List<KtTypeProjection>,
|
||||
typeAliasConstructorDescriptor: TypeAliasConstructorDescriptor,
|
||||
typeAliasParametersSubstitutor: TypeSubstitutor,
|
||||
trace: BindingTrace
|
||||
ktTypeArguments: List<KtTypeProjection>,
|
||||
typeAliasConstructorDescriptor: TypeAliasConstructorDescriptor,
|
||||
typeAliasParametersSubstitutor: TypeSubstitutor,
|
||||
trace: BindingTrace
|
||||
) {
|
||||
val substitutedType = typeAliasParametersSubstitutor.substitute(typeAliasConstructorDescriptor.returnType, Variance.INVARIANT)!!
|
||||
val boundsSubstitutor = TypeSubstitutor.create(substitutedType)
|
||||
@@ -677,10 +684,10 @@ class CandidateResolver(
|
||||
|
||||
|
||||
private fun checkTypeInTypeAliasSubstitutionRec(
|
||||
reportStrategy: TypeAliasExpansionReportStrategy,
|
||||
unsubstitutedType: KotlinType,
|
||||
typeAliasParametersSubstitutor: TypeSubstitutor,
|
||||
boundsSubstitutor: TypeSubstitutor
|
||||
reportStrategy: TypeAliasExpansionReportStrategy,
|
||||
unsubstitutedType: KotlinType,
|
||||
typeAliasParametersSubstitutor: TypeSubstitutor,
|
||||
boundsSubstitutor: TypeSubstitutor
|
||||
) {
|
||||
// TODO refactor TypeResolver
|
||||
val typeParameters = unsubstitutedType.constructor.parameters
|
||||
@@ -688,30 +695,41 @@ class CandidateResolver(
|
||||
// TODO do not perform substitution for type arguments multiple times
|
||||
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]
|
||||
if (substitutedTypeProjection.isStarProjection) continue
|
||||
|
||||
val typeParameter = typeParameters[i]
|
||||
val substitutedTypeArgument = substitutedTypeProjection.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() =
|
||||
candidateResolveMode == CandidateResolveMode.FULLY || candidateCall.status.possibleTransformToSuccess()
|
||||
candidateResolveMode == CandidateResolveMode.FULLY || candidateCall.status.possibleTransformToSuccess()
|
||||
|
||||
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() }
|
||||
}
|
||||
|
||||
private inline fun <D : CallableDescriptor> CallCandidateResolutionContext<D>.checkAndReport(
|
||||
crossinline checker: CallCandidateResolutionContext<D>.() -> ResolutionStatus
|
||||
crossinline checker: CallCandidateResolutionContext<D>.() -> ResolutionStatus
|
||||
) {
|
||||
check {
|
||||
candidateCall.addStatus(checker())
|
||||
|
||||
+38
-22
@@ -38,10 +38,10 @@ import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class DiagnosticReporterByTrackingStrategy(
|
||||
val constantExpressionEvaluator: ConstantExpressionEvaluator,
|
||||
val context: BasicCallResolutionContext,
|
||||
val psiKotlinCall: PSIKotlinCall
|
||||
): DiagnosticReporter {
|
||||
val constantExpressionEvaluator: ConstantExpressionEvaluator,
|
||||
val context: BasicCallResolutionContext,
|
||||
val psiKotlinCall: PSIKotlinCall
|
||||
) : DiagnosticReporter {
|
||||
private val trace = context.trace as TrackingBindingTrace
|
||||
private val tracingStrategy: TracingStrategy get() = psiKotlinCall.tracingStrategy
|
||||
private val call: Call get() = psiKotlinCall.psiCall
|
||||
@@ -53,7 +53,10 @@ class DiagnosticReporterByTrackingStrategy(
|
||||
override fun onCall(diagnostic: KotlinCallDiagnostic) {
|
||||
when (diagnostic.javaClass) {
|
||||
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)
|
||||
AbstractSuperCall::class.java -> tracingStrategy.abstractSuperCall(trace)
|
||||
}
|
||||
@@ -62,10 +65,10 @@ class DiagnosticReporterByTrackingStrategy(
|
||||
override fun onTypeArguments(diagnostic: KotlinCallDiagnostic) {
|
||||
val psiCallElement = psiKotlinCall.psiCall.callElement
|
||||
val reportElement =
|
||||
if (psiCallElement is KtCallExpression)
|
||||
psiCallElement.typeArgumentList ?: psiCallElement.calleeExpression ?: psiCallElement
|
||||
else
|
||||
psiCallElement
|
||||
if (psiCallElement is KtCallExpression)
|
||||
psiCallElement.typeArgumentList ?: psiCallElement.calleeExpression ?: psiCallElement
|
||||
else
|
||||
psiCallElement
|
||||
|
||||
when (diagnostic) {
|
||||
is WrongCountOfTypeArguments -> {
|
||||
@@ -123,8 +126,8 @@ class DiagnosticReporterByTrackingStrategy(
|
||||
}
|
||||
|
||||
override fun onCallArgumentName(callArgument: KotlinCallArgument, diagnostic: KotlinCallDiagnostic) {
|
||||
val nameReference = callArgument.psiCallArgument.valueArgument.getArgumentName()?.referenceExpression ?:
|
||||
error("Argument name should be not null for argument: $callArgument")
|
||||
val nameReference = callArgument.psiCallArgument.valueArgument.getArgumentName()?.referenceExpression
|
||||
?: error("Argument name should be not null for argument: $callArgument")
|
||||
when (diagnostic.javaClass) {
|
||||
NamedArgumentReference::class.java -> {
|
||||
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))
|
||||
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,
|
||||
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))
|
||||
}
|
||||
}
|
||||
@@ -156,23 +161,29 @@ class DiagnosticReporterByTrackingStrategy(
|
||||
is ExpressionKotlinCallArgumentImpl -> {
|
||||
trace.markAsReported()
|
||||
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)
|
||||
SmartCastManager.checkAndRecordPossibleCast(
|
||||
dataFlowValue, smartCastDiagnostic.smartCastType, argumentExpression, context, call,
|
||||
recordExpressionType = true)
|
||||
dataFlowValue, smartCastDiagnostic.smartCastType, argumentExpression, context, call,
|
||||
recordExpressionType = true
|
||||
)
|
||||
}
|
||||
is ReceiverExpressionKotlinCallArgument -> {
|
||||
trace.markAsReported()
|
||||
val receiverValue = expressionArgument.receiver.receiverValue
|
||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiverValue, context)
|
||||
SmartCastManager.checkAndRecordPossibleCast(
|
||||
dataFlowValue, smartCastDiagnostic.smartCastType, (receiverValue as? ExpressionReceiver)?.expression, context, call,
|
||||
recordExpressionType = true)
|
||||
dataFlowValue, smartCastDiagnostic.smartCastType, (receiverValue as? ExpressionReceiver)?.expression, context, call,
|
||||
recordExpressionType = true
|
||||
)
|
||||
}
|
||||
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.extensionReceiver == expressionArgument.receiver.receiverValue) {
|
||||
resolvedCall.updateExtensionReceiverWithSmartCastIfNeeded(smartCastResult.resultType)
|
||||
@@ -194,7 +205,7 @@ class DiagnosticReporterByTrackingStrategy(
|
||||
val constraintError = diagnostic as NewConstraintError
|
||||
val position = constraintError.position.from
|
||||
val argument = (position as? ArgumentConstraintPosition)?.argument
|
||||
?: (position as? ReceiverConstraintPosition)?.argument
|
||||
?: (position as? ReceiverConstraintPosition)?.argument
|
||||
argument?.let {
|
||||
val expression = it.psiExpression ?: return
|
||||
val deparenthesized = KtPsiUtil.safeDeparenthesize(expression)
|
||||
@@ -218,7 +229,12 @@ class DiagnosticReporterByTrackingStrategy(
|
||||
val capturedError = diagnostic as CapturedTypeFromSubtyping
|
||||
(capturedError.position as? ArgumentConstraintPosition)?.let {
|
||||
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 constantValue = constantExpressionEvaluator.evaluateToConstantValue(expression, trace, context.expectedType)
|
||||
val hasConstantTypeError = CompileTimeConstantChecker(context, builtIns, true)
|
||||
.checkConstantExpressionType(constantValue, expression, constraintError.upperType)
|
||||
.checkConstantExpressionType(constantValue, expression, constraintError.upperType)
|
||||
if (hasConstantTypeError) return true
|
||||
}
|
||||
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()
|
||||
|
||||
class GenericCandidateResolver(
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val coroutineInferenceSupport: CoroutineInferenceSupport,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val coroutineInferenceSupport: CoroutineInferenceSupport,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
fun <D : CallableDescriptor> inferTypeArguments(context: CallCandidateResolutionContext<D>): ResolutionStatus {
|
||||
val candidateCall = context.candidateCall
|
||||
@@ -90,7 +90,7 @@ class GenericCandidateResolver(
|
||||
// and throw the results away
|
||||
// We'll type check the arguments later, with the inferred types expected
|
||||
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)
|
||||
}
|
||||
builder.addSubtypeConstraint(
|
||||
receiverType,
|
||||
builder.compositeSubstitutor().substitute(receiverParameter.type, Variance.INVARIANT),
|
||||
RECEIVER_POSITION.position()
|
||||
receiverType,
|
||||
builder.compositeSubstitutor().substitute(receiverParameter.type, Variance.INVARIANT),
|
||||
RECEIVER_POSITION.position()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -133,9 +133,9 @@ class GenericCandidateResolver(
|
||||
}
|
||||
|
||||
private fun ConstraintSystem.Builder.typeInSystem(call: Call, type: KotlinType?): KotlinType? =
|
||||
type?.let {
|
||||
typeVariableSubstitutors[call.toHandle()]?.substitute(it, Variance.INVARIANT)
|
||||
}
|
||||
type?.let {
|
||||
typeVariableSubstitutors[call.toHandle()]?.substitute(it, Variance.INVARIANT)
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.isFunctionForExpectTypeFromCastFeature(): Boolean {
|
||||
val typeParameter = typeParameters.singleOrNull() ?: return false
|
||||
@@ -153,8 +153,8 @@ class GenericCandidateResolver(
|
||||
}
|
||||
|
||||
private fun addExpectedTypeForExplicitCast(
|
||||
context: CallCandidateResolutionContext<*>,
|
||||
builder: ConstraintSystem.Builder
|
||||
context: CallCandidateResolutionContext<*>,
|
||||
builder: ConstraintSystem.Builder
|
||||
) {
|
||||
if (!languageVersionSettings.supportsFeature(LanguageFeature.ExpectedTypeFromCast)) return
|
||||
|
||||
@@ -185,8 +185,7 @@ class GenericCandidateResolver(
|
||||
val targetExpression = if (possibleQualifiedExpression is KtQualifiedExpression) {
|
||||
if (possibleQualifiedExpression.selectorExpression != callExpression) return null
|
||||
possibleQualifiedExpression
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
callExpression
|
||||
}
|
||||
|
||||
@@ -207,7 +206,7 @@ class GenericCandidateResolver(
|
||||
|
||||
val boundsSubstitutor = TypeSubstitutor.create(type)
|
||||
|
||||
type.arguments.forEachIndexed forEachArgument@{ i, typeProjection ->
|
||||
type.arguments.forEachIndexed forEachArgument@ { i, typeProjection ->
|
||||
if (typeProjection.isStarProjection) return@forEachArgument // continue
|
||||
|
||||
val typeParameter = typeConstructor.parameters[i]
|
||||
@@ -218,10 +217,10 @@ class GenericCandidateResolver(
|
||||
}
|
||||
|
||||
private fun addValidityConstraintsForTypeArgument(
|
||||
builder: ConstraintSystem.Builder,
|
||||
substitutedArgument: TypeProjection,
|
||||
typeParameter: TypeParameterDescriptor,
|
||||
boundsSubstitutor: TypeSubstitutor
|
||||
builder: ConstraintSystem.Builder,
|
||||
substitutedArgument: TypeProjection,
|
||||
typeParameter: TypeParameterDescriptor,
|
||||
boundsSubstitutor: TypeSubstitutor
|
||||
) {
|
||||
val substitutedType = substitutedArgument.type
|
||||
for (upperBound in typeParameter.upperBounds) {
|
||||
@@ -247,12 +246,12 @@ class GenericCandidateResolver(
|
||||
}
|
||||
|
||||
private fun addConstraintForValueArgument(
|
||||
valueArgument: ValueArgument,
|
||||
valueParameterDescriptor: ValueParameterDescriptor,
|
||||
substitutor: TypeSubstitutor,
|
||||
builder: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<*>,
|
||||
resolveFunctionArgumentBodies: ResolveArgumentsMode
|
||||
valueArgument: ValueArgument,
|
||||
valueParameterDescriptor: ValueParameterDescriptor,
|
||||
substitutor: TypeSubstitutor,
|
||||
builder: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<*>,
|
||||
resolveFunctionArgumentBodies: ResolveArgumentsMode
|
||||
) {
|
||||
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
|
||||
val argumentExpression = valueArgument.getArgumentExpression()
|
||||
@@ -268,23 +267,24 @@ class GenericCandidateResolver(
|
||||
|
||||
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
|
||||
|
||||
builder.addSubtypeConstraint(
|
||||
type,
|
||||
builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT),
|
||||
constraintPosition
|
||||
type,
|
||||
builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT),
|
||||
constraintPosition
|
||||
)
|
||||
}
|
||||
|
||||
private fun addConstraintForNestedCall(
|
||||
argumentExpression: KtExpression?,
|
||||
constraintPosition: ConstraintPosition,
|
||||
builder: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<*>,
|
||||
effectiveExpectedType: KotlinType
|
||||
argumentExpression: KtExpression?,
|
||||
constraintPosition: ConstraintPosition,
|
||||
builder: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<*>,
|
||||
effectiveExpectedType: KotlinType
|
||||
): Boolean {
|
||||
val resolutionResults = getResolutionResultsCachedData(argumentExpression, context)?.resolutionResults
|
||||
if (resolutionResults == null || !resolutionResults.isSingleResult) return false
|
||||
@@ -312,18 +312,18 @@ class GenericCandidateResolver(
|
||||
val argumentExpressionType = nestedCall.makeNullableTypeIfSafeReceiver(candidateWithFreshVariables.returnType, context)
|
||||
|
||||
builder.addSubtypeConstraint(
|
||||
argumentExpressionType,
|
||||
builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT),
|
||||
constraintPosition
|
||||
argumentExpressionType,
|
||||
builder.compositeSubstitutor().substitute(effectiveExpectedType, Variance.INVARIANT),
|
||||
constraintPosition
|
||||
)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
private fun updateResultTypeForSmartCasts(
|
||||
type: KotlinType?,
|
||||
argumentExpression: KtExpression?,
|
||||
context: ResolutionContext<*>
|
||||
type: KotlinType?,
|
||||
argumentExpression: KtExpression?,
|
||||
context: ResolutionContext<*>
|
||||
): KotlinType? {
|
||||
val deparenthesizedArgument = KtPsiUtil.getLastElementDeparenthesized(argumentExpression, context.statementFilter)
|
||||
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`
|
||||
val newContext = if (resolvedCall is VariableAsFunctionResolvedCall) {
|
||||
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 {
|
||||
context
|
||||
}
|
||||
@@ -356,8 +357,10 @@ class GenericCandidateResolver(
|
||||
for (valueArgument in resolvedValueArgument.arguments) {
|
||||
valueArgument.getArgumentExpression()?.let { argumentExpression ->
|
||||
ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, newContext)?.let { functionLiteral ->
|
||||
addConstraintForFunctionLiteralArgument(functionLiteral, valueArgument, valueParameterDescriptor, constraintSystem, newContext,
|
||||
resolvedCall.candidateDescriptor.returnType)
|
||||
addConstraintForFunctionLiteralArgument(
|
||||
functionLiteral, valueArgument, valueParameterDescriptor, constraintSystem, newContext,
|
||||
resolvedCall.candidateDescriptor.returnType
|
||||
)
|
||||
}
|
||||
|
||||
// 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)
|
||||
val temporaryContextForCall = if (resolvedCall.candidateDescriptor.name in SPECIAL_FUNCTION_NAMES) {
|
||||
newContext
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
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)
|
||||
}
|
||||
|
||||
ArgumentTypeResolver.getCallableReferenceExpressionIfAny(argumentExpression, newContext)?.let { callableReference ->
|
||||
addConstraintForCallableReference(
|
||||
callableReference,
|
||||
valueArgument,
|
||||
valueParameterDescriptor,
|
||||
constraintSystem,
|
||||
temporaryContextForCall)
|
||||
callableReference,
|
||||
valueArgument,
|
||||
valueParameterDescriptor,
|
||||
constraintSystem,
|
||||
temporaryContextForCall
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -395,24 +399,24 @@ class GenericCandidateResolver(
|
||||
// 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
|
||||
private fun estimateLiteralReturnType(
|
||||
context: CallCandidateResolutionContext<*>,
|
||||
literalExpectedType: KotlinType,
|
||||
ownerReturnType: KotlinType?
|
||||
context: CallCandidateResolutionContext<*>,
|
||||
literalExpectedType: KotlinType,
|
||||
ownerReturnType: KotlinType?
|
||||
) = if (!TypeUtils.noExpectedType(context.expectedType) &&
|
||||
ownerReturnType != null &&
|
||||
TypeUtils.isTypeParameter(ownerReturnType) &&
|
||||
literalExpectedType.isFunctionTypeOrSubtype &&
|
||||
getReturnTypeForCallable(literalExpectedType) == ownerReturnType)
|
||||
ownerReturnType != null &&
|
||||
TypeUtils.isTypeParameter(ownerReturnType) &&
|
||||
literalExpectedType.isFunctionTypeOrSubtype &&
|
||||
getReturnTypeForCallable(literalExpectedType) == ownerReturnType)
|
||||
context.expectedType
|
||||
else DONT_CARE
|
||||
|
||||
private fun <D : CallableDescriptor> addConstraintForFunctionLiteralArgument(
|
||||
functionLiteral: KtFunction,
|
||||
valueArgument: ValueArgument,
|
||||
valueParameterDescriptor: ValueParameterDescriptor,
|
||||
constraintSystem: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<D>,
|
||||
argumentOwnerReturnType: KotlinType?
|
||||
functionLiteral: KtFunction,
|
||||
valueArgument: ValueArgument,
|
||||
valueParameterDescriptor: ValueParameterDescriptor,
|
||||
constraintSystem: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<D>,
|
||||
argumentOwnerReturnType: KotlinType?
|
||||
) {
|
||||
val argumentExpression = valueArgument.getArgumentExpression() ?: return
|
||||
|
||||
@@ -439,24 +443,27 @@ class GenericCandidateResolver(
|
||||
val dataFlowInfoForArgument = dataFlowInfoForArguments.getInfo(valueArgument)
|
||||
|
||||
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
|
||||
val hasExpectedReturnType = !hasUnknownReturnType(expectedType)
|
||||
val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
|
||||
if (hasExpectedReturnType) {
|
||||
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 mismatch = BooleanArray(1)
|
||||
val errorInterceptingTrace = ExpressionTypingUtils.makeTraceInterceptingTypeMismatch(
|
||||
temporaryToResolveFunctionLiteral.trace, statementExpression, mismatch)
|
||||
temporaryToResolveFunctionLiteral.trace, statementExpression, mismatch
|
||||
)
|
||||
val newContext = context.replaceBindingTrace(errorInterceptingTrace).replaceExpectedType(expectedType)
|
||||
.replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache)
|
||||
.replaceContextDependency(INDEPENDENT)
|
||||
.replaceDataFlowInfo(dataFlowInfoForArgument).replaceResolutionResultsCache(temporaryToResolveFunctionLiteral.cache)
|
||||
.replaceContextDependency(INDEPENDENT)
|
||||
val type = argumentTypeResolver.getFunctionLiteralTypeInfo(
|
||||
argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).type
|
||||
argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS
|
||||
).type
|
||||
if (!mismatch[0]) {
|
||||
constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position)
|
||||
temporaryToResolveFunctionLiteral.commit()
|
||||
@@ -466,36 +473,38 @@ class GenericCandidateResolver(
|
||||
val estimatedReturnType = estimateLiteralReturnType(context, effectiveExpectedType, argumentOwnerReturnType)
|
||||
val expectedTypeWithEstimatedReturnType = replaceReturnTypeForCallable(expectedType, estimatedReturnType)
|
||||
val newContext = context.replaceExpectedType(expectedTypeWithEstimatedReturnType).replaceDataFlowInfo(dataFlowInfoForArgument)
|
||||
.replaceContextDependency(INDEPENDENT)
|
||||
val type = argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS).type
|
||||
.replaceContextDependency(INDEPENDENT)
|
||||
val type =
|
||||
argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS)
|
||||
.type
|
||||
constraintSystem.addSubtypeConstraint(type, effectiveExpectedTypeInSystem, position)
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> addConstraintForCallableReference(
|
||||
callableReference: KtCallableReferenceExpression,
|
||||
valueArgument: ValueArgument,
|
||||
valueParameterDescriptor: ValueParameterDescriptor,
|
||||
constraintSystem: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<D>
|
||||
callableReference: KtCallableReferenceExpression,
|
||||
valueArgument: ValueArgument,
|
||||
valueParameterDescriptor: ValueParameterDescriptor,
|
||||
constraintSystem: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<D>
|
||||
) {
|
||||
val effectiveExpectedType = getEffectiveExpectedType(valueParameterDescriptor, valueArgument, context)
|
||||
val expectedType = getExpectedTypeForCallableReference(callableReference, constraintSystem, context, effectiveExpectedType)
|
||||
?: return
|
||||
?: return
|
||||
if (!ReflectionTypes.isCallableType(expectedType)) return
|
||||
val resolvedType = getResolvedTypeForCallableReference(callableReference, context, expectedType, valueArgument) ?: return
|
||||
val position = VALUE_PARAMETER_POSITION.position(valueParameterDescriptor.index)
|
||||
constraintSystem.addSubtypeConstraint(
|
||||
resolvedType,
|
||||
constraintSystem.typeVariableSubstitutors[context.call.toHandle()]?.substitute(effectiveExpectedType, Variance.INVARIANT),
|
||||
position
|
||||
resolvedType,
|
||||
constraintSystem.typeVariableSubstitutors[context.call.toHandle()]?.substitute(effectiveExpectedType, Variance.INVARIANT),
|
||||
position
|
||||
)
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> getExpectedTypeForCallableReference(
|
||||
callableReference: KtCallableReferenceExpression,
|
||||
constraintSystem: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<D>,
|
||||
effectiveExpectedType: KotlinType
|
||||
callableReference: KtCallableReferenceExpression,
|
||||
constraintSystem: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<D>,
|
||||
effectiveExpectedType: KotlinType
|
||||
): KotlinType? {
|
||||
val substitutedType = constraintSystem.build().currentSubstitutor.substitute(effectiveExpectedType, Variance.INVARIANT)
|
||||
if (substitutedType != null && !TypeUtils.isDontCarePlaceholder(substitutedType))
|
||||
@@ -509,19 +518,20 @@ class GenericCandidateResolver(
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> getResolvedTypeForCallableReference(
|
||||
callableReference: KtCallableReferenceExpression,
|
||||
context: CallCandidateResolutionContext<D>,
|
||||
expectedType: KotlinType,
|
||||
valueArgument: ValueArgument
|
||||
callableReference: KtCallableReferenceExpression,
|
||||
context: CallCandidateResolutionContext<D>,
|
||||
expectedType: KotlinType,
|
||||
valueArgument: ValueArgument
|
||||
): KotlinType? {
|
||||
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
|
||||
.replaceExpectedType(expectedTypeWithoutReturnType)
|
||||
.replaceDataFlowInfo(dataFlowInfoForArgument)
|
||||
.replaceContextDependency(INDEPENDENT)
|
||||
.replaceExpectedType(expectedTypeWithoutReturnType)
|
||||
.replaceDataFlowInfo(dataFlowInfoForArgument)
|
||||
.replaceContextDependency(INDEPENDENT)
|
||||
return argumentTypeResolver.getCallableReferenceTypeInfo(
|
||||
callableReference, callableReference, newContext, RESOLVE_FUNCTION_ARGUMENTS
|
||||
callableReference, callableReference, newContext, RESOLVE_FUNCTION_ARGUMENTS
|
||||
).type
|
||||
}
|
||||
}
|
||||
@@ -539,7 +549,7 @@ fun makeConstantSubstitutor(typeParameterDescriptors: Collection<TypeParameterDe
|
||||
|
||||
return TypeSubstitutor.create(object : TypeConstructorSubstitution() {
|
||||
override operator fun get(key: TypeConstructor) =
|
||||
if (key in constructors) projection else null
|
||||
if (key in constructors) projection else null
|
||||
|
||||
override fun isEmpty() = false
|
||||
})
|
||||
|
||||
+1
-1
@@ -33,6 +33,6 @@ class CallReturnsArrayOfNothingChecker : CallChecker {
|
||||
if (this == null || isComputingDeferredType(this)) return false
|
||||
|
||||
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) {
|
||||
inner@ for (argument in resolvedArgument.arguments) {
|
||||
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() &&
|
||||
callableReferenceResolvedCall.candidateDescriptor.typeParameters.isNotEmpty()) {
|
||||
context.trace.report(Errors.UNSUPPORTED_FEATURE.on(argumentExpression,
|
||||
typeInferenceForCallableReferencesFeature to context.languageVersionSettings))
|
||||
context.trace.report(
|
||||
Errors.UNSUPPORTED_FEATURE.on(
|
||||
argumentExpression,
|
||||
typeInferenceForCallableReferencesFeature to context.languageVersionSettings
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -62,7 +62,7 @@ class CapturingInClosureChecker : CallChecker {
|
||||
}
|
||||
|
||||
private fun isCapturedInInline(
|
||||
context: BindingContext, scopeContainer: DeclarationDescriptor, variableParent: DeclarationDescriptor
|
||||
context: BindingContext, scopeContainer: DeclarationDescriptor, variableParent: DeclarationDescriptor
|
||||
): Boolean {
|
||||
val scopeDeclaration = DescriptorToSourceUtils.descriptorToDeclaration(scopeContainer)
|
||||
if (!InlineUtil.canBeInlineArgument(scopeDeclaration)) return false
|
||||
@@ -70,7 +70,7 @@ class CapturingInClosureChecker : CallChecker {
|
||||
if (InlineUtil.isInlinedArgument(scopeDeclaration as KtFunction, context, false)) {
|
||||
val scopeContainerParent = scopeContainer.containingDeclaration ?: error("parent is null for $scopeContainer")
|
||||
return !isCapturedVariable(variableParent, scopeContainerParent) ||
|
||||
isCapturedInInline(context, scopeContainerParent, variableParent)
|
||||
isCapturedInInline(context, scopeContainerParent, variableParent)
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
+4
-5
@@ -40,9 +40,9 @@ object DeprecatedCallChecker : CallChecker {
|
||||
}
|
||||
|
||||
private fun check(
|
||||
targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
deprecationResolver: DeprecationResolver
|
||||
targetDescriptor: CallableDescriptor, trace: BindingTrace, element: PsiElement,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
deprecationResolver: DeprecationResolver
|
||||
) {
|
||||
// Objects will be checked by DeprecatedClassifierUsageChecker
|
||||
if (targetDescriptor is FakeCallableDescriptorForObject) return
|
||||
@@ -58,8 +58,7 @@ object DeprecatedCallChecker : CallChecker {
|
||||
for (deprecation in deprecations) {
|
||||
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) }
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -46,15 +46,15 @@ object DslScopeViolationCallChecker : CallChecker {
|
||||
}
|
||||
|
||||
private fun checkCallImplicitReceiver(
|
||||
callImplicitReceiver: ReceiverValue,
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
reportOn: PsiElement,
|
||||
context: CallCheckerContext
|
||||
callImplicitReceiver: ReceiverValue,
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
reportOn: PsiElement,
|
||||
context: CallCheckerContext
|
||||
) {
|
||||
val receiversUntilOneFromTheCall =
|
||||
context.scope.parentsWithSelf
|
||||
.mapNotNull { (it as? LexicalScope)?.implicitReceiver?.value }
|
||||
.takeWhile { it != callImplicitReceiver }.toList()
|
||||
context.scope.parentsWithSelf
|
||||
.mapNotNull { (it as? LexicalScope)?.implicitReceiver?.value }
|
||||
.takeWhile { it != callImplicitReceiver }.toList()
|
||||
|
||||
if (receiversUntilOneFromTheCall.isEmpty()) return
|
||||
|
||||
@@ -62,7 +62,7 @@ object DslScopeViolationCallChecker : CallChecker {
|
||||
if (callDslMarkers.isEmpty()) return
|
||||
|
||||
val closestAnotherReceiverWithSameDslMarker =
|
||||
receiversUntilOneFromTheCall.firstOrNull { receiver -> receiver.type.extractDslMarkerFqNames().any(callDslMarkers::contains) }
|
||||
receiversUntilOneFromTheCall.firstOrNull { receiver -> receiver.type.extractDslMarkerFqNames().any(callDslMarkers::contains) }
|
||||
|
||||
if (closestAnotherReceiverWithSameDslMarker != null) {
|
||||
// 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()
|
||||
?.flatMapTo(result) { it.annotations.extractDslMarkerFqNames() }
|
||||
?.flatMapTo(result) { it.annotations.extractDslMarkerFqNames() }
|
||||
|
||||
return result
|
||||
}
|
||||
@@ -91,7 +91,7 @@ object DslScopeViolationCallChecker : CallChecker {
|
||||
}
|
||||
|
||||
private fun Annotations.extractDslMarkerFqNames() =
|
||||
filter(AnnotationDescriptor::isDslMarker).map { it.fqName!! }
|
||||
filter(AnnotationDescriptor::isDslMarker).map { it.fqName!! }
|
||||
|
||||
private fun AnnotationDescriptor.isDslMarker(): Boolean {
|
||||
val classDescriptor = annotationClass ?: return false
|
||||
|
||||
+11
-10
@@ -49,9 +49,11 @@ class OperatorCallChecker : CallChecker {
|
||||
call is CallTransformer.CallForImplicitInvoke && call.itIsVariableAsFunctionCall) {
|
||||
val outerCall = call.outerCall
|
||||
if (isConventionCall(outerCall) || isWrongCallWithExplicitTypeArguments(resolvedCall, outerCall)) {
|
||||
throw AssertionError("Illegal resolved call to variable with invoke for $outerCall. " +
|
||||
"Variable: ${resolvedCall.variableCall.resultingDescriptor}" +
|
||||
"Invoke: ${resolvedCall.functionCall.resultingDescriptor}")
|
||||
throw AssertionError(
|
||||
"Illegal resolved call to variable with invoke for $outerCall. " +
|
||||
"Variable: ${resolvedCall.variableCall.resultingDescriptor}" +
|
||||
"Invoke: ${resolvedCall.functionCall.resultingDescriptor}"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,11 +91,11 @@ class OperatorCallChecker : CallChecker {
|
||||
}
|
||||
|
||||
private fun isWrongCallWithExplicitTypeArguments(
|
||||
resolvedCall: VariableAsFunctionResolvedCall,
|
||||
outerCall: Call
|
||||
resolvedCall: VariableAsFunctionResolvedCall,
|
||||
outerCall: Call
|
||||
): Boolean {
|
||||
val passedTypeArgumentsToInvoke = outerCall.typeArguments.isNotEmpty() &&
|
||||
resolvedCall.functionCall.candidateDescriptor.typeParameters.isNotEmpty()
|
||||
resolvedCall.functionCall.candidateDescriptor.typeParameters.isNotEmpty()
|
||||
return passedTypeArgumentsToInvoke && resolvedCall.variableCall.candidateDescriptor.typeParameters.isNotEmpty()
|
||||
}
|
||||
}
|
||||
@@ -108,8 +110,8 @@ fun shouldWarnAboutDeprecatedModFromBuiltIns(languageVersionSettings: LanguageVe
|
||||
}
|
||||
|
||||
private fun checkModConvention(
|
||||
descriptor: FunctionDescriptor, languageVersionSettings: LanguageVersionSettings,
|
||||
diagnosticHolder: DiagnosticSink, modifier: PsiElement
|
||||
descriptor: FunctionDescriptor, languageVersionSettings: LanguageVersionSettings,
|
||||
diagnosticHolder: DiagnosticSink, modifier: PsiElement
|
||||
) {
|
||||
if (!descriptor.isOperatorMod()) return
|
||||
|
||||
@@ -117,8 +119,7 @@ private fun checkModConvention(
|
||||
if (shouldWarnAboutDeprecatedModFromBuiltIns(languageVersionSettings)) {
|
||||
addWarningAboutDeprecatedMod(descriptor, diagnosticHolder, modifier)
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)) {
|
||||
addWarningAboutDeprecatedMod(descriptor, diagnosticHolder, modifier)
|
||||
}
|
||||
|
||||
+4
-4
@@ -33,8 +33,8 @@ enum class RttiOperation {
|
||||
}
|
||||
|
||||
class RttiExpressionInformation(
|
||||
val subject: KtExpression,
|
||||
val sourceType: KotlinType?,
|
||||
val targetType: KotlinType?,
|
||||
val operation: RttiOperation
|
||||
val subject: KtExpression,
|
||||
val sourceType: KotlinType?,
|
||||
val targetType: KotlinType?,
|
||||
val operation: RttiOperation
|
||||
)
|
||||
+25
-12
@@ -56,9 +56,9 @@ object CoroutineSuspendCallChecker : CallChecker {
|
||||
}
|
||||
|
||||
val enclosingSuspendFunction = context.scope
|
||||
.parentsWithSelf.firstOrNull {
|
||||
.parentsWithSelf.firstOrNull {
|
||||
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>()
|
||||
|
||||
when {
|
||||
@@ -67,19 +67,32 @@ object CoroutineSuspendCallChecker : CallChecker {
|
||||
|
||||
if (!InlineUtil.checkNonLocalReturnUsage(enclosingSuspendFunction, callElement, context.resolutionContext)) {
|
||||
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.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)
|
||||
}
|
||||
else -> {
|
||||
when (descriptor) {
|
||||
is FunctionDescriptor -> context.trace.report(Errors.ILLEGAL_SUSPEND_FUNCTION_CALL.on(reportOn, resolvedCall.candidateDescriptor))
|
||||
is PropertyDescriptor -> context.trace.report(Errors.ILLEGAL_SUSPEND_PROPERTY_ACCESS.on(reportOn, resolvedCall.candidateDescriptor))
|
||||
is FunctionDescriptor -> context.trace.report(
|
||||
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) =
|
||||
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 {
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
@@ -116,10 +129,10 @@ fun checkCoroutinesFeature(languageVersionSettings: LanguageVersionSettings, dia
|
||||
}
|
||||
|
||||
private fun checkRestrictsSuspension(
|
||||
enclosingCallableDescriptor: CallableDescriptor,
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
reportOn: PsiElement,
|
||||
context: CallCheckerContext
|
||||
enclosingCallableDescriptor: CallableDescriptor,
|
||||
resolvedCall: ResolvedCall<*>,
|
||||
reportOn: PsiElement,
|
||||
context: CallCheckerContext
|
||||
) {
|
||||
val enclosingSuspendReceiverValue = enclosingCallableDescriptor.extensionReceiverParameter?.value ?: return
|
||||
|
||||
|
||||
+83
-68
@@ -50,7 +50,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -74,7 +74,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
||||
}
|
||||
|
||||
override fun registerTypeVariables(
|
||||
call: CallHandle, typeParameters: Collection<TypeParameterDescriptor>, external: Boolean
|
||||
call: CallHandle, typeParameters: Collection<TypeParameterDescriptor>, external: Boolean
|
||||
): TypeSubstitutor {
|
||||
if (typeParameters.isEmpty()) return storeSubstitutor(call, TypeSubstitutor.EMPTY)
|
||||
|
||||
@@ -82,11 +82,10 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
||||
typeParameters.map {
|
||||
TypeVariable(call, it, it, true)
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val freshTypeParameters = ArrayList<TypeParameterDescriptor>(typeParameters.size)
|
||||
DescriptorSubstitutor.substituteTypeParameters(
|
||||
typeParameters.toList(), TypeSubstitution.EMPTY, typeParameters.first().containingDeclaration, freshTypeParameters
|
||||
typeParameters.toList(), TypeSubstitution.EMPTY, typeParameters.first().containingDeclaration, freshTypeParameters
|
||||
)
|
||||
freshTypeParameters.zip(typeParameters).map {
|
||||
val (fresh, original) = it
|
||||
@@ -106,33 +105,44 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
||||
}
|
||||
}
|
||||
|
||||
return storeSubstitutor(call, TypeSubstitutor.create(TypeConstructorSubstitution.createByParametersMap(
|
||||
typeParameters.zip(typeVariables.map { it.type }.defaultProjections()).toMap()
|
||||
)))
|
||||
return storeSubstitutor(
|
||||
call, TypeSubstitutor.create(
|
||||
TypeConstructorSubstitution.createByParametersMap(
|
||||
typeParameters.zip(typeVariables.map { it.type }.defaultProjections()).toMap()
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private fun KotlinType.isProper() = !TypeUtils.contains(this) {
|
||||
type -> type.constructor.declarationDescriptor.let { it is TypeParameterDescriptor && isMyTypeVariable(it) }
|
||||
private fun KotlinType.isProper() = !TypeUtils.contains(this) { type ->
|
||||
type.constructor.declarationDescriptor.let { it is TypeParameterDescriptor && isMyTypeVariable(it) }
|
||||
}
|
||||
|
||||
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) {
|
||||
addConstraint(SUB_TYPE, constrainingType, subjectType, ConstraintContext(constraintPosition, initial = true, initialReduction = true))
|
||||
addConstraint(
|
||||
SUB_TYPE,
|
||||
constrainingType,
|
||||
subjectType,
|
||||
ConstraintContext(constraintPosition, initial = true, initialReduction = true)
|
||||
)
|
||||
}
|
||||
|
||||
fun addConstraint(
|
||||
constraintKind: ConstraintKind,
|
||||
subType: KotlinType?,
|
||||
superType: KotlinType?,
|
||||
constraintContext: ConstraintContext
|
||||
constraintKind: ConstraintKind,
|
||||
subType: KotlinType?,
|
||||
superType: KotlinType?,
|
||||
constraintContext: ConstraintContext
|
||||
) {
|
||||
val constraintPosition = constraintContext.position
|
||||
|
||||
// when processing nested constraints, `derivedFrom` information should be reset
|
||||
val newConstraintContext = ConstraintContext(constraintContext.position, derivedFrom = null, initial = false,
|
||||
initialReduction = constraintContext.initialReduction)
|
||||
val newConstraintContext = ConstraintContext(
|
||||
constraintContext.position, derivedFrom = null, initial = false,
|
||||
initialReduction = constraintContext.initialReduction
|
||||
)
|
||||
val typeCheckingProcedure = TypeCheckingProcedure(object : TypeCheckingProcedureCallbacks {
|
||||
private var depth = 0
|
||||
|
||||
@@ -187,11 +197,11 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
||||
}
|
||||
|
||||
private fun doAddConstraint(
|
||||
constraintKind: ConstraintKind,
|
||||
subType: KotlinType?,
|
||||
superType: KotlinType?,
|
||||
constraintContext: ConstraintContext,
|
||||
typeCheckingProcedure: TypeCheckingProcedure
|
||||
constraintKind: ConstraintKind,
|
||||
subType: KotlinType?,
|
||||
superType: KotlinType?,
|
||||
constraintContext: ConstraintContext,
|
||||
typeCheckingProcedure: TypeCheckingProcedure
|
||||
) {
|
||||
val constraintPosition = constraintContext.position
|
||||
if (isErrorOrSpecialType(subType, constraintPosition) || isErrorOrSpecialType(superType, constraintPosition)) return
|
||||
@@ -212,8 +222,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
||||
return
|
||||
}
|
||||
createTypeForFunctionPlaceholder(subType, superType)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
subType
|
||||
}
|
||||
|
||||
@@ -230,8 +239,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
||||
val superType2 = simplifyType(superType, constraintContext.initial)
|
||||
val result = if (constraintKind == EQUAL) {
|
||||
typeCheckingProcedure.equalTypes(subType2, superType2)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
typeCheckingProcedure.isSubtypeOf(subType2, superType)
|
||||
}
|
||||
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 =
|
||||
if (mode == Mode.SPECIFICITY || !isInitialConstraint)
|
||||
type
|
||||
else {
|
||||
// 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
|
||||
TypeUtils.makeNotNullable(type)
|
||||
}
|
||||
if (mode == Mode.SPECIFICITY || !isInitialConstraint)
|
||||
type
|
||||
else {
|
||||
// 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
|
||||
TypeUtils.makeNotNullable(type)
|
||||
}
|
||||
|
||||
internal fun addBound(
|
||||
typeVariable: TypeVariable,
|
||||
constrainingType: KotlinType,
|
||||
kind: TypeBounds.BoundKind,
|
||||
constraintContext: ConstraintContext
|
||||
typeVariable: TypeVariable,
|
||||
constrainingType: KotlinType,
|
||||
kind: TypeBounds.BoundKind,
|
||||
constraintContext: ConstraintContext
|
||||
) {
|
||||
val bound = Bound(typeVariable, constrainingType, kind, constraintContext.position,
|
||||
constrainingType.isProper(), constraintContext.derivedFrom ?: emptySet())
|
||||
val bound = Bound(
|
||||
typeVariable, constrainingType, kind, constraintContext.position,
|
||||
constrainingType.isProper(), constraintContext.derivedFrom ?: emptySet()
|
||||
)
|
||||
val typeBounds = getTypeBounds(typeVariable)
|
||||
if (typeBounds.bounds.contains(bound)) return
|
||||
|
||||
@@ -277,10 +287,10 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
||||
}
|
||||
|
||||
private fun generateTypeParameterBound(
|
||||
parameterType: KotlinType,
|
||||
constrainingType: KotlinType,
|
||||
boundKind: TypeBounds.BoundKind,
|
||||
constraintContext: ConstraintContext
|
||||
parameterType: KotlinType,
|
||||
constrainingType: KotlinType,
|
||||
boundKind: TypeBounds.BoundKind,
|
||||
constraintContext: ConstraintContext
|
||||
) {
|
||||
val typeVariable = getMyTypeVariable(parameterType)!!
|
||||
|
||||
@@ -321,10 +331,10 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
||||
}
|
||||
|
||||
private fun generateTypeParameterCaptureConstraint(
|
||||
typeVariable: TypeVariable,
|
||||
constrainingTypeProjection: TypeProjection,
|
||||
constraintContext: ConstraintContext,
|
||||
isTypeMarkedNullable: Boolean
|
||||
typeVariable: TypeVariable,
|
||||
constrainingTypeProjection: TypeProjection,
|
||||
constraintContext: ConstraintContext,
|
||||
isTypeMarkedNullable: Boolean
|
||||
) {
|
||||
if (!typeVariable.originalTypeParameter.upperBounds.let { it.size == 1 && it.single().isDefaultBound() } &&
|
||||
constrainingTypeProjection.projectionKind == Variance.IN_VARIANCE) {
|
||||
@@ -332,8 +342,7 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
||||
}
|
||||
val typeProjection = if (isTypeMarkedNullable) {
|
||||
TypeProjectionImpl(constrainingTypeProjection.projectionKind, TypeUtils.makeNotNullable(constrainingTypeProjection.type))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
constrainingTypeProjection
|
||||
}
|
||||
val capturedType = createCapturedType(typeProjection)
|
||||
@@ -341,24 +350,29 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
||||
}
|
||||
|
||||
internal fun getTypeBounds(variable: TypeVariable): TypeBoundsImpl {
|
||||
return allTypeParameterBounds[variable] ?:
|
||||
throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $variable")
|
||||
return allTypeParameterBounds[variable]
|
||||
?: throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $variable")
|
||||
}
|
||||
|
||||
private fun isMyTypeVariable(typeParameter: TypeParameterDescriptor) =
|
||||
getMyTypeVariable(typeParameter) != null
|
||||
getMyTypeVariable(typeParameter) != null
|
||||
|
||||
internal fun isMyTypeVariable(type: KotlinType): Boolean =
|
||||
getMyTypeVariable(type) != null
|
||||
getMyTypeVariable(type) != null
|
||||
|
||||
internal fun getMyTypeVariable(type: KotlinType): TypeVariable? {
|
||||
return getMyTypeVariable(type.constructor.declarationDescriptor as? TypeParameterDescriptor ?: return null)
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
|
||||
@@ -381,14 +395,14 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
||||
}
|
||||
if (!Collections.disjoint(typeVariableSubstitutors.keys, other.typeVariableSubstitutors.keys)) {
|
||||
throw IllegalArgumentException(
|
||||
"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}"
|
||||
"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}"
|
||||
)
|
||||
}
|
||||
if (!Collections.disjoint(other.allTypeParameterBounds.keys, allTypeParameterBounds.keys)) {
|
||||
throw IllegalArgumentException(
|
||||
"Combining two constraint systems only makes sense when they have no common variables. " +
|
||||
"First system variables: ${allTypeParameterBounds.keys}, second: ${other.allTypeParameterBounds.keys}"
|
||||
"Combining two constraint systems only makes sense when they have no common variables. " +
|
||||
"First system variables: ${allTypeParameterBounds.keys}, second: ${other.allTypeParameterBounds.keys}"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -415,10 +429,10 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
||||
var counter = 0
|
||||
|
||||
override fun registerTypeVariables(typeParameters: Collection<TypeParameterDescriptor>) =
|
||||
registerTypeVariables(CallHandle.NONE, typeParameters)
|
||||
registerTypeVariables(CallHandle.NONE, typeParameters)
|
||||
|
||||
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 {
|
||||
fixVariables()
|
||||
@@ -429,8 +443,8 @@ open class ConstraintSystemBuilderImpl(private val mode: Mode = ConstraintSystem
|
||||
}
|
||||
|
||||
internal fun createTypeForFunctionPlaceholder(
|
||||
functionPlaceholder: KotlinType,
|
||||
expectedType: KotlinType
|
||||
functionPlaceholder: KotlinType,
|
||||
expectedType: KotlinType
|
||||
): KotlinType {
|
||||
if (!functionPlaceholder.isFunctionPlaceholder) return functionPlaceholder
|
||||
|
||||
@@ -445,11 +459,12 @@ internal fun createTypeForFunctionPlaceholder(
|
||||
val result = arrayListOf<KotlinType>()
|
||||
(1..functionArgumentsSize).forEach { result.add(DONT_CARE) }
|
||||
result
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
functionPlaceholderTypeConstructor.argumentTypes
|
||||
}
|
||||
val receiverType = if (isExtension) DONT_CARE else null
|
||||
return createFunctionType(functionPlaceholder.builtIns, Annotations.EMPTY, receiverType, newArgumentTypes, null, DONT_CARE,
|
||||
suspendFunction = expectedType.isSuspendFunctionType)
|
||||
return createFunctionType(
|
||||
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.*
|
||||
|
||||
internal class ConstraintSystemImpl(
|
||||
private val allTypeParameterBounds: Map<TypeVariable, TypeBoundsImpl>,
|
||||
private val usedInBounds: Map<TypeVariable, MutableList<TypeBounds.Bound>>,
|
||||
private val errors: List<ConstraintError>,
|
||||
private val initialConstraints: List<ConstraintSystemBuilderImpl.Constraint>,
|
||||
private val typeVariableSubstitutors: Map<CallHandle, TypeSubstitutor>
|
||||
private val allTypeParameterBounds: Map<TypeVariable, TypeBoundsImpl>,
|
||||
private val usedInBounds: Map<TypeVariable, MutableList<TypeBounds.Bound>>,
|
||||
private val errors: List<ConstraintError>,
|
||||
private val initialConstraints: List<ConstraintSystemBuilderImpl.Constraint>,
|
||||
private val typeVariableSubstitutors: Map<CallHandle, TypeSubstitutor>
|
||||
) : ConstraintSystem {
|
||||
private val localTypeParameterBounds: Map<TypeVariable, TypeBoundsImpl>
|
||||
get() = allTypeParameterBounds.filterNot { it.key.isExternal }
|
||||
@@ -48,7 +48,7 @@ internal class ConstraintSystemImpl(
|
||||
override fun isSuccessful() = !hasContradiction() && !hasUnknownParameters() && satisfyInitialConstraints()
|
||||
|
||||
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.
|
||||
@@ -84,7 +84,7 @@ internal class ConstraintSystemImpl(
|
||||
override fun hasConflictingConstraints() = localTypeParameterBounds.values.any { it.values.size > 1 }
|
||||
|
||||
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 }
|
||||
|
||||
@@ -101,26 +101,26 @@ internal class ConstraintSystemImpl(
|
||||
override fun hasTypeInferenceIncorporationError() = errors.any { it is TypeInferenceError } || !satisfyInitialConstraints()
|
||||
|
||||
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>
|
||||
get() = errors
|
||||
}
|
||||
|
||||
private fun getParameterToInferredValueMap(
|
||||
typeParameterBounds: Map<TypeVariable, TypeBoundsImpl>,
|
||||
getDefaultType: (TypeVariable) -> KotlinType,
|
||||
substituteOriginal: Boolean
|
||||
typeParameterBounds: Map<TypeVariable, TypeBoundsImpl>,
|
||||
getDefaultType: (TypeVariable) -> KotlinType,
|
||||
substituteOriginal: Boolean
|
||||
): Map<TypeConstructor, TypeProjection> {
|
||||
val substitutionContext = HashMap<TypeConstructor, TypeProjection>()
|
||||
for ((variable, typeBounds) in typeParameterBounds) {
|
||||
val value = typeBounds.value
|
||||
val typeConstructor =
|
||||
if (substituteOriginal) variable.originalTypeParameter.typeConstructor
|
||||
else variable.type.constructor
|
||||
if (substituteOriginal) variable.originalTypeParameter.typeConstructor
|
||||
else variable.type.constructor
|
||||
val type =
|
||||
if (value != null && !TypeUtils.contains(value, DONT_CARE)) value
|
||||
else getDefaultType(variable)
|
||||
if (value != null && !TypeUtils.contains(value, DONT_CARE)) value
|
||||
else getDefaultType(variable)
|
||||
substitutionContext.put(typeConstructor, TypeProjectionImpl(type))
|
||||
}
|
||||
return substitutionContext
|
||||
@@ -130,8 +130,8 @@ internal class ConstraintSystemImpl(
|
||||
get() = allTypeParameterBounds.keys
|
||||
|
||||
override fun getTypeBounds(typeVariable: TypeVariable): TypeBoundsImpl {
|
||||
return allTypeParameterBounds[typeVariable] ?:
|
||||
throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $typeVariable")
|
||||
return allTypeParameterBounds[typeVariable]
|
||||
?: throw IllegalArgumentException("TypeParameterDescriptor is not a type variable for constraint system: $typeVariable")
|
||||
}
|
||||
|
||||
override val resultingSubstitutor: TypeSubstitutor
|
||||
@@ -143,11 +143,11 @@ internal class ConstraintSystemImpl(
|
||||
private fun getSubstitutor(substituteOriginal: Boolean, getDefaultValue: (TypeVariable) -> KotlinType): TypeSubstitutor {
|
||||
val parameterToInferredValueMap = getParameterToInferredValueMap(allTypeParameterBounds, getDefaultValue, substituteOriginal)
|
||||
return TypeSubstitutor.create(
|
||||
SubstitutionWithCapturedTypeApproximation(
|
||||
SubstitutionFilteringInternalResolveAnnotations(
|
||||
TypeConstructorSubstitution.createByConstructorsMap(parameterToInferredValueMap)
|
||||
)
|
||||
SubstitutionWithCapturedTypeApproximation(
|
||||
SubstitutionFilteringInternalResolveAnnotations(
|
||||
TypeConstructorSubstitution.createByConstructorsMap(parameterToInferredValueMap)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -159,8 +159,7 @@ internal class ConstraintSystemImpl(
|
||||
val substitutor = getSubstitutor(substituteOriginal = false) { ErrorUtils.createUninferredParameterType(it.originalTypeParameter) }
|
||||
fun KotlinType.substitute(): KotlinType? = substitutor.substitute(this, Variance.INVARIANT)
|
||||
|
||||
return initialConstraints.all {
|
||||
(kind, subtype, superType, position) ->
|
||||
return initialConstraints.all { (kind, subtype, superType, position) ->
|
||||
val resultSubType = subtype.substitute()?.let {
|
||||
// the call might be done via safe access, so we check for notNullable receiver type;
|
||||
// 'unsafe call' error is reported otherwise later
|
||||
@@ -181,7 +180,7 @@ internal class ConstraintSystemImpl(
|
||||
}
|
||||
result.usedInBounds.putAll(usedInBounds.map {
|
||||
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())
|
||||
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
|
||||
|
||||
class TypeTemplate(
|
||||
val typeVariable: TypeVariable,
|
||||
val coroutineInferenceData: CoroutineInferenceData,
|
||||
nullable: Boolean = true
|
||||
val typeVariable: TypeVariable,
|
||||
val coroutineInferenceData: CoroutineInferenceData,
|
||||
nullable: Boolean = true
|
||||
) : FlexibleType(
|
||||
typeVariable.originalTypeParameter.builtIns.nothingType,
|
||||
typeVariable.originalTypeParameter.builtIns.anyType.makeNullableAsSpecified(nullable)
|
||||
typeVariable.originalTypeParameter.builtIns.nothingType,
|
||||
typeVariable.originalTypeParameter.builtIns.anyType.makeNullableAsSpecified(nullable)
|
||||
) {
|
||||
override fun replaceAnnotations(newAnnotations: Annotations) = this
|
||||
|
||||
@@ -79,9 +79,9 @@ class CoroutineInferenceData {
|
||||
private var hereIsBadCall = false
|
||||
|
||||
fun getTypeTemplate(typeVariable: TypeVariable) =
|
||||
typeTemplates.getOrPut(typeVariable) {
|
||||
TypeTemplate(typeVariable, this)
|
||||
}
|
||||
typeTemplates.getOrPut(typeVariable) {
|
||||
TypeTemplate(typeVariable, this)
|
||||
}
|
||||
|
||||
fun initSystem() {
|
||||
csBuilder.registerTypeVariables(CallHandle.NONE, typeTemplates.keys.map { it.freshTypeParameter })
|
||||
@@ -115,18 +115,18 @@ class CoroutineInferenceData {
|
||||
}
|
||||
|
||||
class CoroutineInferenceSupport(
|
||||
val argumentTypeResolver: ArgumentTypeResolver,
|
||||
val expressionTypingServices: ExpressionTypingServices
|
||||
val argumentTypeResolver: ArgumentTypeResolver,
|
||||
val expressionTypingServices: ExpressionTypingServices
|
||||
) {
|
||||
@set:Inject
|
||||
lateinit var callCompleter: CallCompleter
|
||||
|
||||
fun analyzeCoroutine(
|
||||
functionLiteral: KtFunction,
|
||||
valueArgument: ValueArgument,
|
||||
csBuilder: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<*>,
|
||||
lambdaExpectedType: KotlinType
|
||||
functionLiteral: KtFunction,
|
||||
valueArgument: ValueArgument,
|
||||
csBuilder: ConstraintSystem.Builder,
|
||||
context: CallCandidateResolutionContext<*>,
|
||||
lambdaExpectedType: KotlinType
|
||||
) {
|
||||
val argumentExpression = valueArgument.getArgumentExpression() ?: return
|
||||
if (!lambdaExpectedType.isSuspendFunctionType) return
|
||||
@@ -155,13 +155,16 @@ class CoroutineInferenceSupport(
|
||||
val approximationSubstitutor = object : DelegatedTypeSubstitution(constraintSystem.currentSubstitutor.substitution) {
|
||||
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,
|
||||
approximatedLambdaType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType),
|
||||
parameterNames = null, // TODO: parameterNames
|
||||
returnType = approximatedLambdaType.getReturnTypeFromFunctionType(),
|
||||
suspendFunction = true)
|
||||
val newExpectedType = createFunctionType(
|
||||
newReceiverType.builtIns, approximatedLambdaType.annotations, newReceiverType,
|
||||
approximatedLambdaType.getValueParameterTypesFromFunctionType().map(TypeProjection::getType),
|
||||
parameterNames = null, // TODO: parameterNames
|
||||
returnType = approximatedLambdaType.getReturnTypeFromFunctionType(),
|
||||
suspendFunction = true
|
||||
)
|
||||
|
||||
if (hasUnknownFunctionParameter(newExpectedType)) return
|
||||
|
||||
@@ -169,20 +172,21 @@ class CoroutineInferenceSupport(
|
||||
|
||||
// this trace shouldn't be committed
|
||||
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)
|
||||
.replaceDataFlowInfo(context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument))
|
||||
.replaceContextDependency(ContextDependency.INDEPENDENT).replaceTraceAndCache(temporaryForCoroutine)
|
||||
.replaceDataFlowInfo(context.candidateCall.dataFlowInfoForArguments.getInfo(valueArgument))
|
||||
.replaceContextDependency(ContextDependency.INDEPENDENT).replaceTraceAndCache(temporaryForCoroutine)
|
||||
argumentTypeResolver.getFunctionLiteralTypeInfo(argumentExpression, functionLiteral, newContext, RESOLVE_FUNCTION_ARGUMENTS)
|
||||
|
||||
inferenceData.reportInferenceResult(csBuilder)
|
||||
}
|
||||
|
||||
fun checkCoroutineCalls(
|
||||
context: BasicCallResolutionContext,
|
||||
tracingStrategy: TracingStrategy,
|
||||
overloadResults: OverloadResolutionResultsImpl<*>
|
||||
context: BasicCallResolutionContext,
|
||||
tracingStrategy: TracingStrategy,
|
||||
overloadResults: OverloadResolutionResultsImpl<*>
|
||||
) {
|
||||
val inferenceData = overloadResults.getCoroutineInferenceData() ?: return
|
||||
|
||||
@@ -197,10 +201,9 @@ class CoroutineInferenceSupport(
|
||||
inferenceData.badCallHappened()
|
||||
}
|
||||
|
||||
forceInferenceForArguments(context) {
|
||||
valueArgument: ValueArgument, kotlinType: KotlinType ->
|
||||
forceInferenceForArguments(context) { valueArgument: ValueArgument, kotlinType: KotlinType ->
|
||||
val argumentMatch = resultingCall.getArgumentMapping(valueArgument) as? ArgumentMatch
|
||||
?: return@forceInferenceForArguments
|
||||
?: return@forceInferenceForArguments
|
||||
|
||||
with(NewKotlinTypeChecker) {
|
||||
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 call = context.call
|
||||
val baseContext = context.replaceContextDependency(ContextDependency.INDEPENDENT).replaceExpectedType(NO_EXPECTED_TYPE)
|
||||
@@ -250,8 +256,8 @@ class CoroutineInferenceSupport(
|
||||
}
|
||||
|
||||
private fun getArgumentTypeInfo(
|
||||
expression: KtExpression,
|
||||
context: CallResolutionContext<*>
|
||||
expression: KtExpression,
|
||||
context: CallResolutionContext<*>
|
||||
): KotlinTypeInfo {
|
||||
getFunctionLiteralArgumentIfAny(expression, context)?.let {
|
||||
return argumentTypeResolver.getFunctionLiteralTypeInfo(expression, it, context, RESOLVE_FUNCTION_ARGUMENTS)
|
||||
@@ -266,9 +272,9 @@ class CoroutineInferenceSupport(
|
||||
}
|
||||
|
||||
fun isCoroutineCallWithAdditionalInference(parameterDescriptor: ValueParameterDescriptor, argument: ValueArgument) =
|
||||
parameterDescriptor.hasSuspendFunctionType &&
|
||||
argument.getArgumentExpression() is KtLambdaExpression &&
|
||||
parameterDescriptor.type.let { it.isBuiltinFunctionalType && it.getReceiverTypeFromFunctionType() != null }
|
||||
parameterDescriptor.hasSuspendFunctionType &&
|
||||
argument.getArgumentExpression() is KtLambdaExpression &&
|
||||
parameterDescriptor.type.let { it.isBuiltinFunctionalType && it.getReceiverTypeFromFunctionType() != null }
|
||||
|
||||
|
||||
fun OverloadResolutionResultsImpl<*>.isResultWithCoroutineInference() = getCoroutineInferenceData() != null
|
||||
|
||||
@@ -23,32 +23,32 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.hasOnlyInputTypesAnnotation
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
|
||||
class TypeVariable(
|
||||
val call: CallHandle,
|
||||
internal val freshTypeParameter: TypeParameterDescriptor,
|
||||
val originalTypeParameter: TypeParameterDescriptor,
|
||||
val isExternal: Boolean
|
||||
val call: CallHandle,
|
||||
internal val freshTypeParameter: TypeParameterDescriptor,
|
||||
val originalTypeParameter: TypeParameterDescriptor,
|
||||
val isExternal: Boolean
|
||||
) {
|
||||
val name: Name get() = originalTypeParameter.name
|
||||
|
||||
val type: KotlinType get() = freshTypeParameter.defaultType
|
||||
|
||||
fun hasOnlyInputTypesAnnotation(): Boolean =
|
||||
originalTypeParameter.hasOnlyInputTypesAnnotation()
|
||||
originalTypeParameter.hasOnlyInputTypesAnnotation()
|
||||
}
|
||||
|
||||
interface CallHandle {
|
||||
object NONE : CallHandle
|
||||
}
|
||||
|
||||
class CallBasedCallHandle(val call: Call): CallHandle {
|
||||
class CallBasedCallHandle(val call: Call) : CallHandle {
|
||||
override fun equals(other: Any?) =
|
||||
other is CallBasedCallHandle && call === other.call
|
||||
other is CallBasedCallHandle && call === other.call
|
||||
|
||||
override fun hashCode() =
|
||||
System.identityHashCode(call)
|
||||
System.identityHashCode(call)
|
||||
|
||||
override fun toString() =
|
||||
call.toString()
|
||||
call.toString()
|
||||
}
|
||||
|
||||
fun Call.toHandle(): CallHandle = CallBasedCallHandle(this)
|
||||
|
||||
+6
-5
@@ -32,11 +32,12 @@ import org.jetbrains.kotlin.types.typesApproximation.approximateCapturedTypes
|
||||
import java.util.*
|
||||
|
||||
data class ConstraintContext(
|
||||
val position: ConstraintPosition,
|
||||
// see TypeBounds.Bound.derivedFrom
|
||||
val derivedFrom: Set<TypeVariable>? = null,
|
||||
val initial: Boolean = false,
|
||||
val initialReduction: Boolean = false)
|
||||
val position: ConstraintPosition,
|
||||
// see TypeBounds.Bound.derivedFrom
|
||||
val derivedFrom: Set<TypeVariable>? = null,
|
||||
val initial: Boolean = false,
|
||||
val initialReduction: Boolean = false
|
||||
)
|
||||
|
||||
fun ConstraintSystemBuilderImpl.incorporateBound(newBound: Bound) {
|
||||
val typeVariable = newBound.typeVariable
|
||||
|
||||
@@ -23,7 +23,7 @@ interface ArgumentMapping {
|
||||
fun isError(): Boolean
|
||||
}
|
||||
|
||||
object ArgumentUnmapped: ArgumentMapping {
|
||||
object ArgumentUnmapped : ArgumentMapping {
|
||||
override fun isError(): Boolean = true
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ interface ArgumentMatch : ArgumentMapping {
|
||||
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
|
||||
|
||||
override val status: ArgumentMatchStatus
|
||||
@@ -64,5 +64,4 @@ class ArgumentMatchImpl(override val valueParameter: ValueParameterDescriptor):
|
||||
}
|
||||
|
||||
//TODO: temporary hack until status.isSuccess is not always correct
|
||||
fun ResolvedCall<*>.isReallySuccess(): Boolean
|
||||
= status.isSuccess && !ErrorUtils.isError(resultingDescriptor)
|
||||
fun ResolvedCall<*>.isReallySuccess(): Boolean = status.isSuccess && !ErrorUtils.isError(resultingDescriptor)
|
||||
|
||||
+2
-2
@@ -32,8 +32,8 @@ interface VariableAsFunctionMutableResolvedCall : VariableAsFunctionResolvedCall
|
||||
}
|
||||
|
||||
class VariableAsFunctionResolvedCallImpl(
|
||||
override val functionCall: MutableResolvedCall<FunctionDescriptor>,
|
||||
override val variableCall: MutableResolvedCall<VariableDescriptor>
|
||||
override val functionCall: MutableResolvedCall<FunctionDescriptor>,
|
||||
override val variableCall: MutableResolvedCall<VariableDescriptor>
|
||||
) : VariableAsFunctionMutableResolvedCall, MutableResolvedCall<FunctionDescriptor> by functionCall {
|
||||
|
||||
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.
|
||||
* In general case it's some r-value.
|
||||
*/
|
||||
class DataFlowValue(val identifierInfo: IdentifierInfo,
|
||||
val type: KotlinType,
|
||||
val immanentNullability: Nullability = type.immanentNullability) {
|
||||
class DataFlowValue(
|
||||
val identifierInfo: IdentifierInfo,
|
||||
val type: KotlinType,
|
||||
val immanentNullability: Nullability = type.immanentNullability
|
||||
) {
|
||||
|
||||
val kind: Kind get() = identifierInfo.kind
|
||||
|
||||
|
||||
+1
-1
@@ -379,7 +379,7 @@ object DataFlowValueFactory {
|
||||
|
||||
// Local variable classification: STABLE or CAPTURED
|
||||
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
|
||||
|
||||
// Analyze who writes variable
|
||||
|
||||
+87
-57
@@ -30,18 +30,18 @@ import org.jetbrains.kotlin.utils.newLinkedHashSetWithExpectedSize
|
||||
import java.util.*
|
||||
|
||||
internal class DelegatingDataFlowInfo private constructor(
|
||||
private val parent: DataFlowInfo?,
|
||||
private val nullabilityInfo: Map<DataFlowValue, Nullability>,
|
||||
// Also immutable
|
||||
private val typeInfo: SetMultimap<DataFlowValue, KotlinType>,
|
||||
/**
|
||||
* Value for which type info was cleared or reassigned at this point
|
||||
* so parent type info should not be in use
|
||||
*/
|
||||
private val valueWithGivenTypeInfo: DataFlowValue?
|
||||
private val parent: DataFlowInfo?,
|
||||
private val nullabilityInfo: Map<DataFlowValue, Nullability>,
|
||||
// Also immutable
|
||||
private val typeInfo: SetMultimap<DataFlowValue, KotlinType>,
|
||||
/**
|
||||
* Value for which type info was cleared or reassigned at this point
|
||||
* so parent type info should not be in use
|
||||
*/
|
||||
private val valueWithGivenTypeInfo: DataFlowValue?
|
||||
) : DataFlowInfo {
|
||||
|
||||
constructor(): this(null, emptyMap(), newTypeInfo(), null)
|
||||
constructor() : this(null, emptyMap(), newTypeInfo(), null)
|
||||
|
||||
override val completeNullabilityInfo: Map<DataFlowValue, Nullability>
|
||||
get() {
|
||||
@@ -80,23 +80,22 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
override fun getStableNullability(key: DataFlowValue) = getNullability(key, true)
|
||||
|
||||
private fun getNullability(key: DataFlowValue, stableOnly: Boolean) =
|
||||
if (stableOnly && !key.isStable) {
|
||||
key.immanentNullability
|
||||
}
|
||||
else {
|
||||
nullabilityInfo[key] ?: parent?.getCollectedNullability(key) ?: key.immanentNullability
|
||||
}
|
||||
if (stableOnly && !key.isStable) {
|
||||
key.immanentNullability
|
||||
} else {
|
||||
nullabilityInfo[key] ?: parent?.getCollectedNullability(key) ?: key.immanentNullability
|
||||
}
|
||||
|
||||
private fun putNullabilityAndTypeInfo(
|
||||
map: MutableMap<DataFlowValue, Nullability>,
|
||||
value: DataFlowValue,
|
||||
nullability: Nullability,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
typeInfo: SetMultimap<DataFlowValue, KotlinType>? = null,
|
||||
affectReceiver: Boolean = true,
|
||||
// TODO: remove me in version 1.3! I'm very dirty hack!
|
||||
// In normal circumstances this should be always true
|
||||
recordUnstable: Boolean = true
|
||||
map: MutableMap<DataFlowValue, Nullability>,
|
||||
value: DataFlowValue,
|
||||
nullability: Nullability,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
typeInfo: SetMultimap<DataFlowValue, KotlinType>? = null,
|
||||
affectReceiver: Boolean = true,
|
||||
// TODO: remove me in version 1.3! I'm very dirty hack!
|
||||
// In normal circumstances this should be always true
|
||||
recordUnstable: Boolean = true
|
||||
): Boolean {
|
||||
if (value.isStable || recordUnstable) {
|
||||
map.put(value, nullability)
|
||||
@@ -110,8 +109,10 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
val receiverType = identifierInfo.receiverType
|
||||
if (identifierInfo.safe && receiverType != null) {
|
||||
val receiverValue = DataFlowValue(identifierInfo.receiverInfo, receiverType)
|
||||
putNullabilityAndTypeInfo(map, receiverValue, nullability,
|
||||
languageVersionSettings, typeInfo, recordUnstable = recordUnstable)
|
||||
putNullabilityAndTypeInfo(
|
||||
map, receiverValue, nullability,
|
||||
languageVersionSettings, typeInfo, recordUnstable = recordUnstable
|
||||
)
|
||||
}
|
||||
}
|
||||
is IdentifierInfo.SafeCast -> {
|
||||
@@ -121,16 +122,20 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
languageVersionSettings.supportsFeature(LanguageFeature.SafeCastCheckBoundSmartCasts)) {
|
||||
|
||||
val subjectValue = DataFlowValue(identifierInfo.subjectInfo, subjectType)
|
||||
putNullabilityAndTypeInfo(map, subjectValue, nullability,
|
||||
languageVersionSettings, typeInfo, recordUnstable = false)
|
||||
putNullabilityAndTypeInfo(
|
||||
map, subjectValue, nullability,
|
||||
languageVersionSettings, typeInfo, recordUnstable = false
|
||||
)
|
||||
if (subjectValue.isStable) {
|
||||
typeInfo?.put(subjectValue, targetType)
|
||||
}
|
||||
}
|
||||
}
|
||||
is IdentifierInfo.Variable -> identifierInfo.bound?.let {
|
||||
putNullabilityAndTypeInfo(map, it, nullability,
|
||||
languageVersionSettings, typeInfo, recordUnstable = recordUnstable)
|
||||
putNullabilityAndTypeInfo(
|
||||
map, it, nullability,
|
||||
languageVersionSettings, typeInfo, recordUnstable = recordUnstable
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,12 +144,12 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
}
|
||||
|
||||
override fun getCollectedTypes(key: DataFlowValue, languageVersionSettings: LanguageVersionSettings) =
|
||||
getCollectedTypes(key, true, languageVersionSettings)
|
||||
getCollectedTypes(key, true, languageVersionSettings)
|
||||
|
||||
private fun getCollectedTypes(
|
||||
key: DataFlowValue,
|
||||
enrichWithNotNull: Boolean,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
key: DataFlowValue,
|
||||
enrichWithNotNull: Boolean,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): Set<KotlinType> {
|
||||
val types = collectTypesFromMeAndParents(key, languageVersionSettings)
|
||||
if (!enrichWithNotNull || getCollectedNullability(key).canBeNull()) {
|
||||
@@ -164,10 +169,10 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
}
|
||||
|
||||
override fun getStableTypes(key: DataFlowValue, languageVersionSettings: LanguageVersionSettings) =
|
||||
getStableTypes(key, true, languageVersionSettings)
|
||||
getStableTypes(key, true, 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 {
|
||||
return if (settings.supportsFeature(LanguageFeature.NewInference))
|
||||
@@ -182,6 +187,7 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
else
|
||||
TypeUtils.makeNotNullable(this)
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this function to clear all data flow information about
|
||||
* the given data flow value.
|
||||
@@ -214,7 +220,7 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
}
|
||||
|
||||
override fun equate(
|
||||
a: DataFlowValue, b: DataFlowValue, identityEquals: Boolean, languageVersionSettings: LanguageVersionSettings
|
||||
a: DataFlowValue, b: DataFlowValue, identityEquals: Boolean, languageVersionSettings: LanguageVersionSettings
|
||||
): DataFlowInfo {
|
||||
val resultNullabilityInfo = hashMapOf<DataFlowValue, Nullability>()
|
||||
val nullabilityOfA = getStableNullability(a)
|
||||
@@ -222,8 +228,20 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
|
||||
val newTypeInfo = newTypeInfo()
|
||||
var changed =
|
||||
putNullabilityAndTypeInfo(resultNullabilityInfo, a, nullabilityOfA.refine(nullabilityOfB), languageVersionSettings, newTypeInfo) or
|
||||
putNullabilityAndTypeInfo(resultNullabilityInfo, b, nullabilityOfB.refine(nullabilityOfA), languageVersionSettings, newTypeInfo)
|
||||
putNullabilityAndTypeInfo(
|
||||
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
|
||||
if (identityEquals || !nullabilityOfA.canBeNonNull() || !nullabilityOfB.canBeNonNull()) {
|
||||
@@ -252,8 +270,7 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
if (current is DelegatingDataFlowInfo) {
|
||||
types.addAll(current.typeInfo.get(value))
|
||||
current = if (value == current.valueWithGivenTypeInfo) null else current.parent
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
types.addAll(current.getCollectedTypes(value, languageVersionSettings))
|
||||
break
|
||||
}
|
||||
@@ -263,7 +280,7 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
}
|
||||
|
||||
override fun disequate(
|
||||
a: DataFlowValue, b: DataFlowValue, languageVersionSettings: LanguageVersionSettings
|
||||
a: DataFlowValue, b: DataFlowValue, languageVersionSettings: LanguageVersionSettings
|
||||
): DataFlowInfo {
|
||||
val resultNullabilityInfo = hashMapOf<DataFlowValue, Nullability>()
|
||||
val nullabilityOfA = getStableNullability(a)
|
||||
@@ -271,15 +288,27 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
|
||||
val newTypeInfo = newTypeInfo()
|
||||
val changed =
|
||||
putNullabilityAndTypeInfo(resultNullabilityInfo, a, nullabilityOfA.refine(nullabilityOfB.invert()), languageVersionSettings, newTypeInfo) or
|
||||
putNullabilityAndTypeInfo(resultNullabilityInfo, b, nullabilityOfB.refine(nullabilityOfA.invert()), languageVersionSettings, newTypeInfo)
|
||||
putNullabilityAndTypeInfo(
|
||||
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
|
||||
|
||||
}
|
||||
|
||||
override fun establishSubtyping(
|
||||
value: DataFlowValue, type: KotlinType, languageVersionSettings: LanguageVersionSettings
|
||||
value: DataFlowValue, type: KotlinType, languageVersionSettings: LanguageVersionSettings
|
||||
): DataFlowInfo {
|
||||
if (value.type == 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>.intersectConsideringNothing(other: Set<KotlinType>) =
|
||||
when {
|
||||
other.containsNothing() -> this
|
||||
this.containsNothing() -> other
|
||||
else -> this.intersect(other)
|
||||
}
|
||||
when {
|
||||
other.containsNothing() -> this
|
||||
this.containsNothing() -> other
|
||||
else -> this.intersect(other)
|
||||
}
|
||||
|
||||
override fun or(other: DataFlowInfo): DataFlowInfo {
|
||||
if (other === DataFlowInfo.EMPTY) return DataFlowInfo.EMPTY
|
||||
@@ -358,15 +387,16 @@ internal class DelegatingDataFlowInfo private constructor(
|
||||
private val EMPTY_TYPE_INFO = newTypeInfo()
|
||||
|
||||
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>()
|
||||
|
||||
private fun create(parent: DataFlowInfo?,
|
||||
nullabilityInfo: Map<DataFlowValue, Nullability>,
|
||||
// NB: typeInfo must be mutable here!
|
||||
typeInfo: SetMultimap<DataFlowValue, KotlinType>,
|
||||
valueWithGivenTypeInfo: DataFlowValue? = null
|
||||
private fun create(
|
||||
parent: DataFlowInfo?,
|
||||
nullabilityInfo: Map<DataFlowValue, Nullability>,
|
||||
// NB: typeInfo must be mutable here!
|
||||
typeInfo: SetMultimap<DataFlowValue, KotlinType>,
|
||||
valueWithGivenTypeInfo: DataFlowValue? = null
|
||||
): DataFlowInfo {
|
||||
val toDelete = newTypeInfo()
|
||||
for (value in typeInfo.keys()) {
|
||||
|
||||
@@ -81,33 +81,32 @@ class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: Kotli
|
||||
override fun getContributedVariables(name: Name, location: LookupLocation): Collection<PropertyDescriptor> {
|
||||
return if (call.valueArgumentList == null && call.valueArguments.isEmpty()) {
|
||||
listOf(createDynamicProperty(owner, name, call))
|
||||
}
|
||||
else listOf()
|
||||
} else listOf()
|
||||
}
|
||||
}
|
||||
|
||||
private fun createDynamicProperty(owner: DeclarationDescriptor, name: Name, call: Call): PropertyDescriptorImpl {
|
||||
val propertyDescriptor = PropertyDescriptorImpl.create(
|
||||
owner,
|
||||
Annotations.EMPTY,
|
||||
Modality.FINAL,
|
||||
Visibilities.PUBLIC,
|
||||
true,
|
||||
name,
|
||||
CallableMemberDescriptor.Kind.DECLARATION,
|
||||
SourceElement.NO_SOURCE,
|
||||
/* lateInit = */ false,
|
||||
/* isConst = */ false,
|
||||
/* isExpect = */ false,
|
||||
/* isActual = */ false,
|
||||
/* isExternal = */ false,
|
||||
/* isDelegated = */ false
|
||||
owner,
|
||||
Annotations.EMPTY,
|
||||
Modality.FINAL,
|
||||
Visibilities.PUBLIC,
|
||||
true,
|
||||
name,
|
||||
CallableMemberDescriptor.Kind.DECLARATION,
|
||||
SourceElement.NO_SOURCE,
|
||||
/* lateInit = */ false,
|
||||
/* isConst = */ false,
|
||||
/* isExpect = */ false,
|
||||
/* isActual = */ false,
|
||||
/* isExternal = */ false,
|
||||
/* isDelegated = */ false
|
||||
)
|
||||
propertyDescriptor.setType(
|
||||
dynamicType,
|
||||
createTypeParameters(propertyDescriptor, call),
|
||||
createDynamicDispatchReceiverParameter(propertyDescriptor),
|
||||
null as KotlinType?
|
||||
dynamicType,
|
||||
createTypeParameters(propertyDescriptor, call),
|
||||
createDynamicDispatchReceiverParameter(propertyDescriptor),
|
||||
null as KotlinType?
|
||||
)
|
||||
|
||||
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 {
|
||||
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||
owner,
|
||||
Annotations.EMPTY,
|
||||
name,
|
||||
CallableMemberDescriptor.Kind.DECLARATION,
|
||||
SourceElement.NO_SOURCE
|
||||
owner,
|
||||
Annotations.EMPTY,
|
||||
name,
|
||||
CallableMemberDescriptor.Kind.DECLARATION,
|
||||
SourceElement.NO_SOURCE
|
||||
)
|
||||
functionDescriptor.initialize(
|
||||
null,
|
||||
createDynamicDispatchReceiverParameter(functionDescriptor),
|
||||
createTypeParameters(functionDescriptor, call),
|
||||
createValueParameters(functionDescriptor, call),
|
||||
dynamicType,
|
||||
Modality.FINAL,
|
||||
Visibilities.PUBLIC
|
||||
null,
|
||||
createDynamicDispatchReceiverParameter(functionDescriptor),
|
||||
createTypeParameters(functionDescriptor, call),
|
||||
createValueParameters(functionDescriptor, call),
|
||||
dynamicType,
|
||||
Modality.FINAL,
|
||||
Visibilities.PUBLIC
|
||||
)
|
||||
functionDescriptor.setHasSynthesizedParameterNames(true)
|
||||
return functionDescriptor
|
||||
@@ -144,26 +143,27 @@ class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: Kotli
|
||||
return ReceiverParameterDescriptorImpl(owner, TransientReceiver(dynamicType))
|
||||
}
|
||||
|
||||
private fun createTypeParameters(owner: DeclarationDescriptor, call: Call): List<TypeParameterDescriptor> = call.typeArguments.indices.map {
|
||||
index
|
||||
->
|
||||
TypeParameterDescriptorImpl.createWithDefaultBound(
|
||||
private fun createTypeParameters(owner: DeclarationDescriptor, call: Call): List<TypeParameterDescriptor> =
|
||||
call.typeArguments.indices.map { index
|
||||
->
|
||||
TypeParameterDescriptorImpl.createWithDefaultBound(
|
||||
owner,
|
||||
Annotations.EMPTY,
|
||||
false,
|
||||
Variance.INVARIANT,
|
||||
Name.identifier("T$index"),
|
||||
index
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun createValueParameters(owner: FunctionDescriptor, call: Call): List<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
|
||||
|
||||
parameters.add(ValueParameterDescriptorImpl(
|
||||
parameters.add(
|
||||
ValueParameterDescriptorImpl(
|
||||
owner,
|
||||
null,
|
||||
index,
|
||||
@@ -175,7 +175,8 @@ class DynamicCallableDescriptors(storageManager: StorageManager, builtIns: Kotli
|
||||
/* isNoinline = */ false,
|
||||
varargElementType,
|
||||
SourceElement.NO_SOURCE
|
||||
))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun getFunctionType(funLiteralExpr: KtLambdaExpression): KotlinType {
|
||||
|
||||
+42
-37
@@ -55,14 +55,14 @@ import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class KotlinResolutionCallbacksImpl(
|
||||
topLevelCallContext: BasicCallResolutionContext,
|
||||
val expressionTypingServices: ExpressionTypingServices,
|
||||
val typeApproximator: TypeApproximator,
|
||||
val argumentTypeResolver: ArgumentTypeResolver,
|
||||
val languageVersionSettings: LanguageVersionSettings,
|
||||
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||
val constantExpressionEvaluator: ConstantExpressionEvaluator
|
||||
): KotlinResolutionCallbacks {
|
||||
topLevelCallContext: BasicCallResolutionContext,
|
||||
val expressionTypingServices: ExpressionTypingServices,
|
||||
val typeApproximator: TypeApproximator,
|
||||
val argumentTypeResolver: ArgumentTypeResolver,
|
||||
val languageVersionSettings: LanguageVersionSettings,
|
||||
val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||
val constantExpressionEvaluator: ConstantExpressionEvaluator
|
||||
) : KotlinResolutionCallbacks {
|
||||
val trace: BindingTrace = topLevelCallContext.trace
|
||||
|
||||
class LambdaInfo(val expectedType: UnwrappedType, val contextDependency: ContextDependency) {
|
||||
@@ -75,35 +75,42 @@ class KotlinResolutionCallbacksImpl(
|
||||
}
|
||||
|
||||
override fun analyzeAndGetLambdaReturnArguments(
|
||||
lambdaArgument: LambdaKotlinCallArgument,
|
||||
isSuspend: Boolean,
|
||||
receiverType: UnwrappedType?,
|
||||
parameters: List<UnwrappedType>,
|
||||
expectedReturnType: UnwrappedType?
|
||||
lambdaArgument: LambdaKotlinCallArgument,
|
||||
isSuspend: Boolean,
|
||||
receiverType: UnwrappedType?,
|
||||
parameters: List<UnwrappedType>,
|
||||
expectedReturnType: UnwrappedType?
|
||||
): List<SimpleKotlinCallArgument> {
|
||||
val psiCallArgument = lambdaArgument.psiCallArgument as PSIFunctionKotlinCallArgument
|
||||
val outerCallContext = psiCallArgument.outerCallContext
|
||||
|
||||
fun createCallArgument(ktExpression: KtExpression, typeInfo: KotlinTypeInfo) =
|
||||
createSimplePSICallArgument(trace.bindingContext, outerCallContext.statementFilter, outerCallContext.scope.ownerDescriptor,
|
||||
CallMaker.makeExternalValueArgument(ktExpression), DataFlowInfo.EMPTY, typeInfo, languageVersionSettings)
|
||||
createSimplePSICallArgument(
|
||||
trace.bindingContext, outerCallContext.statementFilter, outerCallContext.scope.ownerDescriptor,
|
||||
CallMaker.makeExternalValueArgument(ktExpression), DataFlowInfo.EMPTY, typeInfo, languageVersionSettings
|
||||
)
|
||||
|
||||
val lambdaInfo = LambdaInfo(expectedReturnType ?: TypeUtils.NO_EXPECTED_TYPE,
|
||||
if (expectedReturnType == null) ContextDependency.DEPENDENT else ContextDependency.INDEPENDENT)
|
||||
val lambdaInfo = LambdaInfo(
|
||||
expectedReturnType ?: TypeUtils.NO_EXPECTED_TYPE,
|
||||
if (expectedReturnType == null) ContextDependency.DEPENDENT else ContextDependency.INDEPENDENT
|
||||
)
|
||||
|
||||
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, lambdaInfo)
|
||||
|
||||
val builtIns = outerCallContext.scope.ownerDescriptor.builtIns
|
||||
val expectedType = createFunctionType(builtIns, Annotations.EMPTY, receiverType, parameters, null,
|
||||
lambdaInfo.expectedType, isSuspend)
|
||||
val expectedType = createFunctionType(
|
||||
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
|
||||
.replaceBindingTrace(trace)
|
||||
.replaceContextDependency(lambdaInfo.contextDependency)
|
||||
.replaceExpectedType(approximatesExpectedType)
|
||||
.replaceDataFlowInfo(psiCallArgument.lambdaInitialDataFlowInfo)
|
||||
.replaceBindingTrace(trace)
|
||||
.replaceContextDependency(lambdaInfo.contextDependency)
|
||||
.replaceExpectedType(approximatesExpectedType)
|
||||
.replaceDataFlowInfo(psiCallArgument.lambdaInitialDataFlowInfo)
|
||||
|
||||
val functionTypeInfo = expressionTypingServices.getTypeInfo(psiCallArgument.expression, actualContext)
|
||||
trace.record(BindingContext.NEW_INFERENCE_LAMBDA_INFO, psiCallArgument.ktFunction, LambdaInfo.STUB_EMPTY)
|
||||
@@ -113,11 +120,10 @@ class KotlinResolutionCallbacksImpl(
|
||||
val returnedExpression = expression.returnedExpression
|
||||
if (returnedExpression != null) {
|
||||
createCallArgument(
|
||||
returnedExpression,
|
||||
typeInfo ?: throw AssertionError("typeInfo should be non-null for return with expression")
|
||||
returnedExpression,
|
||||
typeInfo ?: throw AssertionError("typeInfo should be non-null for return with expression")
|
||||
)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
hasReturnWithoutExpression = true
|
||||
EmptyLabeledReturn(expression, builtIns)
|
||||
}
|
||||
@@ -141,8 +147,7 @@ class KotlinResolutionCallbacksImpl(
|
||||
val lastExpression: KtExpression?
|
||||
if (psiCallArgument is LambdaKotlinCallArgumentImpl) {
|
||||
lastExpression = psiCallArgument.ktLambdaExpression.bodyExpression?.statements?.lastOrNull()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
lastExpression = (psiCallArgument as FunctionExpressionImpl).ktFunction.bodyExpression?.lastBlockStatementOrThis()
|
||||
}
|
||||
|
||||
@@ -159,11 +164,11 @@ class KotlinResolutionCallbacksImpl(
|
||||
val expression = psiKotlinCall.psiCall.callElement.safeAs<KtExpression>() ?: return null
|
||||
|
||||
return transformToReceiverWithSmartCastInfo(
|
||||
resolvedAtom.candidateDescriptor,
|
||||
trace.bindingContext,
|
||||
psiKotlinCall.resultDataFlowInfo,
|
||||
ExpressionReceiver.create(expression, returnType, trace.bindingContext),
|
||||
languageVersionSettings
|
||||
resolvedAtom.candidateDescriptor,
|
||||
trace.bindingContext,
|
||||
psiKotlinCall.resultDataFlowInfo,
|
||||
ExpressionReceiver.create(expression, returnType, trace.bindingContext),
|
||||
languageVersionSettings
|
||||
)
|
||||
}
|
||||
|
||||
@@ -179,8 +184,8 @@ class KotlinResolutionCallbacksImpl(
|
||||
val expression = findCommonParent(callElement, resolvedAtom.atom.psiKotlinCall.explicitReceiver)
|
||||
|
||||
val temporaryBindingTrace = TemporaryBindingTrace.create(
|
||||
trace,
|
||||
"Trace to check if some expression is constant, we have to avoid writing probably wrong COMPILE_TIME_VALUE slice"
|
||||
trace,
|
||||
"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
|
||||
}
|
||||
|
||||
+158
-121
@@ -61,39 +61,45 @@ import java.lang.IllegalStateException
|
||||
import java.util.*
|
||||
|
||||
class NewResolutionOldInference(
|
||||
private val candidateResolver: CandidateResolver,
|
||||
private val towerResolver: TowerResolver,
|
||||
private val resolutionResultsHandler: ResolutionResultsHandler,
|
||||
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
|
||||
private val syntheticScopes: SyntheticScopes,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val coroutineInferenceSupport: CoroutineInferenceSupport,
|
||||
private val deprecationResolver: DeprecationResolver
|
||||
private val candidateResolver: CandidateResolver,
|
||||
private val towerResolver: TowerResolver,
|
||||
private val resolutionResultsHandler: ResolutionResultsHandler,
|
||||
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
|
||||
private val syntheticScopes: SyntheticScopes,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val coroutineInferenceSupport: CoroutineInferenceSupport,
|
||||
private val deprecationResolver: DeprecationResolver
|
||||
) {
|
||||
sealed class ResolutionKind<D : CallableDescriptor>(val kotlinCallKind: KotlinCallKind = KotlinCallKind.UNSUPPORTED) {
|
||||
abstract internal fun createTowerProcessor(
|
||||
outer: NewResolutionOldInference,
|
||||
name: Name,
|
||||
tracing: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower,
|
||||
explicitReceiver: DetailedReceiver?,
|
||||
context: BasicCallResolutionContext
|
||||
outer: NewResolutionOldInference,
|
||||
name: Name,
|
||||
tracing: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower,
|
||||
explicitReceiver: DetailedReceiver?,
|
||||
context: BasicCallResolutionContext
|
||||
): ScopeTowerProcessor<MyCandidate>
|
||||
|
||||
object Function : ResolutionKind<FunctionDescriptor>(KotlinCallKind.FUNCTION) {
|
||||
override fun createTowerProcessor(
|
||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||
): ScopeTowerProcessor<MyCandidate> {
|
||||
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) {
|
||||
override fun createTowerProcessor(
|
||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||
): ScopeTowerProcessor<MyCandidate> {
|
||||
val variableFactory = outer.CandidateFactoryImpl(name, context, tracing)
|
||||
return createVariableAndObjectProcessor(scopeTower, name, variableFactory, explicitReceiver)
|
||||
@@ -102,22 +108,22 @@ class NewResolutionOldInference(
|
||||
|
||||
object CallableReference : ResolutionKind<CallableDescriptor>() {
|
||||
override fun createTowerProcessor(
|
||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||
): ScopeTowerProcessor<MyCandidate> {
|
||||
val functionFactory = outer.CandidateFactoryImpl(name, context, tracing)
|
||||
val variableFactory = outer.CandidateFactoryImpl(name, context, tracing)
|
||||
return PrioritizedCompositeScopeTowerProcessor(
|
||||
createSimpleFunctionProcessor(scopeTower, name, functionFactory, explicitReceiver, classValueReceiver = false),
|
||||
createVariableProcessor(scopeTower, name, variableFactory, explicitReceiver, classValueReceiver = false)
|
||||
createSimpleFunctionProcessor(scopeTower, name, functionFactory, explicitReceiver, classValueReceiver = false),
|
||||
createVariableProcessor(scopeTower, name, variableFactory, explicitReceiver, classValueReceiver = false)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
object Invoke : ResolutionKind<FunctionDescriptor>() {
|
||||
override fun createTowerProcessor(
|
||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||
): ScopeTowerProcessor<MyCandidate> {
|
||||
val functionFactory = outer.CandidateFactoryImpl(name, context, tracing)
|
||||
// todo
|
||||
@@ -125,7 +131,12 @@ class NewResolutionOldInference(
|
||||
"Call should be CallForImplicitInvoke, but it is: ${context.call}"
|
||||
}
|
||||
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>() {
|
||||
override fun createTowerProcessor(
|
||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||
outer: NewResolutionOldInference, name: Name, tracing: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower, explicitReceiver: DetailedReceiver?, context: BasicCallResolutionContext
|
||||
): ScopeTowerProcessor<MyCandidate> {
|
||||
throw IllegalStateException("Should be not called")
|
||||
}
|
||||
@@ -142,16 +153,15 @@ class NewResolutionOldInference(
|
||||
}
|
||||
|
||||
fun <D : CallableDescriptor> runResolution(
|
||||
context: BasicCallResolutionContext,
|
||||
name: Name,
|
||||
kind: ResolutionKind<D>,
|
||||
tracing: TracingStrategy
|
||||
context: BasicCallResolutionContext,
|
||||
name: Name,
|
||||
kind: ResolutionKind<D>,
|
||||
tracing: TracingStrategy
|
||||
): OverloadResolutionResultsImpl<D> {
|
||||
val explicitReceiver = context.call.explicitReceiver
|
||||
val detailedReceiver = if (explicitReceiver is QualifierReceiver?) {
|
||||
explicitReceiver
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
context.transformToReceiverWithSmartCastInfo(explicitReceiver as ReceiverValue)
|
||||
}
|
||||
|
||||
@@ -171,15 +181,22 @@ class NewResolutionOldInference(
|
||||
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
|
||||
val emptyOrInapplicableCandidates = candidates.isEmpty() ||
|
||||
candidates.all { it.resultingApplicability.isInapplicable }
|
||||
candidates.all { it.resultingApplicability.isInapplicable }
|
||||
if (isBinaryRemOperator && shouldUseOperatorRem && emptyOrInapplicableCandidates) {
|
||||
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[name]
|
||||
val processorForDeprecatedName = kind.createTowerProcessor(this, deprecatedName!!, tracing, scopeTower, detailedReceiver, context)
|
||||
candidates = towerResolver.runResolve(scopeTower, processorForDeprecatedName, useOrder = kind != ResolutionKind.CallableReference, name = deprecatedName)
|
||||
val processorForDeprecatedName =
|
||||
kind.createTowerProcessor(this, deprecatedName!!, tracing, scopeTower, detailedReceiver, context)
|
||||
candidates = towerResolver.runResolve(
|
||||
scopeTower,
|
||||
processorForDeprecatedName,
|
||||
useOrder = kind != ResolutionKind.CallableReference,
|
||||
name = deprecatedName
|
||||
)
|
||||
}
|
||||
|
||||
if (candidates.isEmpty()) {
|
||||
@@ -194,9 +211,9 @@ class NewResolutionOldInference(
|
||||
}
|
||||
|
||||
fun <D : CallableDescriptor> runResolutionForGivenCandidates(
|
||||
basicCallContext: BasicCallResolutionContext,
|
||||
tracing: TracingStrategy,
|
||||
candidates: Collection<ResolutionCandidate<D>>
|
||||
basicCallContext: BasicCallResolutionContext,
|
||||
tracing: TracingStrategy,
|
||||
candidates: Collection<ResolutionCandidate<D>>
|
||||
): OverloadResolutionResultsImpl<D> {
|
||||
val resolvedCandidates = candidates.map { candidate ->
|
||||
val candidateTrace = TemporaryBindingTrace.create(basicCallContext.trace, "Context for resolve candidate")
|
||||
@@ -207,8 +224,8 @@ class NewResolutionOldInference(
|
||||
}
|
||||
|
||||
val callCandidateResolutionContext = CallCandidateResolutionContext.create(
|
||||
resolvedCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
|
||||
CandidateResolveMode.EXIT_ON_FIRST_ERROR
|
||||
resolvedCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
|
||||
CandidateResolveMode.EXIT_ON_FIRST_ERROR
|
||||
)
|
||||
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
|
||||
|
||||
@@ -219,27 +236,31 @@ class NewResolutionOldInference(
|
||||
}
|
||||
}
|
||||
if (basicCallContext.collectAllCandidates) {
|
||||
val allCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates),
|
||||
TowerResolver.AllCandidatesCollector(), useOrder = false)
|
||||
val allCandidates = towerResolver.runWithEmptyTowerData(
|
||||
KnownResultProcessor(resolvedCandidates),
|
||||
TowerResolver.AllCandidatesCollector(), useOrder = false
|
||||
)
|
||||
return allCandidatesResult(allCandidates)
|
||||
}
|
||||
|
||||
val processedCandidates = towerResolver.runWithEmptyTowerData(KnownResultProcessor(resolvedCandidates),
|
||||
TowerResolver.SuccessfulResultCollector(), useOrder = true)
|
||||
val processedCandidates = towerResolver.runWithEmptyTowerData(
|
||||
KnownResultProcessor(resolvedCandidates),
|
||||
TowerResolver.SuccessfulResultCollector(), useOrder = true
|
||||
)
|
||||
|
||||
return convertToOverloadResults(processedCandidates, tracing, basicCallContext, languageVersionSettings)
|
||||
}
|
||||
|
||||
private fun <D: CallableDescriptor> allCandidatesResult(allCandidates: Collection<MyCandidate>)
|
||||
= OverloadResolutionResultsImpl.nameNotFound<D>().apply {
|
||||
this.allCandidates = allCandidates.map { it.resolvedCall as MutableResolvedCall<D> }
|
||||
}
|
||||
private fun <D : CallableDescriptor> allCandidatesResult(allCandidates: Collection<MyCandidate>) =
|
||||
OverloadResolutionResultsImpl.nameNotFound<D>().apply {
|
||||
this.allCandidates = allCandidates.map { it.resolvedCall as MutableResolvedCall<D> }
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> convertToOverloadResults(
|
||||
candidates: Collection<MyCandidate>,
|
||||
tracing: TracingStrategy,
|
||||
basicCallContext: BasicCallResolutionContext,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
candidates: Collection<MyCandidate>,
|
||||
tracing: TracingStrategy,
|
||||
basicCallContext: BasicCallResolutionContext,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): OverloadResolutionResultsImpl<D> {
|
||||
val resolvedCalls = candidates.map {
|
||||
val (diagnostics, resolvedCall) = it
|
||||
@@ -260,8 +281,17 @@ class NewResolutionOldInference(
|
||||
if (resolvedCall.status.possibleTransformToSuccess()) {
|
||||
for (error in diagnostics) {
|
||||
when (error) {
|
||||
is UnsupportedInnerClassCall -> resolvedCall.trace.report(Errors.UNSUPPORTED.on(resolvedCall.call.callElement, error.message))
|
||||
is NestedClassViaInstanceReference -> tracing.nestedClassAccessViaInstanceReference(resolvedCall.trace, error.classDescriptor, resolvedCall.explicitReceiverKind)
|
||||
is UnsupportedInnerClassCall -> resolvedCall.trace.report(
|
||||
Errors.UNSUPPORTED.on(
|
||||
resolvedCall.call.callElement,
|
||||
error.message
|
||||
)
|
||||
)
|
||||
is NestedClassViaInstanceReference -> tracing.nestedClassAccessViaInstanceReference(
|
||||
resolvedCall.trace,
|
||||
error.classDescriptor,
|
||||
resolvedCall.explicitReceiverKind
|
||||
)
|
||||
is ErrorDescriptorDiagnostic -> {
|
||||
// todo
|
||||
// return@map null
|
||||
@@ -278,11 +308,11 @@ class NewResolutionOldInference(
|
||||
|
||||
// true if we found something
|
||||
private fun reportAdditionalDiagnosticIfNoCandidates(
|
||||
context: BasicCallResolutionContext,
|
||||
name: Name,
|
||||
kind: ResolutionKind<*>,
|
||||
scopeTower: ImplicitScopeTower,
|
||||
detailedReceiver: DetailedReceiver?
|
||||
context: BasicCallResolutionContext,
|
||||
name: Name,
|
||||
kind: ResolutionKind<*>,
|
||||
scopeTower: ImplicitScopeTower,
|
||||
detailedReceiver: DetailedReceiver?
|
||||
): Boolean {
|
||||
val reference = context.call.calleeExpression as? KtReferenceExpression ?: return false
|
||||
|
||||
@@ -301,17 +331,17 @@ class NewResolutionOldInference(
|
||||
}
|
||||
|
||||
private class ImplicitScopeTowerImpl(
|
||||
val resolutionContext: ResolutionContext<*>,
|
||||
override val dynamicScope: MemberScope,
|
||||
override val syntheticScopes: SyntheticScopes,
|
||||
override val location: LookupLocation
|
||||
): ImplicitScopeTower {
|
||||
val resolutionContext: ResolutionContext<*>,
|
||||
override val dynamicScope: MemberScope,
|
||||
override val syntheticScopes: SyntheticScopes,
|
||||
override val location: LookupLocation
|
||||
) : ImplicitScopeTower {
|
||||
private val cache = HashMap<ReceiverValue, ReceiverValueWithSmartCastInfo>()
|
||||
|
||||
override fun getImplicitReceiver(scope: LexicalScope): ReceiverValueWithSmartCastInfo? =
|
||||
scope.implicitReceiver?.value?.let {
|
||||
cache.getOrPut(it) { resolutionContext.transformToReceiverWithSmartCastInfo(it) }
|
||||
}
|
||||
scope.implicitReceiver?.value?.let {
|
||||
cache.getOrPut(it) { resolutionContext.transformToReceiverWithSmartCastInfo(it) }
|
||||
}
|
||||
|
||||
override val lexicalScope: LexicalScope get() = resolutionContext.scope
|
||||
|
||||
@@ -322,12 +352,12 @@ class NewResolutionOldInference(
|
||||
}
|
||||
|
||||
internal class MyCandidate(
|
||||
// Diagnostics that are already computed
|
||||
// if resultingApplicability is successful they must be the same as `diagnostics`,
|
||||
// otherwise they might be a bit different but result remains unsuccessful
|
||||
val eagerDiagnostics: List<KotlinCallDiagnostic>,
|
||||
val resolvedCall: MutableResolvedCall<*>,
|
||||
finalDiagnosticsComputation: (() -> List<KotlinCallDiagnostic>)? = null
|
||||
// Diagnostics that are already computed
|
||||
// if resultingApplicability is successful they must be the same as `diagnostics`,
|
||||
// otherwise they might be a bit different but result remains unsuccessful
|
||||
val eagerDiagnostics: List<KotlinCallDiagnostic>,
|
||||
val resolvedCall: MutableResolvedCall<*>,
|
||||
finalDiagnosticsComputation: (() -> List<KotlinCallDiagnostic>)? = null
|
||||
) : Candidate {
|
||||
val diagnostics: List<KotlinCallDiagnostic> by lazy(LazyThreadSafetyMode.NONE) {
|
||||
finalDiagnosticsComputation?.invoke() ?: eagerDiagnostics
|
||||
@@ -344,22 +374,22 @@ class NewResolutionOldInference(
|
||||
}
|
||||
|
||||
private inner class CandidateFactoryImpl(
|
||||
val name: Name,
|
||||
val basicCallContext: BasicCallResolutionContext,
|
||||
val tracing: TracingStrategy
|
||||
val name: Name,
|
||||
val basicCallContext: BasicCallResolutionContext,
|
||||
val tracing: TracingStrategy
|
||||
) : CandidateFactory<MyCandidate> {
|
||||
override fun createCandidate(
|
||||
towerCandidate: CandidateWithBoundDispatchReceiver,
|
||||
explicitReceiverKind: ExplicitReceiverKind,
|
||||
extensionReceiver: ReceiverValueWithSmartCastInfo?
|
||||
towerCandidate: CandidateWithBoundDispatchReceiver,
|
||||
explicitReceiverKind: ExplicitReceiverKind,
|
||||
extensionReceiver: ReceiverValueWithSmartCastInfo?
|
||||
): MyCandidate {
|
||||
|
||||
val candidateTrace = TemporaryBindingTrace.create(basicCallContext.trace, "Context for resolve candidate")
|
||||
val candidateCall = ResolvedCallImpl(
|
||||
basicCallContext.call, towerCandidate.descriptor,
|
||||
towerCandidate.dispatchReceiver?.receiverValue, extensionReceiver?.receiverValue,
|
||||
explicitReceiverKind, null, candidateTrace, tracing,
|
||||
basicCallContext.dataFlowInfoForArguments // todo may be we should create new mutable info for arguments
|
||||
basicCallContext.call, towerCandidate.descriptor,
|
||||
towerCandidate.dispatchReceiver?.receiverValue, extensionReceiver?.receiverValue,
|
||||
explicitReceiverKind, null, candidateTrace, tracing,
|
||||
basicCallContext.dataFlowInfoForArguments // todo may be we should create new mutable info for arguments
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -385,8 +415,8 @@ class NewResolutionOldInference(
|
||||
}
|
||||
|
||||
val callCandidateResolutionContext = CallCandidateResolutionContext.create(
|
||||
candidateCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
|
||||
CandidateResolveMode.EXIT_ON_FIRST_ERROR
|
||||
candidateCall, basicCallContext, candidateTrace, tracing, basicCallContext.call,
|
||||
CandidateResolveMode.EXIT_ON_FIRST_ERROR
|
||||
)
|
||||
candidateResolver.performResolutionForCandidateCall(callCandidateResolutionContext, basicCallContext.checkArguments) // todo
|
||||
|
||||
@@ -398,14 +428,14 @@ class NewResolutionOldInference(
|
||||
}
|
||||
|
||||
private fun createDiagnosticsForCandidate(
|
||||
towerCandidate: CandidateWithBoundDispatchReceiver,
|
||||
candidateCall: ResolvedCallImpl<CallableDescriptor>
|
||||
towerCandidate: CandidateWithBoundDispatchReceiver,
|
||||
candidateCall: ResolvedCallImpl<CallableDescriptor>
|
||||
): List<ResolutionDiagnostic> =
|
||||
mutableListOf<ResolutionDiagnostic>().apply {
|
||||
addAll(towerCandidate.diagnostics)
|
||||
addAll(checkInfixAndOperator(basicCallContext.call, towerCandidate.descriptor))
|
||||
addIfNotNull(createPreviousResolveError(candidateCall.status))
|
||||
}
|
||||
mutableListOf<ResolutionDiagnostic>().apply {
|
||||
addAll(towerCandidate.diagnostics)
|
||||
addAll(checkInfixAndOperator(basicCallContext.call, towerCandidate.descriptor))
|
||||
addIfNotNull(createPreviousResolveError(candidateCall.status))
|
||||
}
|
||||
|
||||
private fun checkInfixAndOperator(call: Call, descriptor: CallableDescriptor): List<ResolutionDiagnostic> {
|
||||
if (descriptor !is FunctionDescriptor || ErrorUtils.isError(descriptor)) return emptyList()
|
||||
@@ -421,16 +451,16 @@ class NewResolutionOldInference(
|
||||
}
|
||||
|
||||
private inner class CandidateFactoryProviderForInvokeImpl(
|
||||
val functionContext: CandidateFactoryImpl
|
||||
val functionContext: CandidateFactoryImpl
|
||||
) : CandidateFactoryProviderForInvoke<MyCandidate> {
|
||||
|
||||
override fun transformCandidate(
|
||||
variable: MyCandidate,
|
||||
invoke: MyCandidate
|
||||
variable: MyCandidate,
|
||||
invoke: MyCandidate
|
||||
): MyCandidate {
|
||||
val resolvedCallImpl = VariableAsFunctionResolvedCallImpl(
|
||||
invoke.resolvedCall as MutableResolvedCall<FunctionDescriptor>,
|
||||
variable.resolvedCall as MutableResolvedCall<VariableDescriptor>
|
||||
invoke.resolvedCall as MutableResolvedCall<FunctionDescriptor>,
|
||||
variable.resolvedCall as MutableResolvedCall<VariableDescriptor>
|
||||
)
|
||||
assert(variable.resultingApplicability.isSuccess) {
|
||||
"Variable call must be success: $variable"
|
||||
@@ -445,16 +475,20 @@ class NewResolutionOldInference(
|
||||
val newCall = CallTransformer.stripCallArguments(functionContext.basicCallContext.call).let {
|
||||
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(
|
||||
variable: MyCandidate,
|
||||
useExplicitReceiver: Boolean
|
||||
variable: MyCandidate,
|
||||
useExplicitReceiver: Boolean
|
||||
): Pair<ReceiverValueWithSmartCastInfo, CandidateFactory<MyCandidate>>? {
|
||||
assert(variable.resolvedCall.status.possibleTransformToSuccess()) {
|
||||
"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 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
|
||||
}
|
||||
val basicCallContext = functionContext.basicCallContext
|
||||
val variableReceiver = ExpressionReceiver.create(calleeExpression!!,
|
||||
variableType,
|
||||
basicCallContext.trace.bindingContext)
|
||||
val variableReceiver = ExpressionReceiver.create(
|
||||
calleeExpression!!,
|
||||
variableType,
|
||||
basicCallContext.trace.bindingContext
|
||||
)
|
||||
// used for smartCasts, see: DataFlowValueFactory.getIdForSimpleNameExpression
|
||||
functionContext.tracing.bindReference(variable.resolvedCall.trace, variable.resolvedCall)
|
||||
// todo hacks
|
||||
val functionCall = CallTransformer.CallForImplicitInvoke(
|
||||
basicCallContext.call.explicitReceiver?.takeIf { useExplicitReceiver },
|
||||
variableReceiver, basicCallContext.call, true)
|
||||
basicCallContext.call.explicitReceiver?.takeIf { useExplicitReceiver },
|
||||
variableReceiver, basicCallContext.call, true
|
||||
)
|
||||
val tracingForInvoke = TracingStrategyForInvoke(calleeExpression, functionCall, variableReceiver.type)
|
||||
val basicCallResolutionContext = basicCallContext.replaceBindingTrace(variable.resolvedCall.trace)
|
||||
.replaceCall(functionCall)
|
||||
.replaceContextDependency(ContextDependency.DEPENDENT) // todo
|
||||
.replaceCall(functionCall)
|
||||
.replaceContextDependency(ContextDependency.DEPENDENT) // todo
|
||||
|
||||
val newContext = CandidateFactoryImpl(OperatorNameConventions.INVOKE, basicCallResolutionContext, tracingForInvoke)
|
||||
|
||||
@@ -491,25 +528,25 @@ class NewResolutionOldInference(
|
||||
}
|
||||
|
||||
fun ResolutionContext<*>.transformToReceiverWithSmartCastInfo(receiver: ReceiverValue) =
|
||||
transformToReceiverWithSmartCastInfo(scope.ownerDescriptor, trace.bindingContext, dataFlowInfo, receiver, languageVersionSettings)
|
||||
transformToReceiverWithSmartCastInfo(scope.ownerDescriptor, trace.bindingContext, dataFlowInfo, receiver, languageVersionSettings)
|
||||
|
||||
fun transformToReceiverWithSmartCastInfo(
|
||||
containingDescriptor: DeclarationDescriptor,
|
||||
bindingContext: BindingContext,
|
||||
dataFlowInfo: DataFlowInfo,
|
||||
receiver: ReceiverValue,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
containingDescriptor: DeclarationDescriptor,
|
||||
bindingContext: BindingContext,
|
||||
dataFlowInfo: DataFlowInfo,
|
||||
receiver: ReceiverValue,
|
||||
languageVersionSettings: LanguageVersionSettings
|
||||
): ReceiverValueWithSmartCastInfo {
|
||||
val dataFlowValue = DataFlowValueFactory.createDataFlowValue(receiver, bindingContext, containingDescriptor)
|
||||
return ReceiverValueWithSmartCastInfo(
|
||||
receiver,
|
||||
dataFlowInfo.getCollectedTypes(dataFlowValue, languageVersionSettings),
|
||||
dataFlowValue.isStable
|
||||
receiver,
|
||||
dataFlowInfo.getCollectedTypes(dataFlowValue, languageVersionSettings),
|
||||
dataFlowValue.isStable
|
||||
)
|
||||
}
|
||||
|
||||
@Deprecated("Temporary error")
|
||||
internal class PreviousResolutionError(candidateLevel: ResolutionCandidateApplicability): ResolutionDiagnostic(candidateLevel)
|
||||
internal class PreviousResolutionError(candidateLevel: ResolutionCandidateApplicability) : ResolutionDiagnostic(candidateLevel)
|
||||
|
||||
@Deprecated("Temporary error")
|
||||
internal fun createPreviousResolveError(status: ResolutionStatus): PreviousResolutionError? {
|
||||
|
||||
+197
-158
@@ -60,28 +60,28 @@ import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
import java.util.*
|
||||
|
||||
class PSICallResolver(
|
||||
private val typeResolver: TypeResolver,
|
||||
private val expressionTypingServices: ExpressionTypingServices,
|
||||
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
|
||||
private val syntheticScopes: SyntheticScopes,
|
||||
private val callComponents: KotlinCallComponents,
|
||||
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||
private val kotlinCallResolver: KotlinCallResolver,
|
||||
private val typeApproximator: TypeApproximator,
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val effectSystem: EffectSystem,
|
||||
private val constantExpressionEvaluator: ConstantExpressionEvaluator
|
||||
private val typeResolver: TypeResolver,
|
||||
private val expressionTypingServices: ExpressionTypingServices,
|
||||
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||
private val languageVersionSettings: LanguageVersionSettings,
|
||||
private val dynamicCallableDescriptors: DynamicCallableDescriptors,
|
||||
private val syntheticScopes: SyntheticScopes,
|
||||
private val callComponents: KotlinCallComponents,
|
||||
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||
private val kotlinCallResolver: KotlinCallResolver,
|
||||
private val typeApproximator: TypeApproximator,
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val effectSystem: EffectSystem,
|
||||
private val constantExpressionEvaluator: ConstantExpressionEvaluator
|
||||
) {
|
||||
private val GIVEN_CANDIDATES_NAME = Name.special("<given candidates>")
|
||||
|
||||
fun <D : CallableDescriptor> runResolutionAndInference(
|
||||
context: BasicCallResolutionContext,
|
||||
name: Name,
|
||||
resolutionKind: NewResolutionOldInference.ResolutionKind<D>,
|
||||
tracingStrategy: TracingStrategy
|
||||
) : OverloadResolutionResults<D> {
|
||||
context: BasicCallResolutionContext,
|
||||
name: Name,
|
||||
resolutionKind: NewResolutionOldInference.ResolutionKind<D>,
|
||||
tracingStrategy: TracingStrategy
|
||||
): OverloadResolutionResults<D> {
|
||||
val isBinaryRemOperator = isBinaryRemOperator(context.call)
|
||||
val refinedName = refineNameForRemOperator(isBinaryRemOperator, name)
|
||||
|
||||
@@ -93,7 +93,8 @@ class PSICallResolver(
|
||||
|
||||
val expectedType = calculateExpectedType(context)
|
||||
var result = kotlinCallResolver.resolveCall(
|
||||
scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke, context.collectAllCandidates)
|
||||
scopeTower, resolutionCallbacks, kotlinCall, expectedType, factoryProviderForInvoke, context.collectAllCandidates
|
||||
)
|
||||
|
||||
val shouldUseOperatorRem = languageVersionSettings.supportsFeature(LanguageFeature.OperatorRem)
|
||||
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`
|
||||
fun <D : CallableDescriptor> runResolutionAndInferenceForGivenCandidates(
|
||||
context: BasicCallResolutionContext,
|
||||
resolutionCandidates: Collection<ResolutionCandidate<D>>,
|
||||
tracingStrategy: TracingStrategy
|
||||
context: BasicCallResolutionContext,
|
||||
resolutionCandidates: Collection<ResolutionCandidate<D>>,
|
||||
tracingStrategy: TracingStrategy
|
||||
): OverloadResolutionResults<D> {
|
||||
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 resolutionCallbacks = createResolutionCallbacks(context)
|
||||
|
||||
val givenCandidates = resolutionCandidates.map {
|
||||
GivenCandidate(it.descriptor as FunctionDescriptor,
|
||||
it.dispatchReceiver?.let { context.transformToReceiverWithSmartCastInfo(it) },
|
||||
it.knownTypeParametersResultingSubstitutor)
|
||||
GivenCandidate(
|
||||
it.descriptor as FunctionDescriptor,
|
||||
it.dispatchReceiver?.let { context.transformToReceiverWithSmartCastInfo(it) },
|
||||
it.knownTypeParametersResultingSubstitutor
|
||||
)
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> resolveToDeprecatedMod(
|
||||
remOperatorName: Name,
|
||||
context: BasicCallResolutionContext,
|
||||
resolutionKind: NewResolutionOldInference.ResolutionKind<D>,
|
||||
tracingStrategy: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower,
|
||||
resolutionCallbacks: KotlinResolutionCallbacksImpl,
|
||||
expectedType: UnwrappedType?
|
||||
remOperatorName: Name,
|
||||
context: BasicCallResolutionContext,
|
||||
resolutionKind: NewResolutionOldInference.ResolutionKind<D>,
|
||||
tracingStrategy: TracingStrategy,
|
||||
scopeTower: ImplicitScopeTower,
|
||||
resolutionCallbacks: KotlinResolutionCallbacksImpl,
|
||||
expectedType: UnwrappedType?
|
||||
): CallResolutionResult {
|
||||
val deprecatedName = OperatorConventions.REM_TO_MOD_OPERATION_NAMES[remOperatorName]!!
|
||||
val callWithDeprecatedName = toKotlinCall(context, resolutionKind.kotlinCallKind, context.call, deprecatedName, tracingStrategy)
|
||||
val refinedProviderForInvokeFactory = FactoryProviderForInvoke(context, scopeTower, callWithDeprecatedName)
|
||||
return kotlinCallResolver.resolveCall(scopeTower, resolutionCallbacks, callWithDeprecatedName, expectedType,
|
||||
refinedProviderForInvokeFactory, context.collectAllCandidates)
|
||||
return kotlinCallResolver.resolveCall(
|
||||
scopeTower, resolutionCallbacks, callWithDeprecatedName, expectedType,
|
||||
refinedProviderForInvokeFactory, context.collectAllCandidates
|
||||
)
|
||||
}
|
||||
|
||||
private fun refineNameForRemOperator(isBinaryRemOperator: Boolean, name: Name): Name {
|
||||
@@ -153,9 +160,11 @@ class PSICallResolver(
|
||||
}
|
||||
|
||||
private fun createResolutionCallbacks(context: BasicCallResolutionContext) =
|
||||
KotlinResolutionCallbacksImpl(context, expressionTypingServices, typeApproximator,
|
||||
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer,
|
||||
constantExpressionEvaluator)
|
||||
KotlinResolutionCallbacksImpl(
|
||||
context, expressionTypingServices, typeApproximator,
|
||||
argumentTypeResolver, languageVersionSettings, kotlinToResolvedCallTransformer,
|
||||
constantExpressionEvaluator
|
||||
)
|
||||
|
||||
private fun calculateExpectedType(context: BasicCallResolutionContext): UnwrappedType? {
|
||||
val expectedType = context.expectedType.unwrap()
|
||||
@@ -165,16 +174,15 @@ class PSICallResolver(
|
||||
"Should have no expected type, got: $expectedType"
|
||||
}
|
||||
null
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (expectedType.isError) TypeUtils.NO_EXPECTED_TYPE else expectedType
|
||||
}
|
||||
}
|
||||
|
||||
private fun <D : CallableDescriptor> convertToOverloadResolutionResults(
|
||||
context: BasicCallResolutionContext,
|
||||
result: CallResolutionResult,
|
||||
tracingStrategy: TracingStrategy
|
||||
context: BasicCallResolutionContext,
|
||||
result: CallResolutionResult,
|
||||
tracingStrategy: TracingStrategy
|
||||
): OverloadResolutionResults<D> {
|
||||
if (result.type == CallResolutionResult.Type.ALL_CANDIDATES) {
|
||||
val resolvedCalls = result.allCandidates?.map {
|
||||
@@ -197,28 +205,26 @@ class PSICallResolver(
|
||||
if (it.candidates.areAllFailed()) {
|
||||
tracingStrategy.noneApplicable(trace, resolvedCalls)
|
||||
tracingStrategy.recordAmbiguity(trace, resolvedCalls)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
tracingStrategy.recordAmbiguity(trace, resolvedCalls)
|
||||
if (resolvedCalls.first().status == ResolutionStatus.INCOMPLETE_TYPE_INFERENCE) {
|
||||
tracingStrategy.cannotCompleteResolve(trace, resolvedCalls)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
tracingStrategy.ambiguity(trace, 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 singleCandidate = result.resultCallAtom ?: error("Should be not null for result: $result")
|
||||
kotlinToResolvedCallTransformer.onlyTransform<D>(singleCandidate, result.diagnostics).also {
|
||||
tracingStrategy.unresolvedReferenceWrongReceiver(trace, listOf(it))
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
kotlinToResolvedCallTransformer.transformAndReport<D>(result, context)
|
||||
}
|
||||
|
||||
@@ -246,12 +252,12 @@ class PSICallResolver(
|
||||
}
|
||||
|
||||
private fun CallResolutionResult.isEmpty(): Boolean =
|
||||
diagnostics.firstIsInstanceOrNull<NoneCandidatesCallDiagnostic>() != null
|
||||
diagnostics.firstIsInstanceOrNull<NoneCandidatesCallDiagnostic>() != null
|
||||
|
||||
private fun Collection<KotlinResolutionCandidate>.areAllFailed() =
|
||||
all {
|
||||
!it.resultingApplicability.isSuccess
|
||||
}
|
||||
all {
|
||||
!it.resultingApplicability.isSuccess
|
||||
}
|
||||
|
||||
private fun CallResolutionResult.areAllInapplicable(): Boolean {
|
||||
val manyCandidates = diagnostics.firstIsInstanceOrNull<ManyCandidatesCallDiagnostic>()?.candidates
|
||||
@@ -261,16 +267,16 @@ class PSICallResolver(
|
||||
|
||||
val applicability = getResultApplicability(diagnostics)
|
||||
return applicability == ResolutionCandidateApplicability.INAPPLICABLE ||
|
||||
applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER ||
|
||||
applicability == ResolutionCandidateApplicability.HIDDEN
|
||||
applicability == ResolutionCandidateApplicability.INAPPLICABLE_WRONG_RECEIVER ||
|
||||
applicability == ResolutionCandidateApplicability.HIDDEN
|
||||
}
|
||||
|
||||
// true if we found something
|
||||
private fun reportAdditionalDiagnosticIfNoCandidates(
|
||||
context: BasicCallResolutionContext,
|
||||
scopeTower: ImplicitScopeTower,
|
||||
kind: KotlinCallKind,
|
||||
kotlinCall: KotlinCall
|
||||
context: BasicCallResolutionContext,
|
||||
scopeTower: ImplicitScopeTower,
|
||||
kind: KotlinCallKind,
|
||||
kotlinCall: KotlinCall
|
||||
): Boolean {
|
||||
val reference = context.call.calleeExpression as? KtReferenceExpression ?: return false
|
||||
|
||||
@@ -285,7 +291,14 @@ class PSICallResolver(
|
||||
for (candidate in errorCandidates) {
|
||||
if (candidate is ErrorCandidate.Classifier) {
|
||||
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
|
||||
}
|
||||
}
|
||||
@@ -294,10 +307,11 @@ class PSICallResolver(
|
||||
|
||||
|
||||
private inner class ASTScopeTower(
|
||||
val context: BasicCallResolutionContext
|
||||
): ImplicitScopeTower {
|
||||
val context: BasicCallResolutionContext
|
||||
) : ImplicitScopeTower {
|
||||
// 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
|
||||
override val location: LookupLocation = context.call.createLookupLocation()
|
||||
|
||||
@@ -317,9 +331,9 @@ class PSICallResolver(
|
||||
}
|
||||
|
||||
private inner class FactoryProviderForInvoke(
|
||||
val context: BasicCallResolutionContext,
|
||||
val scopeTower: ImplicitScopeTower,
|
||||
val kotlinCall: PSIKotlinCallImpl
|
||||
val context: BasicCallResolutionContext,
|
||||
val scopeTower: ImplicitScopeTower,
|
||||
val kotlinCall: PSIKotlinCallImpl
|
||||
) : CandidateFactoryProviderForInvoke<KotlinResolutionCandidate> {
|
||||
|
||||
init {
|
||||
@@ -327,8 +341,8 @@ class PSICallResolver(
|
||||
}
|
||||
|
||||
override fun transformCandidate(
|
||||
variable: KotlinResolutionCandidate,
|
||||
invoke: KotlinResolutionCandidate
|
||||
variable: KotlinResolutionCandidate,
|
||||
invoke: KotlinResolutionCandidate
|
||||
) = invoke
|
||||
|
||||
override fun factoryForVariable(stripExplicitReceiver: Boolean): CandidateFactory<KotlinResolutionCandidate> {
|
||||
@@ -343,15 +357,14 @@ class PSICallResolver(
|
||||
|
||||
assert(variable.isSuccessful) {
|
||||
"Variable call should be successful: $variable " +
|
||||
"Descriptor: ${variable.resolvedCall.candidateDescriptor}"
|
||||
"Descriptor: ${variable.resolvedCall.candidateDescriptor}"
|
||||
}
|
||||
val variableCallArgument = createReceiverCallArgument(variable)
|
||||
|
||||
val explicitReceiver = kotlinCall.explicitReceiver
|
||||
val callForInvoke = if (useExplicitReceiver && explicitReceiver != null) {
|
||||
PSIKotlinCallForInvoke(kotlinCall, variable, explicitReceiver, variableCallArgument)
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
PSIKotlinCallForInvoke(kotlinCall, variable, variableCallArgument, null)
|
||||
}
|
||||
|
||||
@@ -369,22 +382,32 @@ class PSICallResolver(
|
||||
variable.forceResolution()
|
||||
val variableReceiver = createReceiverValueWithSmartCastInfo(variable)
|
||||
if (variableReceiver.possibleTypes.isNotEmpty()) {
|
||||
return ReceiverExpressionKotlinCallArgument(createReceiverValueWithSmartCastInfo(variable), isVariableReceiverForInvoke = true)
|
||||
return ReceiverExpressionKotlinCallArgument(
|
||||
createReceiverValueWithSmartCastInfo(variable),
|
||||
isVariableReceiverForInvoke = true
|
||||
)
|
||||
}
|
||||
|
||||
val psiKotlinCall = variable.resolvedCall.atom.psiKotlinCall
|
||||
|
||||
val variableResult = CallResolutionResult(CallResolutionResult.Type.PARTIAL, variable.resolvedCall, listOf(), variable.getSystem().asReadOnlyStorage())
|
||||
return SubKotlinCallArgumentImpl(CallMaker.makeExternalValueArgument((variableReceiver.receiverValue as ExpressionReceiver).expression),
|
||||
psiKotlinCall.resultDataFlowInfo, psiKotlinCall.resultDataFlowInfo, variableReceiver,
|
||||
variableResult)
|
||||
val variableResult = CallResolutionResult(
|
||||
CallResolutionResult.Type.PARTIAL,
|
||||
variable.resolvedCall,
|
||||
listOf(),
|
||||
variable.getSystem().asReadOnlyStorage()
|
||||
)
|
||||
return SubKotlinCallArgumentImpl(
|
||||
CallMaker.makeExternalValueArgument((variableReceiver.receiverValue as ExpressionReceiver).expression),
|
||||
psiKotlinCall.resultDataFlowInfo, psiKotlinCall.resultDataFlowInfo, variableReceiver,
|
||||
variableResult
|
||||
)
|
||||
}
|
||||
|
||||
// todo: decrease hacks count
|
||||
private fun createReceiverValueWithSmartCastInfo(variable: KotlinResolutionCandidate): ReceiverValueWithSmartCastInfo {
|
||||
val callForVariable = variable.resolvedCall.atom as PSIKotlinCallForVariable
|
||||
val calleeExpression = callForVariable.baseCall.psiCall.calleeExpression as? KtReferenceExpression ?:
|
||||
error("Unexpected call : ${callForVariable.baseCall.psiCall}")
|
||||
val calleeExpression = callForVariable.baseCall.psiCall.calleeExpression as? KtReferenceExpression
|
||||
?: error("Unexpected call : ${callForVariable.baseCall.psiCall}")
|
||||
|
||||
val temporaryTrace = TemporaryBindingTrace.create(context.trace, "Context for resolve candidate")
|
||||
|
||||
@@ -392,31 +415,32 @@ class PSICallResolver(
|
||||
val variableReceiver = ExpressionReceiver.create(calleeExpression, type, temporaryTrace.bindingContext)
|
||||
|
||||
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(
|
||||
variableReceiver,
|
||||
context.dataFlowInfo.getCollectedTypes(dataFlowValue, context.languageVersionSettings),
|
||||
dataFlowValue.isStable
|
||||
variableReceiver,
|
||||
context.dataFlowInfo.getCollectedTypes(dataFlowValue, context.languageVersionSettings),
|
||||
dataFlowValue.isStable
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun toKotlinCall(
|
||||
context: BasicCallResolutionContext,
|
||||
kotlinCallKind: KotlinCallKind,
|
||||
oldCall: Call,
|
||||
name: Name,
|
||||
tracingStrategy: TracingStrategy,
|
||||
forcedExplicitReceiver: Receiver? = null
|
||||
context: BasicCallResolutionContext,
|
||||
kotlinCallKind: KotlinCallKind,
|
||||
oldCall: Call,
|
||||
name: Name,
|
||||
tracingStrategy: TracingStrategy,
|
||||
forcedExplicitReceiver: Receiver? = null
|
||||
): 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 argumentsInParenthesis = if (oldCall.callType != Call.CallType.ARRAY_SET_METHOD && oldCall.functionLiteralArguments.isEmpty()) {
|
||||
oldCall.valueArguments
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
oldCall.valueArguments.dropLast(1)
|
||||
}
|
||||
|
||||
@@ -428,8 +452,7 @@ class PSICallResolver(
|
||||
"Unexpected lambda parameters for call $oldCall"
|
||||
}
|
||||
oldCall.valueArguments.last()
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (externalLambdaArguments.size > 2) {
|
||||
externalLambdaArguments.drop(1).forEach {
|
||||
context.trace.report(Errors.MANY_LAMBDA_EXPRESSION_ARGUMENTS.on(it.getLambdaExpression()))
|
||||
@@ -440,10 +463,10 @@ class PSICallResolver(
|
||||
}
|
||||
|
||||
val dataFlowInfoAfterArgumentsInParenthesis =
|
||||
if (externalArgument != null && resolvedArgumentsInParenthesis.isNotEmpty())
|
||||
resolvedArgumentsInParenthesis.last().psiCallArgument.dataFlowInfoAfterThisArgument
|
||||
else
|
||||
context.dataFlowInfoForArguments.resultInfo
|
||||
if (externalArgument != null && resolvedArgumentsInParenthesis.isNotEmpty())
|
||||
resolvedArgumentsInParenthesis.last().psiCallArgument.dataFlowInfoAfterThisArgument
|
||||
else
|
||||
context.dataFlowInfoForArguments.resultInfo
|
||||
|
||||
val astExternalArgument = externalArgument?.let { resolveValueArgument(context, dataFlowInfoAfterArgumentsInParenthesis, it) }
|
||||
val resultDataFlowInfo = astExternalArgument?.dataFlowInfoAfterThisArgument ?: dataFlowInfoAfterArgumentsInParenthesis
|
||||
@@ -451,39 +474,47 @@ class PSICallResolver(
|
||||
resolvedArgumentsInParenthesis.forEach { it.setResultDataFlowInfoIfRelevant(resultDataFlowInfo) }
|
||||
astExternalArgument?.setResultDataFlowInfoIfRelevant(resultDataFlowInfo)
|
||||
|
||||
return PSIKotlinCallImpl(kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, name, resolvedTypeArguments, resolvedArgumentsInParenthesis,
|
||||
astExternalArgument, context.dataFlowInfo, resultDataFlowInfo, context.dataFlowInfoForArguments)
|
||||
return PSIKotlinCallImpl(
|
||||
kotlinCallKind, oldCall, tracingStrategy, resolvedExplicitReceiver, name, resolvedTypeArguments, resolvedArgumentsInParenthesis,
|
||||
astExternalArgument, context.dataFlowInfo, resultDataFlowInfo, context.dataFlowInfoForArguments
|
||||
)
|
||||
}
|
||||
|
||||
private fun resolveExplicitReceiver(context: BasicCallResolutionContext, oldReceiver: Receiver?, isSafeCall: Boolean): ReceiverKotlinCallArgument? =
|
||||
when(oldReceiver) {
|
||||
null -> null
|
||||
is QualifierReceiver -> QualifierReceiverKotlinCallArgument(oldReceiver) // todo report warning if isSafeCall
|
||||
is ReceiverValue -> {
|
||||
val detailedReceiver = context.transformToReceiverWithSmartCastInfo(oldReceiver)
|
||||
private fun resolveExplicitReceiver(
|
||||
context: BasicCallResolutionContext,
|
||||
oldReceiver: Receiver?,
|
||||
isSafeCall: Boolean
|
||||
): ReceiverKotlinCallArgument? =
|
||||
when (oldReceiver) {
|
||||
null -> null
|
||||
is QualifierReceiver -> QualifierReceiverKotlinCallArgument(oldReceiver) // todo report warning if isSafeCall
|
||||
is ReceiverValue -> {
|
||||
val detailedReceiver = context.transformToReceiverWithSmartCastInfo(oldReceiver)
|
||||
|
||||
var subCallArgument: ReceiverKotlinCallArgument? = null
|
||||
if (oldReceiver is ExpressionReceiver) {
|
||||
val ktExpression = KtPsiUtil.getLastElementDeparenthesized(oldReceiver.expression, context.statementFilter)
|
||||
var subCallArgument: ReceiverKotlinCallArgument? = null
|
||||
if (oldReceiver is ExpressionReceiver) {
|
||||
val ktExpression = KtPsiUtil.getLastElementDeparenthesized(oldReceiver.expression, context.statementFilter)
|
||||
|
||||
val bindingContext = context.trace.bindingContext
|
||||
val call = bindingContext[BindingContext.DELEGATE_EXPRESSION_TO_PROVIDE_DELEGATE_CALL, ktExpression]
|
||||
?: ktExpression?.getCall(bindingContext)
|
||||
val bindingContext = context.trace.bindingContext
|
||||
val call = bindingContext[BindingContext.DELEGATE_EXPRESSION_TO_PROVIDE_DELEGATE_CALL, ktExpression]
|
||||
?: ktExpression?.getCall(bindingContext)
|
||||
|
||||
val onlyResolvedCall = call?.let {
|
||||
bindingContext.get(BindingContext.ONLY_RESOLVED_CALL, it)
|
||||
}
|
||||
if (onlyResolvedCall != null) {
|
||||
subCallArgument = SubKotlinCallArgumentImpl(CallMaker.makeExternalValueArgument(oldReceiver.expression),
|
||||
context.dataFlowInfo, context.dataFlowInfo, detailedReceiver, onlyResolvedCall)
|
||||
|
||||
}
|
||||
val onlyResolvedCall = call?.let {
|
||||
bindingContext.get(BindingContext.ONLY_RESOLVED_CALL, it)
|
||||
}
|
||||
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? {
|
||||
if (typeReference == null) return null
|
||||
@@ -494,18 +525,19 @@ class PSICallResolver(
|
||||
}
|
||||
|
||||
private fun resolveTypeArguments(context: BasicCallResolutionContext, typeArguments: List<KtTypeProjection>): List<TypeArgument> =
|
||||
typeArguments.map { projection ->
|
||||
if (projection.projectionKind != KtProjectionKind.NONE) {
|
||||
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
|
||||
typeArguments.map { projection ->
|
||||
if (projection.projectionKind != KtProjectionKind.NONE) {
|
||||
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
|
||||
}
|
||||
|
||||
private fun resolveArgumentsInParenthesis(
|
||||
context: BasicCallResolutionContext,
|
||||
arguments: List<ValueArgument>
|
||||
context: BasicCallResolutionContext,
|
||||
arguments: List<ValueArgument>
|
||||
): List<KotlinCallArgument> {
|
||||
val dataFlowInfoForArguments = context.dataFlowInfoForArguments
|
||||
return arguments.map { argument ->
|
||||
@@ -516,9 +548,9 @@ class PSICallResolver(
|
||||
}
|
||||
|
||||
private fun resolveValueArgument(
|
||||
outerCallContext: BasicCallResolutionContext,
|
||||
startDataFlowInfo: DataFlowInfo,
|
||||
valueArgument: ValueArgument
|
||||
outerCallContext: BasicCallResolutionContext,
|
||||
startDataFlowInfo: DataFlowInfo,
|
||||
valueArgument: ValueArgument
|
||||
): PSIKotlinCallArgument {
|
||||
val builtIns = outerCallContext.scope.ownerDescriptor.builtIns
|
||||
val parseErrorArgument = ParseErrorKotlinCallArgument(valueArgument, startDataFlowInfo, builtIns)
|
||||
@@ -534,17 +566,21 @@ class PSICallResolver(
|
||||
|
||||
if (ktExpression is KtCollectionLiteralExpression) {
|
||||
return CollectionLiteralKotlinCallArgumentImpl(
|
||||
valueArgument, argumentName, startDataFlowInfo, startDataFlowInfo, ktExpression, outerCallContext)
|
||||
valueArgument, argumentName, startDataFlowInfo, startDataFlowInfo, ktExpression, outerCallContext
|
||||
)
|
||||
}
|
||||
|
||||
val context = outerCallContext.replaceContextDependency(ContextDependency.DEPENDENT)
|
||||
.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceDataFlowInfo(startDataFlowInfo)
|
||||
.replaceExpectedType(TypeUtils.NO_EXPECTED_TYPE).replaceDataFlowInfo(startDataFlowInfo)
|
||||
|
||||
if (ktExpression is KtCallableReferenceExpression) {
|
||||
checkNoSpread(outerCallContext, valueArgument)
|
||||
|
||||
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 name = ktExpression.callableReference.getReferencedNameAsName()
|
||||
|
||||
@@ -556,12 +592,10 @@ class PSICallResolver(
|
||||
val calleeExpression = ktExpression.receiverExpression?.getCalleeExpressionIfAny()
|
||||
if (calleeExpression is KtSimpleNameExpression && classifier is ClassDescriptor) {
|
||||
LHSResult.Object(ClassQualifier(calleeExpression, classifier))
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LHSResult.Error
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
val fakeArgument = FakeValueArgumentForLeftCallableReference(ktExpression)
|
||||
|
||||
val kotlinCallArgument = createSimplePSICallArgument(context, fakeArgument, lhsResult.typeInfo)
|
||||
@@ -573,15 +607,16 @@ class PSICallResolver(
|
||||
val qualifier = expressionTypingContext.trace.get(BindingContext.QUALIFIER, qualifiedExpression)
|
||||
if (qualifier is ClassQualifier) {
|
||||
LHSResult.Type(qualifier, lhsResult.type.unwrap())
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
LHSResult.Error
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CallableReferenceKotlinCallArgumentImpl(ASTScopeTower(context), valueArgument, startDataFlowInfo, newDataFlowInfo,
|
||||
ktExpression, argumentName, lhsNewResult, name)
|
||||
return CallableReferenceKotlinCallArgumentImpl(
|
||||
ASTScopeTower(context), valueArgument, startDataFlowInfo, newDataFlowInfo,
|
||||
ktExpression, argumentName, lhsNewResult, name
|
||||
)
|
||||
}
|
||||
|
||||
// argumentExpression instead of ktExpression is hack -- type info should be stored also for parenthesized expression
|
||||
@@ -590,29 +625,33 @@ class PSICallResolver(
|
||||
}
|
||||
|
||||
private fun processFunctionalExpression(
|
||||
outerCallContext: BasicCallResolutionContext,
|
||||
argumentExpression: KtExpression,
|
||||
startDataFlowInfo: DataFlowInfo,
|
||||
valueArgument: ValueArgument,
|
||||
argumentName: Name?,
|
||||
builtIns: KotlinBuiltIns
|
||||
outerCallContext: BasicCallResolutionContext,
|
||||
argumentExpression: KtExpression,
|
||||
startDataFlowInfo: DataFlowInfo,
|
||||
valueArgument: ValueArgument,
|
||||
argumentName: Name?,
|
||||
builtIns: KotlinBuiltIns
|
||||
): PSIKotlinCallArgument? {
|
||||
val expression = ArgumentTypeResolver.getFunctionLiteralArgumentIfAny(argumentExpression, outerCallContext) ?: return null
|
||||
val postponedExpression = if (expression is KtFunctionLiteral) expression.getParentOfType<KtLambdaExpression>(true) else expression
|
||||
|
||||
val lambdaArgument: PSIKotlinCallArgument? = when (postponedExpression) {
|
||||
is KtLambdaExpression ->
|
||||
LambdaKotlinCallArgumentImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName, postponedExpression,
|
||||
argumentExpression, resolveParametersTypes(outerCallContext, postponedExpression.functionLiteral))
|
||||
LambdaKotlinCallArgumentImpl(
|
||||
outerCallContext, valueArgument, startDataFlowInfo, argumentName, postponedExpression,
|
||||
argumentExpression, resolveParametersTypes(outerCallContext, postponedExpression.functionLiteral)
|
||||
)
|
||||
|
||||
is KtNamedFunction -> {
|
||||
val receiverType = resolveType(outerCallContext, postponedExpression.receiverTypeReference)
|
||||
val parametersTypes = resolveParametersTypes(outerCallContext, postponedExpression) ?: emptyArray()
|
||||
val returnType = resolveType(outerCallContext, postponedExpression.typeReference) ?:
|
||||
if (postponedExpression.hasBlockBody()) builtIns.unitType else null
|
||||
val returnType = resolveType(outerCallContext, postponedExpression.typeReference)
|
||||
?: if (postponedExpression.hasBlockBody()) builtIns.unitType else null
|
||||
|
||||
FunctionExpressionImpl(outerCallContext, valueArgument, startDataFlowInfo, argumentName,
|
||||
argumentExpression, postponedExpression, receiverType, parametersTypes, returnType)
|
||||
FunctionExpressionImpl(
|
||||
outerCallContext, valueArgument, startDataFlowInfo, argumentName,
|
||||
argumentExpression, postponedExpression, receiverType, parametersTypes, returnType
|
||||
)
|
||||
}
|
||||
|
||||
else -> return null
|
||||
|
||||
+64
-39
@@ -47,16 +47,16 @@ import org.jetbrains.kotlin.types.expressions.ExpressionTypingServices
|
||||
import org.jetbrains.kotlin.types.typeUtil.asTypeProjection
|
||||
|
||||
class ResolvedAtomCompleter(
|
||||
private val resultSubstitutor: NewTypeSubstitutor,
|
||||
private val trace: BindingTrace,
|
||||
private val topLevelCallContext: BasicCallResolutionContext,
|
||||
private val resultSubstitutor: NewTypeSubstitutor,
|
||||
private val trace: BindingTrace,
|
||||
private val topLevelCallContext: BasicCallResolutionContext,
|
||||
|
||||
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||
private val expressionTypingServices: ExpressionTypingServices,
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
deprecationResolver: DeprecationResolver
|
||||
private val kotlinToResolvedCallTransformer: KotlinToResolvedCallTransformer,
|
||||
private val expressionTypingServices: ExpressionTypingServices,
|
||||
private val argumentTypeResolver: ArgumentTypeResolver,
|
||||
private val doubleColonExpressionResolver: DoubleColonExpressionResolver,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
deprecationResolver: DeprecationResolver
|
||||
) {
|
||||
private val callCheckerContext = CallCheckerContext(topLevelCallContext, languageVersionSettings, deprecationResolver)
|
||||
|
||||
@@ -79,7 +79,12 @@ class ResolvedAtomCompleter(
|
||||
fun completeResolvedCall(resolvedCallAtom: ResolvedCallAtom, diagnostics: Collection<KotlinCallDiagnostic>): ResolvedCall<*>? {
|
||||
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.runCallCheckers(resolvedCall, callCheckerContext)
|
||||
|
||||
@@ -90,20 +95,20 @@ class ResolvedAtomCompleter(
|
||||
}
|
||||
|
||||
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) {
|
||||
val resultValueArgument = lambdaResult as? PSIKotlinCallArgument ?: continue
|
||||
val newContext =
|
||||
topLevelCallContext.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument)
|
||||
.replaceExpectedType(returnType)
|
||||
.replaceBindingTrace(trace)
|
||||
for (lambdaResult in lambda.resultArguments) {
|
||||
val resultValueArgument = lambdaResult as? PSIKotlinCallArgument ?: continue
|
||||
val newContext =
|
||||
topLevelCallContext.replaceDataFlowInfo(resultValueArgument.dataFlowInfoAfterThisArgument)
|
||||
.replaceExpectedType(returnType)
|
||||
.replaceBindingTrace(trace)
|
||||
|
||||
val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue
|
||||
kotlinToResolvedCallTransformer.updateRecordedType(argumentExpression, newContext, true)
|
||||
}
|
||||
val argumentExpression = resultValueArgument.valueArgument.getArgumentExpression() ?: continue
|
||||
kotlinToResolvedCallTransformer.updateRecordedType(argumentExpression, newContext, true)
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
|
||||
val functionDescriptor = trace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? FunctionDescriptorImpl ?:
|
||||
throw AssertionError("No function descriptor for resolved lambda argument")
|
||||
val functionDescriptor = trace.bindingContext.get(BindingContext.FUNCTION, ktFunction) as? FunctionDescriptorImpl
|
||||
?: throw AssertionError("No function descriptor for resolved lambda argument")
|
||||
functionDescriptor.setReturnType(returnType)
|
||||
|
||||
val existingLambdaType = trace.getType(ktArgumentExpression) ?: throw AssertionError("No type for resolved lambda argument")
|
||||
@@ -132,26 +137,31 @@ class ResolvedAtomCompleter(
|
||||
}
|
||||
|
||||
private fun completeCallableReference(
|
||||
resolvedAtom: ResolvedCallableReferenceAtom
|
||||
resolvedAtom: ResolvedCallableReferenceAtom
|
||||
) {
|
||||
val callableCandidate = resolvedAtom.candidate
|
||||
if (callableCandidate == null) {
|
||||
// todo report meanfull diagnostic here
|
||||
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 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
|
||||
val resultType = resultSubstitutor.safeSubstitute(callableCandidate.reflectionCandidateType, Variance.INVARIANT)
|
||||
argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(trace, expressionTypingServices.statementFilter,
|
||||
resultType,
|
||||
callableReferenceExpression)
|
||||
argumentTypeResolver.updateResultArgumentTypeIfNotDenotable(
|
||||
trace, expressionTypingServices.statementFilter,
|
||||
resultType,
|
||||
callableReferenceExpression
|
||||
)
|
||||
val reference = callableReferenceExpression.callableReference
|
||||
|
||||
val explicitCallableReceiver = when (callableCandidate.explicitReceiverKind) {
|
||||
@@ -166,9 +176,11 @@ class ResolvedAtomCompleter(
|
||||
val tracing = TracingStrategyImpl.create(reference, psiCall)
|
||||
val temporaryTrace = TemporaryBindingTrace.create(trace, "callable reference fake call")
|
||||
|
||||
val resolvedCall = ResolvedCallImpl(psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue,
|
||||
callableCandidate.extensionReceiver?.receiver?.receiverValue, callableCandidate.explicitReceiverKind,
|
||||
null, temporaryTrace, tracing, MutableDataFlowInfoForArguments.WithoutArgumentsCheck(DataFlowInfo.EMPTY))
|
||||
val resolvedCall = ResolvedCallImpl(
|
||||
psiCall, callableCandidate.candidate, callableCandidate.dispatchReceiver?.receiver?.receiverValue,
|
||||
callableCandidate.extensionReceiver?.receiver?.receiverValue, callableCandidate.explicitReceiverKind,
|
||||
null, temporaryTrace, tracing, MutableDataFlowInfoForArguments.WithoutArgumentsCheck(DataFlowInfo.EMPTY)
|
||||
)
|
||||
resolvedCall.setResultingSubstitutor(resultSubstitutor)
|
||||
|
||||
tracing.bindCall(trace, psiCall)
|
||||
@@ -179,27 +191,40 @@ class ResolvedAtomCompleter(
|
||||
resolvedCall.markCallAsCompleted()
|
||||
|
||||
when (callableCandidate.candidate) {
|
||||
is FunctionDescriptor -> doubleColonExpressionResolver.bindFunctionReference(callableReferenceExpression, resultType, topLevelCallContext)
|
||||
is PropertyDescriptor -> doubleColonExpressionResolver.bindPropertyReference(callableReferenceExpression, resultType, topLevelCallContext)
|
||||
is FunctionDescriptor -> doubleColonExpressionResolver.bindFunctionReference(
|
||||
callableReferenceExpression,
|
||||
resultType,
|
||||
topLevelCallContext
|
||||
)
|
||||
is PropertyDescriptor -> doubleColonExpressionResolver.bindPropertyReference(
|
||||
callableReferenceExpression,
|
||||
resultType,
|
||||
topLevelCallContext
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: probably we should also record key 'DATA_FLOW_INFO_BEFORE', see ExpressionTypingVisitorDispatcher.getTypeInfo
|
||||
trace.recordType(callableReferenceExpression, resultType)
|
||||
trace.record(BindingContext.PROCESSED, callableReferenceExpression)
|
||||
|
||||
doubleColonExpressionResolver.checkReferenceIsToAllowedMember(callableCandidate.candidate, topLevelCallContext.trace, callableReferenceExpression)
|
||||
doubleColonExpressionResolver.checkReferenceIsToAllowedMember(
|
||||
callableCandidate.candidate,
|
||||
topLevelCallContext.trace,
|
||||
callableReferenceExpression
|
||||
)
|
||||
}
|
||||
|
||||
private fun completeCollectionLiteralCalls(collectionLiteralArgument: ResolvedCollectionLiteralAtom) {
|
||||
val psiCallArgument = collectionLiteralArgument.atom.psiCallArgument as CollectionLiteralKotlinCallArgumentImpl
|
||||
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
|
||||
.replaceBindingTrace(trace)
|
||||
.replaceExpectedType(expectedType)
|
||||
.replaceContextDependency(ContextDependency.INDEPENDENT)
|
||||
.replaceBindingTrace(trace)
|
||||
.replaceExpectedType(expectedType)
|
||||
.replaceContextDependency(ContextDependency.INDEPENDENT)
|
||||
|
||||
expressionTypingServices.getTypeInfo(psiCallArgument.collectionLiteralExpression, actualContext)
|
||||
}
|
||||
|
||||
@@ -49,8 +49,8 @@ fun <D : CallableDescriptor> ResolvedCall<D>.hasUnmappedParameters(): Boolean {
|
||||
return !parameterToArgumentMap.keys.containsAll(resultingDescriptor.valueParameters)
|
||||
}
|
||||
|
||||
fun <D : CallableDescriptor> ResolvedCall<D>.allArgumentsMapped()
|
||||
= call.valueArguments.all { argument -> getArgumentMapping(argument) is ArgumentMatch }
|
||||
fun <D : CallableDescriptor> ResolvedCall<D>.allArgumentsMapped() =
|
||||
call.valueArguments.all { argument -> getArgumentMapping(argument) is ArgumentMatch }
|
||||
|
||||
fun <D : CallableDescriptor> ResolvedCall<D>.hasTypeMismatchErrorOnParameter(parameter: ValueParameterDescriptor): Boolean {
|
||||
val resolvedValueArgument = valueArguments[parameter]
|
||||
@@ -73,9 +73,9 @@ fun <D : CallableDescriptor> ResolvedCall<D>.usesDefaultArguments(): Boolean {
|
||||
|
||||
// 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() }
|
||||
return arguments.any (fun (argument: KtExpression?): Boolean {
|
||||
return arguments.any(fun(argument: KtExpression?): Boolean {
|
||||
if (argument == null || ArgumentTypeResolver.isFunctionLiteralOrCallableReference(argument, context)) return false
|
||||
|
||||
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 Call.getValueArgumentListOrElement(): KtElement =
|
||||
if (this is CallTransformer.CallForImplicitInvoke) {
|
||||
outerCall.getValueArgumentListOrElement()
|
||||
}
|
||||
else {
|
||||
valueArgumentList ?: calleeExpression ?: callElement
|
||||
}
|
||||
if (this is CallTransformer.CallForImplicitInvoke) {
|
||||
outerCall.getValueArgumentListOrElement()
|
||||
} else {
|
||||
valueArgumentList ?: calleeExpression ?: callElement
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
private fun List<ValueArgument?>.filterArgsInParentheses() = filter { it !is KtLambdaArgument } as List<ValueArgument>
|
||||
@@ -111,6 +110,7 @@ fun Call.getValueArgumentForExpression(expression: KtExpression): ValueArgument?
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
fun KtElement.isParenthesizedExpression() = generateSequence(this) { it.deparenthesizeStructurally() }.any { it == expression }
|
||||
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? {
|
||||
val callExpressionTypes = arrayOf<Class<out KtElement>?>(
|
||||
KtSimpleNameExpression::class.java, KtCallElement::class.java, KtBinaryExpression::class.java,
|
||||
KtUnaryExpression::class.java, KtArrayAccessExpression::class.java)
|
||||
KtSimpleNameExpression::class.java, KtCallElement::class.java, KtBinaryExpression::class.java,
|
||||
KtUnaryExpression::class.java, KtArrayAccessExpression::class.java
|
||||
)
|
||||
|
||||
val parent = if (strict) {
|
||||
PsiTreeUtil.getParentOfType(this, *callExpressionTypes)
|
||||
@@ -248,20 +249,19 @@ fun Call.isSafeCall(): Boolean {
|
||||
fun Call.isCallableReference(): Boolean {
|
||||
val callElement = callElement
|
||||
return callElement is KtNameReferenceExpression &&
|
||||
(callElement.parent as? KtCallableReferenceExpression)?.callableReference == callElement
|
||||
(callElement.parent as? KtCallableReferenceExpression)?.callableReference == callElement
|
||||
}
|
||||
|
||||
fun Call.createLookupLocation(): KotlinLookupLocation {
|
||||
val calleeExpression = calleeExpression
|
||||
val element =
|
||||
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
|
||||
else callElement
|
||||
if (calleeExpression != null && !calleeExpression.isFakeElement) calleeExpression
|
||||
else callElement
|
||||
return KotlinLookupLocation(element)
|
||||
}
|
||||
|
||||
fun ResolvedCall<*>.getFirstArgumentExpression(): KtExpression? =
|
||||
valueArgumentsByIndex?.run { get(0).arguments[0].getArgumentExpression() }
|
||||
valueArgumentsByIndex?.run { get(0).arguments[0].getArgumentExpression() }
|
||||
|
||||
fun ResolvedCall<*>.getReceiverExpression(): KtExpression? =
|
||||
extensionReceiver.safeAs<ExpressionReceiver>()?.expression ?:
|
||||
dispatchReceiver.safeAs<ExpressionReceiver>()?.expression
|
||||
extensionReceiver.safeAs<ExpressionReceiver>()?.expression ?: dispatchReceiver.safeAs<ExpressionReceiver>()?.expression
|
||||
+5
-5
@@ -26,11 +26,11 @@ import org.jetbrains.kotlin.resolve.checkSinceKotlinVersionAccessibility
|
||||
|
||||
object ApiVersionClassifierUsageChecker : ClassifierUsageChecker {
|
||||
override fun check(
|
||||
targetDescriptor: ClassifierDescriptor,
|
||||
trace: BindingTrace,
|
||||
element: PsiElement,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
deprecationResolver: DeprecationResolver
|
||||
targetDescriptor: ClassifierDescriptor,
|
||||
trace: BindingTrace,
|
||||
element: PsiElement,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
deprecationResolver: DeprecationResolver
|
||||
) {
|
||||
targetDescriptor.checkSinceKotlinVersionAccessibility(languageVersionSettings) { version ->
|
||||
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 {
|
||||
override fun check(
|
||||
declaration: KtDeclaration,
|
||||
descriptor: DeclarationDescriptor,
|
||||
diagnosticHolder: DiagnosticSink,
|
||||
bindingContext: BindingContext
|
||||
declaration: KtDeclaration,
|
||||
descriptor: DeclarationDescriptor,
|
||||
diagnosticHolder: DiagnosticSink,
|
||||
bindingContext: BindingContext
|
||||
) {
|
||||
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 =
|
||||
checkCanBeConst(declaration, constModifierPsiElement, descriptor).canBeConst
|
||||
checkCanBeConst(declaration, constModifierPsiElement, descriptor).canBeConst
|
||||
|
||||
private fun checkCanBeConst(declaration: KtDeclaration,
|
||||
constModifierPsiElement: PsiElement,
|
||||
descriptor: VariableDescriptor): ConstApplicability {
|
||||
private fun checkCanBeConst(
|
||||
declaration: KtDeclaration,
|
||||
constModifierPsiElement: PsiElement,
|
||||
descriptor: VariableDescriptor
|
||||
): ConstApplicability {
|
||||
if (descriptor.isVar) {
|
||||
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 {
|
||||
override fun check(
|
||||
declaration: KtDeclaration,
|
||||
descriptor: DeclarationDescriptor,
|
||||
diagnosticHolder: DiagnosticSink,
|
||||
bindingContext: BindingContext,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
expectActualTracker: ExpectActualTracker
|
||||
declaration: KtDeclaration,
|
||||
descriptor: DeclarationDescriptor,
|
||||
diagnosticHolder: DiagnosticSink,
|
||||
bindingContext: BindingContext,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
expectActualTracker: ExpectActualTracker
|
||||
) {
|
||||
if (descriptor !is ClassDescriptor) return
|
||||
if (declaration !is KtClassOrObject) return
|
||||
@@ -57,21 +57,27 @@ class DelegationChecker : DeclarationChecker {
|
||||
}
|
||||
|
||||
private fun checkDescriptor(
|
||||
classDeclaration: KtClassOrObject,
|
||||
delegatedDescriptor: CallableMemberDescriptor,
|
||||
delegatedToDescriptor: CallableMemberDescriptor,
|
||||
diagnosticHolder: DiagnosticSink
|
||||
classDeclaration: KtClassOrObject,
|
||||
delegatedDescriptor: CallableMemberDescriptor,
|
||||
delegatedToDescriptor: CallableMemberDescriptor,
|
||||
diagnosticHolder: DiagnosticSink
|
||||
) {
|
||||
val reachableFromDelegated =
|
||||
OverridingUtil.filterOutOverridden(
|
||||
DescriptorUtils.getAllOverriddenDescriptors(delegatedDescriptor).filter { it.kind.isReal }.toSet()
|
||||
) - DescriptorUtils.unwrapFakeOverride(delegatedToDescriptor).original
|
||||
OverridingUtil.filterOutOverridden(
|
||||
DescriptorUtils.getAllOverriddenDescriptors(delegatedDescriptor).filter { it.kind.isReal }.toSet()
|
||||
) - DescriptorUtils.unwrapFakeOverride(delegatedToDescriptor).original
|
||||
|
||||
val nonAbstractReachable = reachableFromDelegated.filter { it.modality == Modality.OPEN }
|
||||
|
||||
if (nonAbstractReachable.isNotEmpty()) {
|
||||
/*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