diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/NameValidators.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/NameValidators.kt index ce1d2d48120..bf8906ad001 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/NameValidators.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/NameValidators.kt @@ -51,10 +51,17 @@ public class CollectingNameValidator @jvmOverloads constructor( } public class NewDeclarationNameValidator( - private val container: PsiElement, - private val anchor: PsiElement?, + private val visibleDeclarationsContext: JetElement?, + private val checkDeclarationsIn: Sequence, private val target: NewDeclarationNameValidator.Target ) : (String) -> Boolean { + + public constructor(container: PsiElement, anchor: PsiElement?, target: NewDeclarationNameValidator.Target) + : this( + (anchor ?: container).parentsWithSelf.firstIsInstanceOrNull(), + anchor?.siblings() ?: container.allChildren, + target) + public enum class Target { VARIABLES, FUNCTIONS_AND_CLASSES @@ -63,13 +70,13 @@ public class NewDeclarationNameValidator( override fun invoke(name: String): Boolean { val identifier = Name.identifier(name) - val scopeContext = (anchor ?: container).parentsWithSelf.firstIsInstanceOrNull() ?: return true - val bindingContext = scopeContext.analyze(BodyResolveMode.PARTIAL_FOR_COMPLETION) - val resolutionScope = scopeContext.getResolutionScope(bindingContext, scopeContext.getResolutionFacade()) - if (resolutionScope.hasConflict(identifier)) return false + if (visibleDeclarationsContext != null) { + val bindingContext = visibleDeclarationsContext.analyze(BodyResolveMode.PARTIAL_FOR_COMPLETION) + val resolutionScope = visibleDeclarationsContext.getResolutionScope(bindingContext, visibleDeclarationsContext.getResolutionFacade()) + if (resolutionScope.hasConflict(identifier)) return false + } - val elementsToCheck = anchor?.siblings() ?: container.allChildren - return elementsToCheck.none { + return checkDeclarationsIn.none { it.findDescendantOfType { it.isConflicting(identifier) } != null } } diff --git a/idea/src/org/jetbrains/kotlin/idea/intentions/IterateExpressionIntention.kt b/idea/src/org/jetbrains/kotlin/idea/intentions/IterateExpressionIntention.kt index 8a61c312f2c..ec785497546 100644 --- a/idea/src/org/jetbrains/kotlin/idea/intentions/IterateExpressionIntention.kt +++ b/idea/src/org/jetbrains/kotlin/idea/intentions/IterateExpressionIntention.kt @@ -25,9 +25,11 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.core.IterableTypesDetector import org.jetbrains.kotlin.idea.core.KotlinNameSuggester +import org.jetbrains.kotlin.idea.core.NewDeclarationNameValidator import org.jetbrains.kotlin.idea.core.replaced import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.siblings import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.types.JetType @@ -57,8 +59,8 @@ public class IterateExpressionIntention : JetSelfTargetingIntention targetParent.getBody() else -> null } ?: throw AssertionError("Body element is not found: ${targetParent.getElementTextWithContext()}") - val nameValidator = NewDeclarationNameValidator(body, null, NewDeclarationNameValidator.Target.VARIABLES) + val nameValidator = NewDeclarationNameValidator(body, sequenceOf(body), NewDeclarationNameValidator.Target.VARIABLES) val suggestedNames = KotlinNameSuggester.suggestNamesByType(replacementType, nameValidator, "p") val parametersUsages = findInternalUsagesOfParametersAndReceiver(targetParent, functionDescriptor) diff --git a/idea/testData/intentions/iterateExpression/noNameConflict.kt b/idea/testData/intentions/iterateExpression/noNameConflict.kt new file mode 100644 index 00000000000..4e9d6e586aa --- /dev/null +++ b/idea/testData/intentions/iterateExpression/noNameConflict.kt @@ -0,0 +1,9 @@ +fun foo(names: List, name: String) { + if (name == "") { + val name2 = "" + } + + names + + val name1 = "" +} \ No newline at end of file diff --git a/idea/testData/intentions/iterateExpression/noNameConflict.kt.after b/idea/testData/intentions/iterateExpression/noNameConflict.kt.after new file mode 100644 index 00000000000..f221a68afb1 --- /dev/null +++ b/idea/testData/intentions/iterateExpression/noNameConflict.kt.after @@ -0,0 +1,11 @@ +fun foo(names: List, name: String) { + if (name == "") { + val name2 = "" + } + + for (name2 in names) { + + } + + val name1 = "" +} \ 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 659a3d07d67..f068e1782f7 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/intentions/IntentionTestGenerated.java @@ -5241,6 +5241,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest { doTest(fileName); } + @TestMetadata("noNameConflict.kt") + public void testNoNameConflict() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/iterateExpression/noNameConflict.kt"); + doTest(fileName); + } + @TestMetadata("simple.kt") public void testSimple() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/iterateExpression/simple.kt");