Allow to force-require syntetic SAM-adapters even in NI
This is needed for some IDE clients, particularly, completion: even
though presenting only non-converted member (e.g., 'foo(Consumer<Int>')
is nominally OK, as resolution with NI is smart enough to accept 'foo { }'
for such a call, it is inconvenient for users (for example, hitting
enter would insert round brackets instead of a figure brackets)
This commit adds very-very narrow API (borderline hacky) in
JavaSyntheticScopes, to allow clients explicitly ask for a scopes with
force-enabled synthetic conversions. It fixes several tests, which had
started to fail after corresponding commit about NI and SAM-adapters
(fe5976d7f4), e.g.:
- Java8BasicCompletionTestGenerated.testCollectionMethods
- Java8BasicCompletionTestGenerated.testStreamMethods
- JvmBasicCompletionTestGenerated$Common$StaticMembers.testJavaStaticMethods
- JvmBasicCompletionTestGenerated$Java.testSAMAdaptersStatic
- JvmWithLibBasicCompletionTestGenerated.testSamAdapter
- JvmWithLibBasicCompletionTestGenerated.testSamAdapterAndGenerics
Note that changes are made in ReferenceVariantsHelper, which is used by
several other clients in IDE. Presumably, those changes are needed for
them too.
This commit is contained in:
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.synthetic
|
package org.jetbrains.kotlin.synthetic
|
||||||
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
|
import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor
|
||||||
@@ -28,34 +29,61 @@ import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
|||||||
import org.jetbrains.kotlin.storage.StorageManager
|
import org.jetbrains.kotlin.storage.StorageManager
|
||||||
|
|
||||||
class JavaSyntheticScopes(
|
class JavaSyntheticScopes(
|
||||||
private val project: Project,
|
private val project: Project,
|
||||||
private val moduleDescriptor: ModuleDescriptor,
|
private val moduleDescriptor: ModuleDescriptor,
|
||||||
storageManager: StorageManager,
|
storageManager: StorageManager,
|
||||||
lookupTracker: LookupTracker,
|
lookupTracker: LookupTracker,
|
||||||
languageVersionSettings: LanguageVersionSettings,
|
languageVersionSettings: LanguageVersionSettings,
|
||||||
samConventionResolver: SamConversionResolver,
|
samConventionResolver: SamConversionResolver,
|
||||||
deprecationResolver: DeprecationResolver
|
deprecationResolver: DeprecationResolver
|
||||||
): SyntheticScopes {
|
) : SyntheticScopes {
|
||||||
override val scopes = run {
|
override val scopes: Collection<SyntheticScope>
|
||||||
val javaSyntheticPropertiesScope = JavaSyntheticPropertiesScope(storageManager, lookupTracker)
|
|
||||||
|
|
||||||
|
// New Inference disables SAM-adapters scope, because it knows how to perform SAM-conversion in resolution
|
||||||
|
// However, some outer clients (mostly in IDE) sometimes would like to look at synthetic SAM-produced descriptors
|
||||||
|
// (e.g., completion)
|
||||||
|
val scopesWithForceEnabledSamAdapters: Collection<SyntheticScope>
|
||||||
|
|
||||||
|
init {
|
||||||
|
val newInferenceEnabled = languageVersionSettings.supportsFeature(LanguageFeature.NewInference)
|
||||||
|
|
||||||
|
val javaSyntheticPropertiesScope = JavaSyntheticPropertiesScope(storageManager, lookupTracker)
|
||||||
val scopesFromExtensions = SyntheticScopeProviderExtension
|
val scopesFromExtensions = SyntheticScopeProviderExtension
|
||||||
.getInstances(project)
|
.getInstances(project)
|
||||||
.flatMap { it.getScopes(moduleDescriptor, javaSyntheticPropertiesScope) }
|
.flatMap { it.getScopes(moduleDescriptor, javaSyntheticPropertiesScope) }
|
||||||
|
|
||||||
listOf(
|
|
||||||
javaSyntheticPropertiesScope,
|
val samAdapterFunctionsScope = SamAdapterFunctionsScope(
|
||||||
SamAdapterFunctionsScope(
|
storageManager,
|
||||||
storageManager, languageVersionSettings, samConventionResolver, deprecationResolver,
|
samConventionResolver,
|
||||||
lookupTracker
|
deprecationResolver,
|
||||||
|
lookupTracker,
|
||||||
|
samViaSyntheticScopeDisabled = newInferenceEnabled
|
||||||
|
)
|
||||||
|
|
||||||
|
scopes = listOf(javaSyntheticPropertiesScope, samAdapterFunctionsScope) + scopesFromExtensions
|
||||||
|
|
||||||
|
if (newInferenceEnabled) {
|
||||||
|
val forceEnabledSamAdapterFunctionsScope = SamAdapterFunctionsScope(
|
||||||
|
storageManager,
|
||||||
|
samConventionResolver,
|
||||||
|
deprecationResolver,
|
||||||
|
lookupTracker,
|
||||||
|
samViaSyntheticScopeDisabled = false
|
||||||
)
|
)
|
||||||
) + scopesFromExtensions
|
|
||||||
|
scopesWithForceEnabledSamAdapters =
|
||||||
|
listOf(javaSyntheticPropertiesScope, forceEnabledSamAdapterFunctionsScope) + scopesFromExtensions
|
||||||
|
} else {
|
||||||
|
scopesWithForceEnabledSamAdapters = scopes
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SyntheticScopeProviderExtension {
|
interface SyntheticScopeProviderExtension {
|
||||||
companion object : ProjectExtensionDescriptor<SyntheticScopeProviderExtension>(
|
companion object : ProjectExtensionDescriptor<SyntheticScopeProviderExtension>(
|
||||||
"org.jetbrains.kotlin.syntheticScopeProviderExtension", SyntheticScopeProviderExtension::class.java)
|
"org.jetbrains.kotlin.syntheticScopeProviderExtension", SyntheticScopeProviderExtension::class.java
|
||||||
|
)
|
||||||
|
|
||||||
fun getScopes(moduleDescriptor: ModuleDescriptor, javaSyntheticPropertiesScope: JavaSyntheticPropertiesScope): List<SyntheticScope>
|
fun getScopes(moduleDescriptor: ModuleDescriptor, javaSyntheticPropertiesScope: JavaSyntheticPropertiesScope): List<SyntheticScope>
|
||||||
}
|
}
|
||||||
+2
-3
@@ -55,12 +55,11 @@ val SAM_LOOKUP_NAME = Name.special("<SAM-CONSTRUCTOR>")
|
|||||||
|
|
||||||
class SamAdapterFunctionsScope(
|
class SamAdapterFunctionsScope(
|
||||||
storageManager: StorageManager,
|
storageManager: StorageManager,
|
||||||
private val languageVersionSettings: LanguageVersionSettings,
|
|
||||||
private val samResolver: SamConversionResolver,
|
private val samResolver: SamConversionResolver,
|
||||||
private val deprecationResolver: DeprecationResolver,
|
private val deprecationResolver: DeprecationResolver,
|
||||||
private val lookupTracker: LookupTracker
|
private val lookupTracker: LookupTracker,
|
||||||
|
private val samViaSyntheticScopeDisabled: Boolean
|
||||||
) : SyntheticScope.Default() {
|
) : SyntheticScope.Default() {
|
||||||
private val samViaSyntheticScopeDisabled = languageVersionSettings.supportsFeature(LanguageFeature.NewInference)
|
|
||||||
|
|
||||||
private val extensionForFunction =
|
private val extensionForFunction =
|
||||||
storageManager.createMemoizedFunctionWithNullableValues<FunctionDescriptor, FunctionDescriptor> { function ->
|
storageManager.createMemoizedFunctionWithNullableValues<FunctionDescriptor, FunctionDescriptor> { function ->
|
||||||
|
|||||||
@@ -17,8 +17,14 @@
|
|||||||
package org.jetbrains.kotlin.synthetic
|
package org.jetbrains.kotlin.synthetic
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.synthetic.SyntheticMemberDescriptor
|
||||||
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
|
import org.jetbrains.kotlin.load.java.descriptors.JavaCallableMemberDescriptor
|
||||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.load.java.sam.SamAdapterDescriptor
|
||||||
|
import org.jetbrains.kotlin.load.java.sam.SamConstructorDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCallImpl
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl
|
||||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
import org.jetbrains.kotlin.resolve.scopes.receivers.ReceiverValue
|
||||||
|
|
||||||
fun FunctionDescriptor.hasJavaOriginInHierarchy(): Boolean {
|
fun FunctionDescriptor.hasJavaOriginInHierarchy(): Boolean {
|
||||||
@@ -55,3 +61,15 @@ fun syntheticVisibility(originalDescriptor: DeclarationDescriptorWithVisibility,
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun <D : CallableDescriptor> ResolvedCall<D>.isResolvedWithSamConversions(): Boolean {
|
||||||
|
return if (this is NewResolvedCallImpl<D>) {
|
||||||
|
// New inference
|
||||||
|
this.resolvedCallAtom.argumentsWithConversion.isNotEmpty()
|
||||||
|
} else {
|
||||||
|
// Old Inference
|
||||||
|
this.resultingDescriptor is SamAdapterDescriptor<*> ||
|
||||||
|
this.resultingDescriptor is SamConstructorDescriptor ||
|
||||||
|
this.resultingDescriptor is SamAdapterExtensionFunctionDescriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
+17
-2
@@ -44,6 +44,7 @@ import org.jetbrains.kotlin.resolve.scopes.utils.collectAllFromMeAndParent
|
|||||||
import org.jetbrains.kotlin.resolve.scopes.utils.collectDescriptorsFiltered
|
import org.jetbrains.kotlin.resolve.scopes.utils.collectDescriptorsFiltered
|
||||||
import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
|
import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
|
||||||
import org.jetbrains.kotlin.resolve.source.getPsi
|
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||||
|
import org.jetbrains.kotlin.synthetic.JavaSyntheticScopes
|
||||||
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||||
@@ -442,7 +443,7 @@ class ReferenceVariantsHelper(
|
|||||||
process(descriptor as CallableDescriptor)
|
process(descriptor as CallableDescriptor)
|
||||||
}
|
}
|
||||||
|
|
||||||
val syntheticScopes = resolutionFacade.getFrontendService(SyntheticScopes::class.java)
|
val syntheticScopes = resolutionFacade.getFrontendService(SyntheticScopes::class.java).forceEnableSamAdapters()
|
||||||
if (kindFilter.acceptsKinds(DescriptorKindFilter.VARIABLES_MASK)) {
|
if (kindFilter.acceptsKinds(DescriptorKindFilter.VARIABLES_MASK)) {
|
||||||
val lookupLocation = (scope.ownerDescriptor.toSourceElement.getPsi() as? KtElement)?.let { KotlinLookupLocation(it) }
|
val lookupLocation = (scope.ownerDescriptor.toSourceElement.getPsi() as? KtElement)?.let { KotlinLookupLocation(it) }
|
||||||
?: NoLookupLocation.FROM_IDE
|
?: NoLookupLocation.FROM_IDE
|
||||||
@@ -477,7 +478,21 @@ fun ResolutionScope.collectSyntheticStaticMembersAndConstructors(
|
|||||||
kindFilter: DescriptorKindFilter,
|
kindFilter: DescriptorKindFilter,
|
||||||
nameFilter: (Name) -> Boolean
|
nameFilter: (Name) -> Boolean
|
||||||
): List<FunctionDescriptor> {
|
): List<FunctionDescriptor> {
|
||||||
val syntheticScopes = resolutionFacade.getFrontendService(SyntheticScopes::class.java)
|
val syntheticScopes = resolutionFacade.getFrontendService(SyntheticScopes::class.java).forceEnableSamAdapters()
|
||||||
return (syntheticScopes.collectSyntheticStaticFunctions(this) + syntheticScopes.collectSyntheticConstructors(this))
|
return (syntheticScopes.collectSyntheticStaticFunctions(this) + syntheticScopes.collectSyntheticConstructors(this))
|
||||||
.filter { kindFilter.accepts(it) && nameFilter(it.name) }
|
.filter { kindFilter.accepts(it) && nameFilter(it.name) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// New Inference disables scope with synthetic SAM-adapters because it uses conversions for resolution
|
||||||
|
// However, sometimes we need to pretend that we have those synthetic members, for example:
|
||||||
|
// - to show both option (with SAM-conversion signature, and without) in completion
|
||||||
|
// - for various intentions and checks (see RedundantSamConstructorInspection, ConflictingExtensionPropertyIntention and other)
|
||||||
|
// TODO(dsavvinov): review clients, rewrite them to not rely on synthetic adapetrs
|
||||||
|
fun SyntheticScopes.forceEnableSamAdapters(): SyntheticScopes {
|
||||||
|
return if (this !is JavaSyntheticScopes)
|
||||||
|
this
|
||||||
|
else
|
||||||
|
object : SyntheticScopes {
|
||||||
|
override val scopes: Collection<SyntheticScope> = this@forceEnableSamAdapters.scopesWithForceEnabledSamAdapters
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference
|
|||||||
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
|
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMemberDescriptor
|
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMemberDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.util.resolveToDescriptor
|
import org.jetbrains.kotlin.idea.caches.resolve.util.resolveToDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.codeInsight.forceEnableSamAdapters
|
||||||
import org.jetbrains.kotlin.idea.core.extension.KotlinIndicesHelperExtension
|
import org.jetbrains.kotlin.idea.core.extension.KotlinIndicesHelperExtension
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.resolve.frontendService
|
import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||||
@@ -466,7 +467,7 @@ class KotlinIndicesHelper(
|
|||||||
processor(descriptor)
|
processor(descriptor)
|
||||||
|
|
||||||
// SAM-adapter
|
// SAM-adapter
|
||||||
val syntheticScopes = resolutionFacade.getFrontendService(SyntheticScopes::class.java)
|
val syntheticScopes = resolutionFacade.getFrontendService(SyntheticScopes::class.java).forceEnableSamAdapters()
|
||||||
syntheticScopes.collectSyntheticStaticFunctions(container.staticScope, descriptor.name, NoLookupLocation.FROM_IDE)
|
syntheticScopes.collectSyntheticStaticFunctions(container.staticScope, descriptor.name, NoLookupLocation.FROM_IDE)
|
||||||
.filterIsInstance<SamAdapterDescriptor<*>>()
|
.filterIsInstance<SamAdapterDescriptor<*>>()
|
||||||
.firstOrNull { it.baseDescriptorForSynthetic.original == descriptor.original }
|
.firstOrNull { it.baseDescriptorForSynthetic.original == descriptor.original }
|
||||||
|
|||||||
@@ -22,11 +22,15 @@ import com.intellij.psi.impl.source.codeStyle.CodeEditUtil
|
|||||||
import com.intellij.psi.tree.IElementType
|
import com.intellij.psi.tree.IElementType
|
||||||
import com.intellij.psi.util.PsiTreeUtil
|
import com.intellij.psi.util.PsiTreeUtil
|
||||||
import org.jetbrains.kotlin.builtins.isFunctionOrSuspendFunctionType
|
import org.jetbrains.kotlin.builtins.isFunctionOrSuspendFunctionType
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension
|
import org.jetbrains.kotlin.extensions.DeclarationAttributeAltererExtension
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||||
import org.jetbrains.kotlin.idea.references.mainReference
|
import org.jetbrains.kotlin.idea.references.mainReference
|
||||||
|
import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.idea.util.hasJvmFieldAnnotation
|
import org.jetbrains.kotlin.idea.util.hasJvmFieldAnnotation
|
||||||
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
|
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
|
||||||
@@ -41,6 +45,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
|||||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentsInParentheses
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getValueArgumentsInParentheses
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.components.SamConversionTransformer
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.types.KotlinType
|
import org.jetbrains.kotlin.types.KotlinType
|
||||||
@@ -131,25 +136,61 @@ fun KtCallExpression.canMoveLambdaOutsideParentheses(): Boolean {
|
|||||||
if (callee is KtNameReferenceExpression) {
|
if (callee is KtNameReferenceExpression) {
|
||||||
val lambdaArgumentCount = valueArguments.count { it.getArgumentExpression()?.unpackFunctionLiteral() != null }
|
val lambdaArgumentCount = valueArguments.count { it.getArgumentExpression()?.unpackFunctionLiteral() != null }
|
||||||
val referenceArgumentCount = valueArguments.count { it.getArgumentExpression() is KtCallableReferenceExpression }
|
val referenceArgumentCount = valueArguments.count { it.getArgumentExpression() is KtCallableReferenceExpression }
|
||||||
val bindingContext = analyze(BodyResolveMode.PARTIAL)
|
|
||||||
|
val resolutionFacade = getResolutionFacade()
|
||||||
|
val samConversionTransformer = resolutionFacade.frontendService<SamConversionTransformer>()
|
||||||
|
val languageVersionSettings = resolutionFacade.frontendService<LanguageVersionSettings>()
|
||||||
|
|
||||||
|
val bindingContext = analyze(resolutionFacade, BodyResolveMode.PARTIAL)
|
||||||
val targets = bindingContext[BindingContext.REFERENCE_TARGET, callee]?.let { listOf(it) }
|
val targets = bindingContext[BindingContext.REFERENCE_TARGET, callee]?.let { listOf(it) }
|
||||||
?: bindingContext[BindingContext.AMBIGUOUS_REFERENCE_TARGET, callee]
|
?: bindingContext[BindingContext.AMBIGUOUS_REFERENCE_TARGET, callee]
|
||||||
?: listOf()
|
?: listOf()
|
||||||
|
|
||||||
val candidates = targets.filterIsInstance<FunctionDescriptor>()
|
val candidates = targets.filterIsInstance<FunctionDescriptor>()
|
||||||
|
|
||||||
// if there are functions among candidates but none of them have last function parameter then not show the intention
|
// if there are functions among candidates but none of them have last function parameter then not show the intention
|
||||||
if (candidates.isNotEmpty() && candidates.none { candidate ->
|
val areAllCandidatesWithoutLastFunctionParameter = candidates.none {
|
||||||
val params = candidate.valueParameters
|
it.allowsMoveOfLastParameterOutsideParentheses(
|
||||||
val lastParamType = params.lastOrNull()?.type
|
lambdaArgumentCount + referenceArgumentCount,
|
||||||
(lastParamType?.isFunctionOrSuspendFunctionType == true || lastParamType?.isTypeParameter() == true) && params.count {
|
samConversionTransformer,
|
||||||
it.type.let { type -> type.isFunctionOrSuspendFunctionType || type.isTypeParameter() }
|
languageVersionSettings.supportsFeature(LanguageFeature.NewInference)
|
||||||
} == lambdaArgumentCount + referenceArgumentCount
|
)
|
||||||
}
|
}
|
||||||
) return false
|
|
||||||
|
if (candidates.isNotEmpty() && areAllCandidatesWithoutLastFunctionParameter) return false
|
||||||
}
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun FunctionDescriptor.allowsMoveOfLastParameterOutsideParentheses(
|
||||||
|
lambdaAndCallableReferencesInOriginalCallCount: Int,
|
||||||
|
samConversionTransformer: SamConversionTransformer,
|
||||||
|
newInferenceEnabled: Boolean
|
||||||
|
): Boolean {
|
||||||
|
fun KotlinType.allowsMoveOutsideParentheses(): Boolean {
|
||||||
|
// Fast-path
|
||||||
|
if (isFunctionOrSuspendFunctionType || isTypeParameter()) return true
|
||||||
|
|
||||||
|
// Also check if it can be SAM-converted
|
||||||
|
// Note that it is not necessary in OI, where we provide synthetic candidate descriptors with already
|
||||||
|
// converted types, but in NI it is performed by conversions, so we check it explicitly
|
||||||
|
// Also note that 'newInferenceEnabled' is essentially a micro-optimization, as there are no
|
||||||
|
// harm in just calling 'samConversionTransformer' on all candidates.
|
||||||
|
return newInferenceEnabled && samConversionTransformer.getFunctionTypeForPossibleSamType(this.unwrap()) != null
|
||||||
|
}
|
||||||
|
|
||||||
|
val params = valueParameters
|
||||||
|
val lastParamType = params.lastOrNull()?.type ?: return false
|
||||||
|
|
||||||
|
if (!lastParamType.allowsMoveOutsideParentheses()) return false
|
||||||
|
|
||||||
|
val movableParametersOfCandidateCount = params.count { it.type.allowsMoveOutsideParentheses() }
|
||||||
|
return movableParametersOfCandidateCount == lambdaAndCallableReferencesInOriginalCallCount
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
fun KtCallExpression.moveFunctionLiteralOutsideParentheses() {
|
fun KtCallExpression.moveFunctionLiteralOutsideParentheses() {
|
||||||
assert(lambdaArguments.isEmpty())
|
assert(lambdaArguments.isEmpty())
|
||||||
val argumentList = valueArgumentList!!
|
val argumentList = valueArgumentList!!
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
|||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getType
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.synthetic.SamAdapterExtensionFunctionDescriptor
|
import org.jetbrains.kotlin.synthetic.isResolvedWithSamConversions
|
||||||
|
|
||||||
class JavaMapForEachInspection : AbstractApplicabilityBasedInspection<KtDotQualifiedExpression>(
|
class JavaMapForEachInspection : AbstractApplicabilityBasedInspection<KtDotQualifiedExpression>(
|
||||||
KtDotQualifiedExpression::class.java
|
KtDotQualifiedExpression::class.java
|
||||||
@@ -37,7 +37,8 @@ class JavaMapForEachInspection : AbstractApplicabilityBasedInspection<KtDotQuali
|
|||||||
|
|
||||||
val context = element.analyze(BodyResolveMode.PARTIAL)
|
val context = element.analyze(BodyResolveMode.PARTIAL)
|
||||||
if (!element.receiverExpression.getType(context).isMap(DefaultBuiltIns.Instance)) return false
|
if (!element.receiverExpression.getType(context).isMap(DefaultBuiltIns.Instance)) return false
|
||||||
return callExpression.getResolvedCall(context)?.resultingDescriptor is SamAdapterExtensionFunctionDescriptor
|
val resolvedCall = callExpression.getResolvedCall(context) ?: return false
|
||||||
|
return resolvedCall.isResolvedWithSamConversions()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun inspectionTarget(element: KtDotQualifiedExpression) = element.callExpression?.calleeExpression ?: element
|
override fun inspectionTarget(element: KtDotQualifiedExpression) = element.callExpression?.calleeExpression ?: element
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
|||||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
||||||
|
import org.jetbrains.kotlin.idea.codeInsight.forceEnableSamAdapters
|
||||||
import org.jetbrains.kotlin.idea.resolve.frontendService
|
import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
@@ -32,6 +33,7 @@ import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
|
|||||||
import org.jetbrains.kotlin.resolve.calls.CallResolver
|
import org.jetbrains.kotlin.resolve.calls.CallResolver
|
||||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||||
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
|
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
|
||||||
|
import org.jetbrains.kotlin.resolve.calls.tower.NewResolvedCallImpl
|
||||||
import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall
|
import org.jetbrains.kotlin.resolve.calls.util.DelegatingCall
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
||||||
@@ -128,7 +130,12 @@ class RedundantSamConstructorInspection : AbstractKotlinInspection() {
|
|||||||
|
|
||||||
if (!resolutionResults.isSuccess) return false
|
if (!resolutionResults.isSuccess) return false
|
||||||
|
|
||||||
val samAdapterOriginalDescriptor = SamCodegenUtil.getOriginalIfSamAdapter(resolutionResults.resultingDescriptor) ?: return false
|
val samAdapterOriginalDescriptor =
|
||||||
|
if (resolutionResults.resultingCall is NewResolvedCallImpl<*>)
|
||||||
|
resolutionResults.resultingDescriptor
|
||||||
|
else
|
||||||
|
SamCodegenUtil.getOriginalIfSamAdapter(resolutionResults.resultingDescriptor) ?: return false
|
||||||
|
|
||||||
return samAdapterOriginalDescriptor.original == originalCall.resultingDescriptor.original
|
return samAdapterOriginalDescriptor.original == originalCall.resultingDescriptor.original
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -176,7 +183,7 @@ class RedundantSamConstructorInspection : AbstractKotlinInspection() {
|
|||||||
val originalFunctionDescriptor = functionResolvedCall.resultingDescriptor.original as? FunctionDescriptor ?: return emptyList()
|
val originalFunctionDescriptor = functionResolvedCall.resultingDescriptor.original as? FunctionDescriptor ?: return emptyList()
|
||||||
val containingClass = originalFunctionDescriptor.containingDeclaration as? ClassDescriptor ?: return emptyList()
|
val containingClass = originalFunctionDescriptor.containingDeclaration as? ClassDescriptor ?: return emptyList()
|
||||||
|
|
||||||
val syntheticScopes = functionCall.getResolutionFacade().getFrontendService(SyntheticScopes::class.java)
|
val syntheticScopes = functionCall.getResolutionFacade().getFrontendService(SyntheticScopes::class.java).forceEnableSamAdapters()
|
||||||
|
|
||||||
// SAM adapters for static functions
|
// SAM adapters for static functions
|
||||||
val contributedFunctions = syntheticScopes.collectSyntheticStaticFunctions(containingClass.staticScope)
|
val contributedFunctions = syntheticScopes.collectSyntheticStaticFunctions(containingClass.staticScope)
|
||||||
|
|||||||
Reference in New Issue
Block a user