KT-15092 Suppress inspection "use property access syntax" for some getters and fix completion for them

#KT-15092 fixed
This commit is contained in:
Simon Ogorodnik
2016-12-20 20:39:06 +03:00
parent c1538aea43
commit 0cf02dcb7b
17 changed files with 434 additions and 13 deletions
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtExpression
@@ -49,7 +50,8 @@ class ReferenceVariantsHelper(
private val bindingContext: BindingContext,
private val resolutionFacade: ResolutionFacade,
private val moduleDescriptor: ModuleDescriptor,
private val visibilityFilter: (DeclarationDescriptor) -> Boolean
private val visibilityFilter: (DeclarationDescriptor) -> Boolean,
private val notProperties: Set<FqNameUnsafe> = setOf()
) {
fun getReferenceVariants(
expression: KtSimpleNameExpression,
@@ -96,7 +98,9 @@ class ReferenceVariantsHelper(
fun filterOutJavaGettersAndSetters(variants: Collection<DeclarationDescriptor>): Collection<DeclarationDescriptor> {
val accessorMethodsToRemove = HashSet<FunctionDescriptor>()
for (variant in variants) {
val filteredVariants = variants.filter { it !is SyntheticJavaPropertyDescriptor || !it.suppressedByNotPropertyList(notProperties) }
for (variant in filteredVariants) {
if (variant is SyntheticJavaPropertyDescriptor) {
accessorMethodsToRemove.add(variant.getMethod.original)
@@ -107,7 +111,7 @@ class ReferenceVariantsHelper(
}
}
return variants.filter { it !is FunctionDescriptor || it.original !in accessorMethodsToRemove }
return filteredVariants.filter { it !is FunctionDescriptor || it.original !in accessorMethodsToRemove }
}
// filters out variable inside its initializer
@@ -0,0 +1,32 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.util
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.descriptorUtil.overriddenTreeUniqueAsSequence
import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
fun FunctionDescriptor.shouldNotConvertToProperty(notProperties: Set<FqNameUnsafe>): Boolean {
if (fqNameUnsafe in notProperties) return true
return this.overriddenTreeUniqueAsSequence(false).any { fqNameUnsafe in notProperties }
}
fun SyntheticJavaPropertyDescriptor.suppressedByNotPropertyList(set: Set<FqNameUnsafe>) =
getMethod.shouldNotConvertToProperty(set) || setMethod?.shouldNotConvertToProperty(set) ?: false
+1 -1
View File
@@ -15,7 +15,7 @@
<orderEntry type="library" scope="PROVIDED" name="java-i18n" level="project" />
<orderEntry type="library" scope="PROVIDED" name="gradle-and-groovy-plugin" level="project" />
<orderEntry type="module" module-name="eval4j" />
<orderEntry type="library" name="intellij-core-analysis" level="project" />
<orderEntry type="library" exported="" name="intellij-core-analysis" level="project" />
<orderEntry type="module-library">
<library>
<CLASSES>
@@ -78,7 +78,9 @@ abstract class IntentionBasedInspection<TElement : PsiElement>(
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
val intentionsAndCheckers = intentionInfos.map {
it.intention.constructors.single().call() to it.additionalChecker
val instance = it.intention.constructors.single().call()
instance.inspection = this
instance to it.additionalChecker
}
val elementType = intentionsAndCheckers.map { it.first.elementType }.distinct().singleOrNull()
?: error("$intentionInfos should have the same elementType")
@@ -105,7 +107,7 @@ abstract class IntentionBasedInspection<TElement : PsiElement>(
if (fixes == null) {
fixes = SmartList<LocalQuickFix>()
}
fixes!!.add(createQuickFix(intention, additionalChecker, targetElement))
fixes.add(createQuickFix(intention, additionalChecker, targetElement))
}
}
@@ -91,8 +91,11 @@ abstract class SelfTargetingIntention<TElement : PsiElement>(
return !isIntentionBaseInspectionEnabled(project, target)
}
var inspection: IntentionBasedInspection<TElement>? = null
internal set
protected fun isIntentionBaseInspectionEnabled(project: Project, target: TElement): Boolean {
val inspection = findInspection(this.javaClass.kotlin) ?: return false
val inspection = inspection ?: findInspection(this.javaClass.kotlin) ?: return false
val key = HighlightDisplayKey.find(inspection.shortName)
if (!InspectionProjectProfileManager.getInstance(project).inspectionProfile.isToolEnabled(key, target)) {
@@ -123,7 +123,11 @@ abstract class CompletionSession(
protected val isVisibleFilter: (DeclarationDescriptor) -> Boolean = { isVisibleDescriptor(it, completeNonAccessible = configuration.nonAccessibleDeclarations) }
protected val isVisibleFilterCheckAlways: (DeclarationDescriptor) -> Boolean = { isVisibleDescriptor(it, completeNonAccessible = false) }
protected val referenceVariantsHelper = ReferenceVariantsHelper(bindingContext, resolutionFacade, moduleDescriptor, isVisibleFilter)
protected val referenceVariantsHelper = ReferenceVariantsHelper(bindingContext,
resolutionFacade,
moduleDescriptor,
isVisibleFilter,
NotPropertiesService.getNotProperties(position))
protected val callTypeAndReceiver: CallTypeAndReceiver<*, *>
protected val receiverTypes: Collection<ReceiverType>?
@@ -0,0 +1,9 @@
import java.net.Socket
fun main(args: Array<String>) {
val s = Socket()
s.<caret>
}
// EXIST: {"lookupString":"getInputStream","tailText":"()","typeText":"InputStream!","attributes":"bold","allLookupStrings":"getInputStream","itemText":"getInputStream"}
// ABSENT: inputStream
@@ -2917,6 +2917,12 @@ public class JvmBasicCompletionTestGenerated extends AbstractJvmBasicCompletionT
doTest(fileName);
}
@TestMetadata("SuppressedByNotPropertyList.kt")
public void testSuppressedByNotPropertyList() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/java/syntheticExtensions/SuppressedByNotPropertyList.kt");
doTest(fileName);
}
@TestMetadata("SyntheticExtensions1.kt")
public void testSyntheticExtensions1() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/basic/java/syntheticExtensions/SyntheticExtensions1.kt");
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.core
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.name.FqNameUnsafe
interface NotPropertiesService {
fun getNotProperties(element: PsiElement): Set<FqNameUnsafe>
companion object {
fun getInstance(project: Project): NotPropertiesService {
return ServiceManager.getService(project, NotPropertiesService::class.java)
}
fun getNotProperties(element: PsiElement) =
getInstance(element.project).getNotProperties(element)
}
}
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper
import org.jetbrains.kotlin.idea.completion.BasicLookupElementFactory
import org.jetbrains.kotlin.idea.completion.InsertHandlerProvider
import org.jetbrains.kotlin.idea.core.NotPropertiesService
import org.jetbrains.kotlin.idea.core.isVisible
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver
@@ -60,7 +61,7 @@ abstract class BaseKotlinVariableMacro<TState> : Macro() {
val state = initState(contextElement, bindingContext)
val helper = ReferenceVariantsHelper(bindingContext, resolutionFacade, resolutionFacade.moduleDescriptor, ::isVisible)
val helper = ReferenceVariantsHelper(bindingContext, resolutionFacade, resolutionFacade.moduleDescriptor, ::isVisible, NotPropertiesService.getNotProperties(contextElement))
return helper
.getReferenceVariants(contextElement, CallTypeAndReceiver.DEFAULT, DescriptorKindFilter.VARIABLES, { true })
.map { it as VariableDescriptor }
+9
View File
@@ -119,6 +119,11 @@
<add-to-group group-id="KotlinToolsGroup" anchor="last"/>
</action>
<action id="PrintOutNotPropertyMatches" class="org.jetbrains.kotlin.idea.actions.internal.SearchNotPropertyCandidatesAction"
text="Search Not Property Candidates">
<add-to-group group-id="KotlinToolsGroup" anchor="last"/>
</action>
<action id="FindImplicitNothingAction" class="org.jetbrains.kotlin.idea.actions.internal.FindImplicitNothingAction"
text="Find Implicit Nothing Calls">
<add-to-group group-id="KotlinToolsGroup" anchor="last"/>
@@ -306,6 +311,9 @@
<projectService serviceInterface="org.jetbrains.kotlin.config.KotlinFacetSettingsProvider"
serviceImplementation="org.jetbrains.kotlin.idea.facet.KotlinFacetSettingsProviderImpl"/>
<projectService serviceInterface="org.jetbrains.kotlin.idea.core.NotPropertiesService"
serviceImplementation="org.jetbrains.kotlin.idea.intentions.NotPropertiesServiceImpl"/>
<errorHandler implementation="org.jetbrains.kotlin.idea.reporter.KotlinReportSubmitter"/>
<internalFileTemplate name="Kotlin File"/>
@@ -1612,6 +1620,7 @@
<localInspection implementationClass="org.jetbrains.kotlin.idea.intentions.UsePropertyAccessSyntaxInspection"
displayName="Accessor call that can be replaced with property access syntax"
shortName="UsePropertyAccessSyntax"
groupName="Kotlin"
cleanupTool="true"
enabledByDefault="true"
@@ -0,0 +1,167 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.actions.internal
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.progress.ProgressManager.progress
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiModifier
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.util.application.runReadAction
import org.jetbrains.kotlin.load.java.isFromJava
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
class SearchNotPropertyCandidatesAction : AnAction() {
override fun actionPerformed(e: AnActionEvent?) {
val project = e?.project!!
val psiFile = e.getData(CommonDataKeys.PSI_FILE) as? KtFile ?: return
val desc = psiFile.findModuleDescriptor()
val result = Messages.showInputDialog("Enter package FqName", "Search for Not Property candidates", Messages.getQuestionIcon())
val packageDesc = try {
val fqName = FqName.fromSegments(result!!.split('.'))
desc.getPackage(fqName)
}
catch (e: Exception) {
return
}
ProgressManager.getInstance().runProcessWithProgressSynchronously(
{
runReadAction {
ProgressManager.getInstance().progressIndicator.isIndeterminate = true
processAllDescriptors(packageDesc, project)
}
},
"Searching for Not Property candidates",
true,
project)
}
fun processAllDescriptors(desc: DeclarationDescriptor, project: Project) {
val processed = mutableSetOf<DeclarationDescriptor>()
var pFunctions = 0
val matchedDescriptors = mutableSetOf<FunctionDescriptor>()
fun recursive(desc: DeclarationDescriptor) {
if (desc in processed) return
progress("Step 1: Collecting ${processed.size}:$pFunctions:${matchedDescriptors.size}", "$desc")
when (desc) {
is ModuleDescriptor -> recursive(desc.getPackage(FqName("java")))
is ClassDescriptor -> desc.unsubstitutedMemberScope.getContributedDescriptors { true }.forEach(::recursive)
is PackageViewDescriptor -> desc.memberScope.getContributedDescriptors { true }.forEach(::recursive)
is FunctionDescriptor -> {
if (desc.isFromJava) {
val name = desc.fqNameUnsafe.shortName().asString()
if (name.length > 3 &&
((name.startsWith("get") && desc.valueParameters.isEmpty() && desc.returnType != null) ||
(name.startsWith("set") && desc.valueParameters.size == 1))) {
if (desc in matchedDescriptors) return
matchedDescriptors += desc
}
}
pFunctions++
return
}
}
processed += desc
}
recursive(desc)
val resultDescriptors = mutableSetOf<FunctionDescriptor>()
matchedDescriptors.flatMapTo(resultDescriptors) {
sequenceOf(it, *(it.overriddenDescriptors.toTypedArray())).asIterable()
}
println("Found ${resultDescriptors.size} accessors")
fun PsiMethod.isTrivial(): Boolean {
val t = this.text
val s = t.indexOf('{')
val e = t.lastIndexOf('}')
if (s != e && s != -1) {
return t.substring(s, e).lines().size <= 3
}
else return true
}
val descriptorToPsiBinding = mutableMapOf<FunctionDescriptor, PsiMethod>()
var i = 0
resultDescriptors.forEach { desc ->
progress("Step 2: ${i++} of ${resultDescriptors.size}", "$desc")
val source = DescriptorToSourceUtilsIde.getAllDeclarations(project, desc)
.filterIsInstance<PsiMethod>()
.firstOrNull() ?: return@forEach
val abstract = source.modifierList.hasModifierProperty(PsiModifier.ABSTRACT)
if (!abstract) {
if (!source.isTrivial()) {
descriptorToPsiBinding[desc] = source
}
}
}
val nonTrivial = mutableSetOf<FunctionDescriptor>()
i = 0
descriptorToPsiBinding.forEach { t, u ->
progress("Step 3: ${i++} of ${descriptorToPsiBinding.size}", "$t")
val descriptors = t.overriddenDescriptors
var impl = false
descriptors.forEach {
val source = DescriptorToSourceUtilsIde.getAllDeclarations(project, it).filterIsInstance<PsiMethod>().firstOrNull()
if (source != null) {
if (source.body != null || source.hasModifierProperty(PsiModifier.ABSTRACT))
nonTrivial += it
impl = true
}
}
if (u.body != null)
if (!impl)
nonTrivial += t
}
nonTrivial.forEach(::println)
println("Non trivial count: ${nonTrivial.size}")
}
override fun update(e: AnActionEvent) {
if (!KotlinInternalMode.enabled) {
e.presentation.isVisible = false
e.presentation.isEnabled = false
}
else {
e.presentation.isVisible = true
e.presentation.isEnabled = e.getData(CommonDataKeys.PSI_FILE) is KtFile
}
}
}
@@ -0,0 +1,73 @@
/*
* Copyright 2010-2016 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.idea.configuration.ui
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.ui.NonEmptyInputValidator
import com.intellij.ui.AddEditRemovePanel
import org.jetbrains.kotlin.name.FqNameUnsafe
class NotPropertyListPanel(data: List<FqNameUnsafe>) : AddEditRemovePanel<FqNameUnsafe>(MyTableModel(), data) {
var modified = false
override fun removeItem(fqName: FqNameUnsafe): Boolean {
modified = true
return true
}
override fun editItem(fqName: FqNameUnsafe): FqNameUnsafe? {
val result = Messages.showInputDialog(this, "Enter fully-qualified method name:",
"Edit exclusion",
Messages.getQuestionIcon(),
fqName.asString(),
NonEmptyInputValidator()
) ?: return null
val created = FqNameUnsafe(result)
if (created in data)
return null
modified = true
return created
}
override fun addItem(): FqNameUnsafe? {
val result = Messages.showInputDialog(this, "Enter fully-qualified method name:",
"Add exclusion",
Messages.getQuestionIcon(),
"",
NonEmptyInputValidator()
) ?: return null
val created = FqNameUnsafe(result)
if (created in data)
return null
modified = true
return created
}
class MyTableModel : AddEditRemovePanel.TableModel<FqNameUnsafe>() {
override fun getField(o: FqNameUnsafe, columnIndex: Int) = o.asString()
override fun getColumnName(columnIndex: Int) = "Method"
override fun getColumnCount() = 1
}
}
@@ -18,17 +18,26 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.codeInspection.CleanupLocalInspectionTool
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.LabeledComponent
import com.intellij.openapi.util.Key
import com.intellij.profile.codeInspection.InspectionProjectProfileManager
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.descriptors.CallableDescriptor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.configuration.ui.NotPropertyListPanel
import org.jetbrains.kotlin.idea.core.NotPropertiesService
import org.jetbrains.kotlin.idea.core.copied
import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.idea.util.shouldNotConvertToProperty
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
@@ -36,7 +45,6 @@ import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis
import org.jetbrains.kotlin.renderer.render
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoAfter
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsExpression
import org.jetbrains.kotlin.resolve.calls.CallResolver
@@ -55,8 +63,54 @@ import org.jetbrains.kotlin.synthetic.SyntheticJavaPropertyDescriptor
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isUnit
import javax.swing.JComponent
class UsePropertyAccessSyntaxInspection : IntentionBasedInspection<KtCallExpression>(UsePropertyAccessSyntaxIntention::class), CleanupLocalInspectionTool
class UsePropertyAccessSyntaxInspection : IntentionBasedInspection<KtCallExpression>(UsePropertyAccessSyntaxIntention::class), CleanupLocalInspectionTool {
val fqNameList = mutableListOf<FqNameUnsafe>()
var fqNameStrings: List<String>
get() = fqNameList.map { it.asString() }
set(value) {
fqNameList.clear()
value.mapTo(fqNameList, ::FqNameUnsafe)
}
init {
fqNameStrings = NotPropertiesServiceImpl.default
}
override fun createOptionsPanel(): JComponent? {
val list = NotPropertyListPanel(fqNameList)
return LabeledComponent.create(list, "Excluded methods")
}
}
class NotPropertiesServiceImpl(private val project: Project) : NotPropertiesService {
override fun getNotProperties(element: PsiElement): Set<FqNameUnsafe> {
val profile = InspectionProjectProfileManager.getInstance(project).inspectionProfile
val tool = profile.getUnwrappedTool(USE_PROPERTY_ACCESS_INSPECTION, element)
return (tool?.fqNameList ?: default.map(::FqNameUnsafe)).toSet()
}
companion object {
val default = listOf(
"java.net.Socket.getInputStream",
"java.net.Socket.getOutputStream",
"java.net.URLConnection.getInputStream",
"java.net.URLConnection.getOutputStream",
"java.util.concurrent.atomic.AtomicInteger.getAndIncrement",
"java.util.concurrent.atomic.AtomicInteger.getAndDecrement",
"java.util.concurrent.atomic.AtomicLong.getAndIncrement",
"java.util.concurrent.atomic.AtomicLong.getAndDecrement"
)
val USE_PROPERTY_ACCESS_INSPECTION: Key<UsePropertyAccessSyntaxInspection> = Key.create("UsePropertyAccessSyntax")
}
}
class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention<KtCallExpression>(KtCallExpression::class.java, "Use property access syntax") {
override fun isApplicableTo(element: KtCallExpression): Boolean {
@@ -87,6 +141,11 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention
if (!resolvedCall.isReallySuccess()) return null
val function = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return null
val notProperties = (inspection as? UsePropertyAccessSyntaxInspection)?.fqNameList?.toSet() ?:
NotPropertiesService.getNotProperties(callExpression)
if (function.shouldNotConvertToProperty(notProperties)) return null
val resolutionScope = callExpression.getResolutionScope(bindingContext, resolutionFacade)
val property = findSyntheticProperty(function, resolutionFacade.getFrontendService(SyntheticScopes::class.java)) ?: return null
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.codeInsight.ReferenceVariantsHelper
import org.jetbrains.kotlin.idea.core.NotPropertiesService
import org.jetbrains.kotlin.idea.core.isVisible
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.guessTypes
import org.jetbrains.kotlin.idea.util.psi.patternMatching.KotlinPsiUnifier
@@ -101,9 +102,9 @@ class RenameUnresolvedReferenceFix(element: KtNameReferenceExpression): KotlinQu
val resolutionFacade = element.getResolutionFacade()
val context = resolutionFacade.analyze(element, BodyResolveMode.PARTIAL)
val moduleDescriptor = resolutionFacade.moduleDescriptor
val variantsHelper = ReferenceVariantsHelper(context, resolutionFacade, moduleDescriptor) {
val variantsHelper = ReferenceVariantsHelper(context, resolutionFacade, moduleDescriptor, {
it !is DeclarationDescriptorWithVisibility || it.isVisible(element, null, context, resolutionFacade)
}
}, NotPropertiesService.getNotProperties(element))
val expectedTypes = patternExpression
.guessTypes(context, moduleDescriptor)
.ifEmpty { arrayOf(moduleDescriptor.builtIns.nullableAnyType) }
@@ -0,0 +1,9 @@
// WITH_RUNTIME
// WITH_JDK
// IS_APPLICABLE: false
import java.net.Socket
fun main(args: Array<String>) {
val s = Socket()
val stream = s.getInputStream()<caret>
}
@@ -14605,6 +14605,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
doTest(fileName);
}
@TestMetadata("suppressedByNotPropertyList.kt")
public void testSuppressedByNotPropertyList() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/usePropertyAccessSyntax/suppressedByNotPropertyList.kt");
doTest(fileName);
}
@TestMetadata("typeParameterReceiver.kt")
public void testTypeParameterReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/intentions/usePropertyAccessSyntax/typeParameterReceiver.kt");