Change Signature: Support header/impl declarations

This commit is contained in:
Alexey Sedunov
2017-03-03 16:46:43 +03:00
parent 66265972aa
commit b33b06722d
28 changed files with 445 additions and 16 deletions
@@ -80,4 +80,4 @@ internal fun KtDeclaration.liftToHeader(): KtDeclaration? {
hasModifier(KtTokens.IMPL_KEYWORD) -> headerDeclarationIfAny()
else -> null
}
}
}
@@ -28,12 +28,12 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.descriptors.impl.AnonymousFunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.highlighter.markers.headerImplementations
import org.jetbrains.kotlin.idea.highlighter.markers.liftToHeader
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.KotlinCallableDefinitionUsage
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.KtCallableDeclaration
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.DescriptorUtils
import java.util.*
@@ -86,7 +86,9 @@ class KotlinChangeSignatureData(
override val primaryCallables: Collection<KotlinCallableDefinitionUsage<PsiElement>> by lazy {
descriptorsForSignatureChange.map {
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(baseDeclaration.project, it)
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(baseDeclaration.project, it)?.let {
(it as? KtDeclaration)?.liftToHeader() ?: it
}
assert(declaration != null) { "No declaration found for " + baseDescriptor }
KotlinCallableDefinitionUsage(declaration!!, it, null, null)
}
@@ -98,9 +100,15 @@ class KotlinChangeSignatureData(
override val affectedCallables: Collection<UsageInfo> by lazy {
primaryCallables + primaryCallables.flatMapTo(HashSet<UsageInfo>()) { primaryFunction ->
val primaryDeclaration = primaryFunction.declaration as? KtCallableDeclaration
val lightMethods = primaryDeclaration?.toLightMethods() ?: Collections.emptyList()
lightMethods.flatMap { baseMethod ->
val primaryDeclaration = primaryFunction.declaration as? KtCallableDeclaration ?: return@flatMapTo emptyList()
if (primaryDeclaration.hasModifier(KtTokens.HEADER_KEYWORD)) {
return@flatMapTo primaryDeclaration.headerImplementations().map {
KotlinCallableDefinitionUsage<PsiElement>(it, it.resolveToDescriptor() as CallableDescriptor, primaryFunction, null)
}
}
primaryDeclaration.toLightMethods().flatMap { baseMethod ->
OverridingMethodsSearch
.search(baseMethod)
.mapNotNullTo(HashSet<UsageInfo>()) { overridingMethod ->
@@ -31,12 +31,11 @@ import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.asJava.toLightMethods
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.core.quoteIfNeeded
import org.jetbrains.kotlin.idea.highlighter.markers.headerDeclarationIfAny
import org.jetbrains.kotlin.idea.highlighter.markers.headerImplementations
import org.jetbrains.kotlin.idea.highlighter.markers.liftToHeader
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchOptions
import org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinReferencesSearchParameters
import org.jetbrains.kotlin.idea.search.projectScope
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
@@ -72,11 +71,7 @@ abstract class RenameKotlinPsiProcessor : RenamePsiElementProcessor() {
val declaration = element.namedUnwrappedElement as? KtNamedDeclaration
if (declaration != null) {
when {
declaration.hasModifier(KtTokens.HEADER_KEYWORD) -> declaration
declaration.hasModifier(KtTokens.IMPL_KEYWORD) -> declaration.headerDeclarationIfAny()
else -> null
}?.let { headerDeclaration ->
declaration.liftToHeader()?.let { headerDeclaration ->
allRenames[headerDeclaration] = safeNewName
headerDeclaration.headerImplementations().forEach { allRenames[it] = safeNewName }
}
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="Common (experimental) " useProjectSettings="false">
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,11 @@
package test
header fun foo()
header fun baz(n: Int)
header fun bar(n: Int)
fun test() {
foo()
baz(1)
bar(1)
}
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="JavaScript " useProjectSettings="false">
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="Common" />
</component>
</module>
@@ -0,0 +1,11 @@
package test
impl fun foo() { }
impl fun baz(n: Int) { }
impl fun bar(n: Int) { }
fun test() {
foo()
baz(1)
bar(1)
}
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="JVM 1.6" useProjectSettings="false">
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="Common" />
</component>
</module>
@@ -0,0 +1,11 @@
package test
impl fun foo() { }
impl fun baz(n: Int) { }
impl fun bar(n: Int) { }
fun test() {
foo()
baz(1)
bar(1)
}
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="Common (experimental) " useProjectSettings="false">
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,11 @@
package test
header fun foo()
header fun <caret>foo(n: Int)
header fun bar(n: Int)
fun test() {
foo()
foo(1)
bar(1)
}
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="JavaScript " useProjectSettings="false">
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="Common" />
</component>
</module>
@@ -0,0 +1,11 @@
package test
impl fun foo() { }
impl fun foo(n: Int) { }
impl fun bar(n: Int) { }
fun test() {
foo()
foo(1)
bar(1)
}
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="JVM 1.6" useProjectSettings="false">
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="Common" />
</component>
</module>
@@ -0,0 +1,11 @@
package test
impl fun foo() { }
impl fun foo(n: Int) { }
impl fun bar(n: Int) { }
fun test() {
foo()
foo(1)
bar(1)
}
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="Common (experimental) " useProjectSettings="false">
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,11 @@
package test
header fun foo()
header fun baz(n: Int)
header fun bar(n: Int)
fun test() {
foo()
baz(1)
bar(1)
}
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="JavaScript " useProjectSettings="false">
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="Common" />
</component>
</module>
@@ -0,0 +1,11 @@
package test
impl fun foo() { }
impl fun baz(n: Int) { }
impl fun bar(n: Int) { }
fun test() {
foo()
baz(1)
bar(1)
}
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="JVM 1.6" useProjectSettings="false">
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="Common" />
</component>
</module>
@@ -0,0 +1,11 @@
package test
impl fun foo() { }
impl fun baz(n: Int) { }
impl fun bar(n: Int) { }
fun test() {
foo()
baz(1)
bar(1)
}
@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="Common (experimental) " useProjectSettings="false">
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
@@ -0,0 +1,11 @@
package test
header fun foo()
header fun foo(n: Int)
header fun bar(n: Int)
fun test() {
foo()
foo(1)
bar(1)
}
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="JavaScript " useProjectSettings="false">
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="Common" />
</component>
</module>
@@ -0,0 +1,11 @@
package test
impl fun foo() { }
impl fun <caret>foo(n: Int) { }
impl fun bar(n: Int) { }
fun test() {
foo()
foo(1)
bar(1)
}
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="JVM 1.6" useProjectSettings="false">
<compilerSettings/>
<compilerArguments/>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="Common" />
</component>
</module>
@@ -0,0 +1,11 @@
package test
impl fun foo() { }
impl fun foo(n: Int) { }
impl fun bar(n: Int) { }
fun test() {
foo()
foo(1)
bar(1)
}
@@ -0,0 +1,58 @@
/*
* 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.refactoring.changeSignature
import com.intellij.psi.PsiDocumentManager
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.refactoring.toPsiFile
import org.jetbrains.kotlin.idea.test.KotlinMultiFileTestCase
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase
import org.jetbrains.kotlin.idea.test.extractMarkerOffset
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class KotlinMultiModuleChangeSignatureTest : KotlinMultiFileTestCase() {
init {
isMultiModule = true
}
override fun getTestRoot(): String = "/refactoring/changeSignatureMultiModule/"
override fun getTestDataPath(): String = PluginTestCaseBase.getTestDataPathBase()
private fun doTest(filePath: String, configure: KotlinChangeInfo.() -> Unit) {
doTestCommittingDocuments { rootDir, _ ->
val psiFile = rootDir.findFileByRelativePath(filePath)!!.toPsiFile(project)!!
val doc = PsiDocumentManager.getInstance(project).getDocument(psiFile)!!
val marker = doc.extractMarkerOffset(project)
assert(marker != -1)
val element = KotlinChangeSignatureHandler().findTargetMember(psiFile.findElementAt(marker)!!) as KtElement
val bindingContext = element.analyze(BodyResolveMode.FULL)
val callableDescriptor = KotlinChangeSignatureHandler.findDescriptor(element, project, editor, bindingContext)!!
val changeInfo = createChangeInfo(project, callableDescriptor, KotlinChangeSignatureConfiguration.Empty, element)!!
KotlinChangeSignatureProcessor(project, changeInfo.apply { configure() }, "Change signature").run()
}
}
fun testHeadersAndImplsByHeaderFun() = doTest("Common/src/test/test.kt") {
newName = "baz"
}
fun testHeadersAndImplsByImplFun() = doTest("JS/src/test/test.kt") {
newName = "baz"
}
}