diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt index ac11dec7b66..c7f7aec42dc 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/codeInsight/ReferenceVariantsHelper.kt @@ -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 = setOf() ) { fun getReferenceVariants( expression: KtSimpleNameExpression, @@ -96,7 +98,9 @@ class ReferenceVariantsHelper( fun filterOutJavaGettersAndSetters(variants: Collection): Collection { val accessorMethodsToRemove = HashSet() - 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 diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/NotPropertyList.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/NotPropertyList.kt new file mode 100644 index 00000000000..f102e7e07a2 --- /dev/null +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/NotPropertyList.kt @@ -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): Boolean { + if (fqNameUnsafe in notProperties) return true + return this.overriddenTreeUniqueAsSequence(false).any { fqNameUnsafe in notProperties } +} + +fun SyntheticJavaPropertyDescriptor.suppressedByNotPropertyList(set: Set) = + getMethod.shouldNotConvertToProperty(set) || setMethod?.shouldNotConvertToProperty(set) ?: false \ No newline at end of file diff --git a/idea/idea-analysis/idea-analysis.iml b/idea/idea-analysis/idea-analysis.iml index 41cf1cdfca0..d17a8482c7e 100644 --- a/idea/idea-analysis/idea-analysis.iml +++ b/idea/idea-analysis/idea-analysis.iml @@ -15,7 +15,7 @@ - + diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/inspections/IntentionBasedInspection.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/inspections/IntentionBasedInspection.kt index 414ca1f681a..fea61503938 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/inspections/IntentionBasedInspection.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/inspections/IntentionBasedInspection.kt @@ -78,7 +78,9 @@ abstract class IntentionBasedInspection( 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( if (fixes == null) { fixes = SmartList() } - fixes!!.add(createQuickFix(intention, additionalChecker, targetElement)) + fixes.add(createQuickFix(intention, additionalChecker, targetElement)) } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/intentions/SelfTargetingIntention.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/intentions/SelfTargetingIntention.kt index 73fb166d3cf..f006e392bdb 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/intentions/SelfTargetingIntention.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/intentions/SelfTargetingIntention.kt @@ -91,8 +91,11 @@ abstract class SelfTargetingIntention( return !isIntentionBaseInspectionEnabled(project, target) } + var inspection: IntentionBasedInspection? = 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)) { diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt index 6bf3bc51dcd..30dd6781474 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionSession.kt @@ -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? diff --git a/idea/idea-completion/testData/basic/java/syntheticExtensions/SuppressedByNotPropertyList.kt b/idea/idea-completion/testData/basic/java/syntheticExtensions/SuppressedByNotPropertyList.kt new file mode 100644 index 00000000000..d20708ec55f --- /dev/null +++ b/idea/idea-completion/testData/basic/java/syntheticExtensions/SuppressedByNotPropertyList.kt @@ -0,0 +1,9 @@ +import java.net.Socket + +fun main(args: Array) { + val s = Socket() + s. +} + +// EXIST: {"lookupString":"getInputStream","tailText":"()","typeText":"InputStream!","attributes":"bold","allLookupStrings":"getInputStream","itemText":"getInputStream"} +// ABSENT: inputStream \ No newline at end of file diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java index 88e48a27f0b..0ef4624a714 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/JvmBasicCompletionTestGenerated.java @@ -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"); diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/NotPropertiesService.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/NotPropertiesService.kt new file mode 100644 index 00000000000..0a6be9dd949 --- /dev/null +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/NotPropertiesService.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 + + companion object { + fun getInstance(project: Project): NotPropertiesService { + return ServiceManager.getService(project, NotPropertiesService::class.java) + } + + fun getNotProperties(element: PsiElement) = + getInstance(element.project).getNotProperties(element) + } +} \ No newline at end of file diff --git a/idea/idea-live-templates/src/org/jetbrains/kotlin/idea/liveTemplates/macro/BaseKotlinVariableMacro.kt b/idea/idea-live-templates/src/org/jetbrains/kotlin/idea/liveTemplates/macro/BaseKotlinVariableMacro.kt index b48db9040bb..f5adbc79f86 100644 --- a/idea/idea-live-templates/src/org/jetbrains/kotlin/idea/liveTemplates/macro/BaseKotlinVariableMacro.kt +++ b/idea/idea-live-templates/src/org/jetbrains/kotlin/idea/liveTemplates/macro/BaseKotlinVariableMacro.kt @@ -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 : 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 } diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml index 9628e54eb6d..b968e4483ba 100644 --- a/idea/src/META-INF/plugin.xml +++ b/idea/src/META-INF/plugin.xml @@ -119,6 +119,11 @@ + + + + @@ -306,6 +311,9 @@ + + @@ -1612,6 +1620,7 @@ () + var pFunctions = 0 + val matchedDescriptors = mutableSetOf() + + 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() + 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() + + + var i = 0 + resultDescriptors.forEach { desc -> + progress("Step 2: ${i++} of ${resultDescriptors.size}", "$desc") + val source = DescriptorToSourceUtilsIde.getAllDeclarations(project, desc) + .filterIsInstance() + .firstOrNull() ?: return@forEach + val abstract = source.modifierList.hasModifierProperty(PsiModifier.ABSTRACT) + if (!abstract) { + if (!source.isTrivial()) { + descriptorToPsiBinding[desc] = source + } + } + } + + val nonTrivial = mutableSetOf() + 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().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 + } + } + +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/ui/NotPropertyListPanel.kt b/idea/src/org/jetbrains/kotlin/idea/configuration/ui/NotPropertyListPanel.kt new file mode 100644 index 00000000000..ab4f3653f9c --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/ui/NotPropertyListPanel.kt @@ -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) : AddEditRemovePanel(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() { + override fun getField(o: FqNameUnsafe, columnIndex: Int) = o.asString() + override fun getColumnName(columnIndex: Int) = "Method" + override fun getColumnCount() = 1 + } +} + diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/UsePropertyAccessSyntaxIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/UsePropertyAccessSyntaxIntention.kt index 3382d00dfc7..3c5ba588cb8 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/UsePropertyAccessSyntaxIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/UsePropertyAccessSyntaxIntention.kt @@ -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(UsePropertyAccessSyntaxIntention::class), CleanupLocalInspectionTool +class UsePropertyAccessSyntaxInspection : IntentionBasedInspection(UsePropertyAccessSyntaxIntention::class), CleanupLocalInspectionTool { + + val fqNameList = mutableListOf() + + var fqNameStrings: List + 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 { + 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 = Key.create("UsePropertyAccessSyntax") + } +} class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention(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 diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/RenameUnresolvedReferenceFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/RenameUnresolvedReferenceFix.kt index d8275076df8..b0ad6a13f48 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/RenameUnresolvedReferenceFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/RenameUnresolvedReferenceFix.kt @@ -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) } diff --git a/idea/testData/intentions/usePropertyAccessSyntax/suppressedByNotPropertyList.kt b/idea/testData/intentions/usePropertyAccessSyntax/suppressedByNotPropertyList.kt new file mode 100644 index 00000000000..bf240cb68d1 --- /dev/null +++ b/idea/testData/intentions/usePropertyAccessSyntax/suppressedByNotPropertyList.kt @@ -0,0 +1,9 @@ +// WITH_RUNTIME +// WITH_JDK +// IS_APPLICABLE: false +import java.net.Socket + +fun main(args: Array) { + val s = Socket() + val stream = s.getInputStream() +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java index 46b4443cf58..03a6ee3606f 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -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");