IterateExpressionIntention: checking for name conflicts
This commit is contained in:
@@ -51,10 +51,17 @@ public class CollectingNameValidator @jvmOverloads constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class NewDeclarationNameValidator(
|
public class NewDeclarationNameValidator(
|
||||||
private val container: PsiElement,
|
private val visibleDeclarationsContext: JetElement?,
|
||||||
private val anchor: PsiElement?,
|
private val checkDeclarationsIn: Sequence<PsiElement>,
|
||||||
private val target: NewDeclarationNameValidator.Target
|
private val target: NewDeclarationNameValidator.Target
|
||||||
) : (String) -> Boolean {
|
) : (String) -> Boolean {
|
||||||
|
|
||||||
|
public constructor(container: PsiElement, anchor: PsiElement?, target: NewDeclarationNameValidator.Target)
|
||||||
|
: this(
|
||||||
|
(anchor ?: container).parentsWithSelf.firstIsInstanceOrNull<JetElement>(),
|
||||||
|
anchor?.siblings() ?: container.allChildren,
|
||||||
|
target)
|
||||||
|
|
||||||
public enum class Target {
|
public enum class Target {
|
||||||
VARIABLES,
|
VARIABLES,
|
||||||
FUNCTIONS_AND_CLASSES
|
FUNCTIONS_AND_CLASSES
|
||||||
@@ -63,13 +70,13 @@ public class NewDeclarationNameValidator(
|
|||||||
override fun invoke(name: String): Boolean {
|
override fun invoke(name: String): Boolean {
|
||||||
val identifier = Name.identifier(name)
|
val identifier = Name.identifier(name)
|
||||||
|
|
||||||
val scopeContext = (anchor ?: container).parentsWithSelf.firstIsInstanceOrNull<JetElement>() ?: return true
|
if (visibleDeclarationsContext != null) {
|
||||||
val bindingContext = scopeContext.analyze(BodyResolveMode.PARTIAL_FOR_COMPLETION)
|
val bindingContext = visibleDeclarationsContext.analyze(BodyResolveMode.PARTIAL_FOR_COMPLETION)
|
||||||
val resolutionScope = scopeContext.getResolutionScope(bindingContext, scopeContext.getResolutionFacade())
|
val resolutionScope = visibleDeclarationsContext.getResolutionScope(bindingContext, visibleDeclarationsContext.getResolutionFacade())
|
||||||
if (resolutionScope.hasConflict(identifier)) return false
|
if (resolutionScope.hasConflict(identifier)) return false
|
||||||
|
}
|
||||||
|
|
||||||
val elementsToCheck = anchor?.siblings() ?: container.allChildren
|
return checkDeclarationsIn.none {
|
||||||
return elementsToCheck.none {
|
|
||||||
it.findDescendantOfType<JetNamedDeclaration> { it.isConflicting(identifier) } != null
|
it.findDescendantOfType<JetNamedDeclaration> { it.isConflicting(identifier) } != null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.caches.resolve.getResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.core.IterableTypesDetector
|
import org.jetbrains.kotlin.idea.core.IterableTypesDetector
|
||||||
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
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.core.replaced
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
|
import org.jetbrains.kotlin.psi.psiUtil.siblings
|
||||||
import org.jetbrains.kotlin.resolve.BindingContext
|
import org.jetbrains.kotlin.resolve.BindingContext
|
||||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
@@ -57,8 +59,8 @@ public class IterateExpressionIntention : JetSelfTargetingIntention<JetExpressio
|
|||||||
//TODO: multi-declaration (when?)
|
//TODO: multi-declaration (when?)
|
||||||
|
|
||||||
val elementType = data(element)!!.elementType
|
val elementType = data(element)!!.elementType
|
||||||
//TODO: name validation
|
val nameValidator = NewDeclarationNameValidator(element, element.siblings(), NewDeclarationNameValidator.Target.VARIABLES)
|
||||||
val names = KotlinNameSuggester.suggestIterationVariableNames(element, elementType, { true }, "e")
|
val names = KotlinNameSuggester.suggestIterationVariableNames(element, elementType, nameValidator, "e")
|
||||||
|
|
||||||
var forExpression = JetPsiFactory(element).createExpressionByPattern("for($0 in $1) {\nx\n}", names.first(), element) as JetForExpression
|
var forExpression = JetPsiFactory(element).createExpressionByPattern("for($0 in $1) {\nx\n}", names.first(), element) as JetForExpression
|
||||||
forExpression = element.replaced(forExpression)
|
forExpression = element.replaced(forExpression)
|
||||||
|
|||||||
+1
-1
@@ -234,7 +234,7 @@ public open class KotlinIntroduceParameterHandler(
|
|||||||
is JetClass -> targetParent.getBody()
|
is JetClass -> targetParent.getBody()
|
||||||
else -> null
|
else -> null
|
||||||
} ?: throw AssertionError("Body element is not found: ${targetParent.getElementTextWithContext()}")
|
} ?: 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 suggestedNames = KotlinNameSuggester.suggestNamesByType(replacementType, nameValidator, "p")
|
||||||
|
|
||||||
val parametersUsages = findInternalUsagesOfParametersAndReceiver(targetParent, functionDescriptor)
|
val parametersUsages = findInternalUsagesOfParametersAndReceiver(targetParent, functionDescriptor)
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
fun foo(names: List<String>, name: String) {
|
||||||
|
if (name == "") {
|
||||||
|
val name2 = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
names<caret>
|
||||||
|
|
||||||
|
val name1 = ""
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fun foo(names: List<String>, name: String) {
|
||||||
|
if (name == "") {
|
||||||
|
val name2 = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
for (name2 in names) {
|
||||||
|
<caret>
|
||||||
|
}
|
||||||
|
|
||||||
|
val name1 = ""
|
||||||
|
}
|
||||||
@@ -5241,6 +5241,12 @@ public class IntentionTestGenerated extends AbstractIntentionTest {
|
|||||||
doTest(fileName);
|
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")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/iterateExpression/simple.kt");
|
String fileName = JetTestUtils.navigationMetadata("idea/testData/intentions/iterateExpression/simple.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user