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:
Dmitry Savvinov
2019-05-29 14:32:39 +03:00
parent eda975d317
commit dca23f871c
8 changed files with 146 additions and 36 deletions
@@ -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.memberScopeAsImportingScope
import org.jetbrains.kotlin.resolve.source.getPsi
import org.jetbrains.kotlin.synthetic.JavaSyntheticScopes
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
@@ -442,7 +443,7 @@ class ReferenceVariantsHelper(
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)) {
val lookupLocation = (scope.ownerDescriptor.toSourceElement.getPsi() as? KtElement)?.let { KotlinLookupLocation(it) }
?: NoLookupLocation.FROM_IDE
@@ -477,7 +478,21 @@ fun ResolutionScope.collectSyntheticStaticMembersAndConstructors(
kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean
): List<FunctionDescriptor> {
val syntheticScopes = resolutionFacade.getFrontendService(SyntheticScopes::class.java)
val syntheticScopes = resolutionFacade.getFrontendService(SyntheticScopes::class.java).forceEnableSamAdapters()
return (syntheticScopes.collectSyntheticStaticFunctions(this) + syntheticScopes.collectSyntheticConstructors(this))
.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
}
}