diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetNamedDeclarationNotStubbed.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetNamedDeclarationNotStubbed.java index 7db34d5ac22..2f1e11ae9a3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetNamedDeclarationNotStubbed.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetNamedDeclarationNotStubbed.java @@ -48,7 +48,7 @@ abstract class JetNamedDeclarationNotStubbed extends JetDeclarationImpl implemen @Override public Name getNameAsName() { String name = getName(); - return name != null ? Name.identifier(name) : null; + return name != null ? Name.guess(name) : null; } @Override diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetNamedDeclarationStub.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetNamedDeclarationStub.java index 0840765871b..29fce242176 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/JetNamedDeclarationStub.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/JetNamedDeclarationStub.java @@ -62,7 +62,7 @@ abstract class JetNamedDeclarationStub extends J @Override public Name getNameAsName() { String name = getName(); - return name != null ? Name.identifier(name) : null; + return name != null ? Name.guess(name) : null; } @Override diff --git a/idea/src/org/jetbrains/kotlin/idea/refactoring/NameValidatorImpl.kt b/idea/src/org/jetbrains/kotlin/idea/refactoring/NameValidatorImpl.kt index 042db54ffd1..f2e01a8f722 100644 --- a/idea/src/org/jetbrains/kotlin/idea/refactoring/NameValidatorImpl.kt +++ b/idea/src/org/jetbrains/kotlin/idea/refactoring/NameValidatorImpl.kt @@ -16,21 +16,20 @@ package org.jetbrains.kotlin.idea.refactoring -import com.intellij.openapi.util.Ref import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.idea.caches.resolve.* -import org.jetbrains.kotlin.idea.core.* +import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade +import org.jetbrains.kotlin.idea.core.getResolutionScope import org.jetbrains.kotlin.name.Name -import org.jetbrains.kotlin.psi.JetElement -import org.jetbrains.kotlin.psi.JetExpression -import org.jetbrains.kotlin.psi.JetVisitorVoid +import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.psiUtil.allChildren +import org.jetbrains.kotlin.psi.psiUtil.findDescendantOfType +import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.kotlin.psi.psiUtil.siblings -import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.scopes.JetScope - -import java.util.HashSet +import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull public class NameValidatorImpl( private val container: PsiElement, @@ -43,54 +42,32 @@ public class NameValidatorImpl( } override fun invoke(name: String): Boolean { - val visitedScopes = HashSet() - val identifier = Name.identifier(name) - val sibling = if (anchor != null) { - anchor - } - else { - if (container is JetExpression) { - return !hasConflict(identifier, container, visitedScopes) - } - container.getFirstChild() ?: return true - } + 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 - return sibling.siblings().none { hasConflict(identifier, it, visitedScopes) } + val elementsToCheck = anchor?.siblings() ?: container.allChildren + return elementsToCheck.none { + it.findDescendantOfType { it.isConflicting(identifier) } != null + } } - private fun hasConflict(name: Name, sibling: PsiElement, visitedScopes: MutableSet): Boolean { - if (sibling !is JetElement) return false + private fun JetScope.hasConflict(name: Name): Boolean { + return when(target) { + Target.PROPERTIES -> getProperties(name).any { !it.isExtension } || getLocalVariable(name) != null + Target.FUNCTIONS_AND_CLASSES -> getFunctions(name).any { !it.isExtension } || getClassifier(name) != null + } + } - val context = sibling.analyze(BodyResolveMode.FULL) - - var conflictFound = false - sibling.accept(object : JetVisitorVoid() { - override fun visitElement(element: PsiElement) { - if (!conflictFound) { - element.acceptChildren(this) - } - } - - override fun visitExpression(expression: JetExpression) { - val resolutionScope = expression.getResolutionScope(context, expression.getResolutionFacade()) - - if (!visitedScopes.add(resolutionScope)) return - - val conflict = if (target === Target.PROPERTIES) - resolutionScope.getProperties(name).any { !it.isExtension } || resolutionScope.getLocalVariable(name) != null - else - resolutionScope.getFunctions(name).any { !it.isExtension } || resolutionScope.getClassifier(name) != null - - if (conflict) { - conflictFound = true - return - } - - super.visitExpression(expression) - } - }) - return conflictFound + private fun JetNamedDeclaration.isConflicting(name: Name): Boolean { + if (getNameAsName() != name) return false + if (this is JetCallableDeclaration && getReceiverTypeReference() != null) return false + return when(target) { + Target.PROPERTIES -> this is JetVariableDeclaration + Target.FUNCTIONS_AND_CLASSES -> this is JetNamedFunction || this is JetClassOrObject + } } } diff --git a/idea/testData/refactoring/introduceParameter/substituteExplicitThisInMember.kt.after b/idea/testData/refactoring/introduceParameter/substituteExplicitThisInMember.kt.after index a21e80c9e36..fdd138e0e74 100644 --- a/idea/testData/refactoring/introduceParameter/substituteExplicitThisInMember.kt.after +++ b/idea/testData/refactoring/introduceParameter/substituteExplicitThisInMember.kt.after @@ -8,12 +8,12 @@ class A(val a: Int) { } fun test() { - val a = A(1) - val a1 = A(2) - a.foo(a.a + a1.a) + val a2 = A(1) + val a3 = A(2) + a2.foo(a2.a + a3.a) with(A(1)) { val a1 = A(2) - foo(this.a + a1.a) + foo(a + a1.a) val a = A(2) this.foo(this.a + a.a) } diff --git a/idea/testData/refactoring/introduceParameter/substituteImplicitThisInMember.kt.after b/idea/testData/refactoring/introduceParameter/substituteImplicitThisInMember.kt.after index a21e80c9e36..fdd138e0e74 100644 --- a/idea/testData/refactoring/introduceParameter/substituteImplicitThisInMember.kt.after +++ b/idea/testData/refactoring/introduceParameter/substituteImplicitThisInMember.kt.after @@ -8,12 +8,12 @@ class A(val a: Int) { } fun test() { - val a = A(1) - val a1 = A(2) - a.foo(a.a + a1.a) + val a2 = A(1) + val a3 = A(2) + a2.foo(a2.a + a3.a) with(A(1)) { val a1 = A(2) - foo(this.a + a1.a) + foo(a + a1.a) val a = A(2) this.foo(this.a + a.a) } diff --git a/idea/testData/refactoring/introduceVariable/NameSuggestionBug.kt b/idea/testData/refactoring/introduceVariable/NameSuggestionBug1.kt similarity index 100% rename from idea/testData/refactoring/introduceVariable/NameSuggestionBug.kt rename to idea/testData/refactoring/introduceVariable/NameSuggestionBug1.kt diff --git a/idea/testData/refactoring/introduceVariable/NameSuggestionBug.kt.after b/idea/testData/refactoring/introduceVariable/NameSuggestionBug1.kt.after similarity index 100% rename from idea/testData/refactoring/introduceVariable/NameSuggestionBug.kt.after rename to idea/testData/refactoring/introduceVariable/NameSuggestionBug1.kt.after diff --git a/idea/testData/refactoring/introduceVariable/NameSuggestionBug2.kt b/idea/testData/refactoring/introduceVariable/NameSuggestionBug2.kt new file mode 100644 index 00000000000..8970d4c0dab --- /dev/null +++ b/idea/testData/refactoring/introduceVariable/NameSuggestionBug2.kt @@ -0,0 +1,12 @@ +class For { + var xxx: For? = null +} + + +fun foo(f: For) { + f.xxx + + if (true) { + val xxx = 1 + } +} \ No newline at end of file diff --git a/idea/testData/refactoring/introduceVariable/NameSuggestionBug2.kt.after b/idea/testData/refactoring/introduceVariable/NameSuggestionBug2.kt.after new file mode 100644 index 00000000000..b5fcd59e19f --- /dev/null +++ b/idea/testData/refactoring/introduceVariable/NameSuggestionBug2.kt.after @@ -0,0 +1,12 @@ +class For { + var xxx: For? = null +} + + +fun foo(f: For) { + val xxx1 = f.xxx + + if (true) { + val xxx = 1 + } +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/JetExtractionTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/JetExtractionTestGenerated.java index 18985c72c86..166f702c7e2 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/JetExtractionTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/refactoring/introduce/JetExtractionTestGenerated.java @@ -163,9 +163,15 @@ public class JetExtractionTestGenerated extends AbstractJetExtractionTest { doIntroduceVariableTest(fileName); } - @TestMetadata("NameSuggestionBug.kt") - public void testNameSuggestionBug() throws Exception { - String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/NameSuggestionBug.kt"); + @TestMetadata("NameSuggestionBug1.kt") + public void testNameSuggestionBug1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/NameSuggestionBug1.kt"); + doIntroduceVariableTest(fileName); + } + + @TestMetadata("NameSuggestionBug2.kt") + public void testNameSuggestionBug2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/introduceVariable/NameSuggestionBug2.kt"); doIntroduceVariableTest(fileName); }