IterateExpressionIntention: checking for name conflicts

This commit is contained in:
Valentin Kipyatkov
2015-06-26 21:44:33 +03:00
parent abb729b2ed
commit 5c0195ff68
6 changed files with 46 additions and 11 deletions
@@ -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<PsiElement>,
private val target: NewDeclarationNameValidator.Target
) : (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 {
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<JetElement>() ?: 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<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.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<JetExpressio
//TODO: multi-declaration (when?)
val elementType = data(element)!!.elementType
//TODO: name validation
val names = KotlinNameSuggester.suggestIterationVariableNames(element, elementType, { true }, "e")
val nameValidator = NewDeclarationNameValidator(element, element.siblings(), NewDeclarationNameValidator.Target.VARIABLES)
val names = KotlinNameSuggester.suggestIterationVariableNames(element, elementType, nameValidator, "e")
var forExpression = JetPsiFactory(element).createExpressionByPattern("for($0 in $1) {\nx\n}", names.first(), element) as JetForExpression
forExpression = element.replaced(forExpression)
@@ -234,7 +234,7 @@ public open class KotlinIntroduceParameterHandler(
is JetClass -> 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)
@@ -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);
}
@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");