Change signature fix: correct parameter add / remove from enum constructor calls, relevant test fixes
This commit is contained in:
@@ -17,7 +17,6 @@
|
|||||||
package org.jetbrains.kotlin.psi
|
package org.jetbrains.kotlin.psi
|
||||||
|
|
||||||
import com.intellij.lang.ASTNode
|
import com.intellij.lang.ASTNode
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
|
||||||
import com.intellij.openapi.project.Project
|
import com.intellij.openapi.project.Project
|
||||||
import com.intellij.openapi.util.Key
|
import com.intellij.openapi.util.Key
|
||||||
import com.intellij.psi.PsiComment
|
import com.intellij.psi.PsiComment
|
||||||
@@ -27,14 +26,11 @@ import com.intellij.psi.util.PsiTreeUtil
|
|||||||
import com.intellij.util.LocalTimeCounter
|
import com.intellij.util.LocalTimeCounter
|
||||||
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
import org.jetbrains.kotlin.analyzer.ModuleInfo
|
||||||
import org.jetbrains.kotlin.idea.JetFileType
|
import org.jetbrains.kotlin.idea.JetFileType
|
||||||
import org.jetbrains.kotlin.lexer.JetKeywordToken
|
|
||||||
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken
|
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.JetPsiFactory.CallableBuilder.Target
|
import org.jetbrains.kotlin.psi.JetPsiFactory.CallableBuilder.Target
|
||||||
import org.jetbrains.kotlin.resolve.ImportPath
|
import org.jetbrains.kotlin.resolve.ImportPath
|
||||||
import java.io.PrintWriter
|
|
||||||
import java.io.StringWriter
|
|
||||||
|
|
||||||
public fun JetPsiFactory(project: Project?): JetPsiFactory = JetPsiFactory(project!!)
|
public fun JetPsiFactory(project: Project?): JetPsiFactory = JetPsiFactory(project!!)
|
||||||
public fun JetPsiFactory(elementForProject: PsiElement): JetPsiFactory = JetPsiFactory(elementForProject.getProject())
|
public fun JetPsiFactory(elementForProject: PsiElement): JetPsiFactory = JetPsiFactory(elementForProject.getProject())
|
||||||
@@ -262,9 +258,13 @@ public class JetPsiFactory(private val project: Project) {
|
|||||||
return createDeclaration<JetClass>("enum class E {$text}").getDeclarations()[0] as JetEnumEntry
|
return createDeclaration<JetClass>("enum class E {$text}").getDeclarations()[0] as JetEnumEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun createEnumEntryInitializerList(): JetInitializerList {
|
||||||
|
return createEnumEntry("Entry()").initializerList!!
|
||||||
|
}
|
||||||
|
|
||||||
public fun createEnumEntrySuperclassReferenceExpression(): JetEnumEntrySuperclassReferenceExpression {
|
public fun createEnumEntrySuperclassReferenceExpression(): JetEnumEntrySuperclassReferenceExpression {
|
||||||
val userType = createEnumEntry("Entry()").getInitializerList()!!.getInitializers()[0].getTypeReference()!!.getTypeElement() as JetUserType
|
val userType = createEnumEntryInitializerList().initializers[0].typeReference!!.typeElement as JetUserType
|
||||||
return userType.getReferenceExpression() as JetEnumEntrySuperclassReferenceExpression
|
return userType.referenceExpression as JetEnumEntrySuperclassReferenceExpression
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun createWhenEntry(entryText: String): JetWhenEntry {
|
public fun createWhenEntry(entryText: String): JetWhenEntry {
|
||||||
|
|||||||
@@ -110,12 +110,12 @@ private fun JetElement.getConstructorCallDescriptor(): DeclarationDescriptor? {
|
|||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
public fun PsiElement.processDelegationCallConstructorUsages(scope: SearchScope, process: (JetConstructorDelegationCall) -> Unit) {
|
public fun PsiElement.processDelegationCallConstructorUsages(scope: SearchScope, process: (JetCallElement) -> Unit) {
|
||||||
processDelegationCallKotlinConstructorUsages(scope, process)
|
processDelegationCallKotlinConstructorUsages(scope, process)
|
||||||
processDelegationCallJavaConstructorUsages(scope, process)
|
processDelegationCallJavaConstructorUsages(scope, process)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun PsiElement.processDelegationCallKotlinConstructorUsages(scope: SearchScope, process: (JetConstructorDelegationCall) -> Unit) {
|
private fun PsiElement.processDelegationCallKotlinConstructorUsages(scope: SearchScope, process: (JetCallElement) -> Unit) {
|
||||||
val element = unwrapped
|
val element = unwrapped
|
||||||
val klass = when (element) {
|
val klass = when (element) {
|
||||||
is JetConstructor<*> -> element.getContainingClassOrObject()
|
is JetConstructor<*> -> element.getContainingClassOrObject()
|
||||||
@@ -130,7 +130,7 @@ private fun PsiElement.processDelegationCallKotlinConstructorUsages(scope: Searc
|
|||||||
processInheritorsDelegatingCallToSpecifiedConstructor(klass, scope, descriptor, process)
|
processInheritorsDelegatingCallToSpecifiedConstructor(klass, scope, descriptor, process)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun PsiElement.processDelegationCallJavaConstructorUsages(scope: SearchScope, process: (JetConstructorDelegationCall) -> Unit) {
|
private fun PsiElement.processDelegationCallJavaConstructorUsages(scope: SearchScope, process: (JetCallElement) -> Unit) {
|
||||||
if (this is KotlinLightElement<*, *>) return
|
if (this is KotlinLightElement<*, *>) return
|
||||||
// TODO: Temporary hack to avoid NPE while KotlinNoOriginLightMethod is around
|
// TODO: Temporary hack to avoid NPE while KotlinNoOriginLightMethod is around
|
||||||
if (this is KotlinNoOriginLightMethod) return
|
if (this is KotlinNoOriginLightMethod) return
|
||||||
@@ -145,7 +145,7 @@ private fun processInheritorsDelegatingCallToSpecifiedConstructor(
|
|||||||
klass: PsiElement,
|
klass: PsiElement,
|
||||||
scope: SearchScope,
|
scope: SearchScope,
|
||||||
descriptor: ConstructorDescriptor,
|
descriptor: ConstructorDescriptor,
|
||||||
process: (JetConstructorDelegationCall) -> Unit
|
process: (JetCallElement) -> Unit
|
||||||
) {
|
) {
|
||||||
HierarchySearchRequest(klass, scope, false).searchInheritors().forEach() {
|
HierarchySearchRequest(klass, scope, false).searchInheritors().forEach() {
|
||||||
val unwrapped = it.unwrapped
|
val unwrapped = it.unwrapped
|
||||||
@@ -156,7 +156,7 @@ private fun processInheritorsDelegatingCallToSpecifiedConstructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun processClassDelegationCallsToSpecifiedConstructor(
|
private fun processClassDelegationCallsToSpecifiedConstructor(
|
||||||
klass: JetClass, constructor: DeclarationDescriptor, process: (JetConstructorDelegationCall) -> Unit
|
klass: JetClass, constructor: DeclarationDescriptor, process: (JetCallElement) -> Unit
|
||||||
) {
|
) {
|
||||||
for (secondaryConstructor in klass.getSecondaryConstructors()) {
|
for (secondaryConstructor in klass.getSecondaryConstructors()) {
|
||||||
val delegationCallDescriptor = secondaryConstructor.getDelegationCall().getConstructorCallDescriptor()
|
val delegationCallDescriptor = secondaryConstructor.getDelegationCall().getConstructorCallDescriptor()
|
||||||
@@ -164,6 +164,15 @@ private fun processClassDelegationCallsToSpecifiedConstructor(
|
|||||||
process(secondaryConstructor.getDelegationCall())
|
process(secondaryConstructor.getDelegationCall())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (!klass.isEnum()) return
|
||||||
|
for (declaration in klass.declarations) {
|
||||||
|
if (declaration is JetEnumEntry) {
|
||||||
|
val delegationCall = declaration.getDelegationSpecifiers().firstOrNull()
|
||||||
|
if (delegationCall is JetDelegatorToSuperCall && constructor == delegationCall.calleeExpression.getConstructorCallDescriptor()) {
|
||||||
|
process(delegationCall)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if reference resolves to extension function whose receiver is the same as declaration's parent (or its superclass)
|
// Check if reference resolves to extension function whose receiver is the same as declaration's parent (or its superclass)
|
||||||
|
|||||||
+15
-7
@@ -252,7 +252,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static void findOneMethodUsages(
|
private static void findOneMethodUsages(
|
||||||
@NotNull JetCallableDefinitionUsage<?> functionUsageInfo,
|
@NotNull final JetCallableDefinitionUsage<?> functionUsageInfo,
|
||||||
final JetChangeInfo changeInfo,
|
final JetChangeInfo changeInfo,
|
||||||
final Set<UsageInfo> result
|
final Set<UsageInfo> result
|
||||||
) {
|
) {
|
||||||
@@ -333,10 +333,16 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
|
|||||||
UsagesSearchPackage.processDelegationCallConstructorUsages(
|
UsagesSearchPackage.processDelegationCallConstructorUsages(
|
||||||
functionPsi,
|
functionPsi,
|
||||||
functionPsi.getUseScope(),
|
functionPsi.getUseScope(),
|
||||||
new Function1<JetConstructorDelegationCall, Unit>() {
|
new Function1<JetCallElement, Unit>() {
|
||||||
@Override
|
@Override
|
||||||
public Unit invoke(JetConstructorDelegationCall element) {
|
public Unit invoke(JetCallElement element) {
|
||||||
result.add(new JetConstructorDelegationCallUsage(element, changeInfo));
|
if (element instanceof JetConstructorDelegationCall) {
|
||||||
|
result.add(new JetConstructorDelegationCallUsage((JetConstructorDelegationCall) element, changeInfo));
|
||||||
|
}
|
||||||
|
else if (element instanceof JetDelegatorToSuperCall) {
|
||||||
|
result.add(new JetFunctionCallUsage(element, functionUsageInfo));
|
||||||
|
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -478,10 +484,12 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
|
|||||||
UsagesSearchPackage.processDelegationCallConstructorUsages(
|
UsagesSearchPackage.processDelegationCallConstructorUsages(
|
||||||
psiMethod,
|
psiMethod,
|
||||||
psiMethod.getUseScope(),
|
psiMethod.getUseScope(),
|
||||||
new Function1<JetConstructorDelegationCall, Unit>() {
|
new Function1<JetCallElement, Unit>() {
|
||||||
@Override
|
@Override
|
||||||
public Unit invoke(JetConstructorDelegationCall element) {
|
public Unit invoke(JetCallElement element) {
|
||||||
result.add(new JavaConstructorDeferredUsageInDelegationCall(element));
|
if (element instanceof JetConstructorDelegationCall) {
|
||||||
|
result.add(new JavaConstructorDeferredUsageInDelegationCall((JetConstructorDelegationCall) element));
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-11
@@ -17,24 +17,18 @@
|
|||||||
package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages
|
package org.jetbrains.kotlin.idea.refactoring.changeSignature.usages
|
||||||
|
|
||||||
import com.intellij.usageView.UsageInfo
|
import com.intellij.usageView.UsageInfo
|
||||||
import org.jetbrains.kotlin.psi.JetEnumEntry
|
|
||||||
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo
|
import org.jetbrains.kotlin.idea.refactoring.changeSignature.JetChangeInfo
|
||||||
import org.jetbrains.kotlin.psi.JetPsiFactory
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.JetClass
|
|
||||||
import org.jetbrains.kotlin.psi.JetDelegatorToSuperCall
|
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
|
||||||
|
|
||||||
public class JetEnumEntryWithoutSuperCallUsage(enumEntry: JetEnumEntry) : JetUsageInfo<JetEnumEntry>(enumEntry) {
|
public class JetEnumEntryWithoutSuperCallUsage(enumEntry: JetEnumEntry) : JetUsageInfo<JetEnumEntry>(enumEntry) {
|
||||||
override fun processUsage(changeInfo: JetChangeInfo, element: JetEnumEntry, allUsages: Array<out UsageInfo>): Boolean {
|
override fun processUsage(changeInfo: JetChangeInfo, element: JetEnumEntry, allUsages: Array<out UsageInfo>): Boolean {
|
||||||
if (changeInfo.getNewParameters().size() > 0) {
|
if (changeInfo.newParameters.size() > 0) {
|
||||||
val psiFactory = JetPsiFactory(element)
|
val psiFactory = JetPsiFactory(element)
|
||||||
|
|
||||||
val enumClass = element.getStrictParentOfType<JetClass>()!!
|
val delegatorToSuperCall = (element.addAfter(
|
||||||
val delegatorToSuperCall = element.addAfter(
|
psiFactory.createEnumEntryInitializerList(),
|
||||||
psiFactory.createDelegatorToSuperCall("${enumClass.getName()}()"),
|
|
||||||
element.getNameAsDeclaration()
|
element.getNameAsDeclaration()
|
||||||
) as JetDelegatorToSuperCall
|
) as JetInitializerList).initializers[0] as JetDelegatorToSuperCall
|
||||||
element.addBefore(psiFactory.createColon(), delegatorToSuperCall)
|
|
||||||
|
|
||||||
return JetFunctionCallUsage(delegatorToSuperCall, changeInfo.methodDescriptor.originalPrimaryCallable)
|
return JetFunctionCallUsage(delegatorToSuperCall, changeInfo.methodDescriptor.originalPrimaryCallable)
|
||||||
.processUsage(changeInfo, delegatorToSuperCall, allUsages)
|
.processUsage(changeInfo, delegatorToSuperCall, allUsages)
|
||||||
|
|||||||
+2
-1
@@ -120,9 +120,10 @@ public class JetFunctionCallUsage extends JetUsageInfo<JetCallElement> {
|
|||||||
|
|
||||||
private boolean shouldSkipUsage(JetCallElement element) {
|
private boolean shouldSkipUsage(JetCallElement element) {
|
||||||
// TODO: We probable need more clever processing of invalid calls, but for now default to Java-like behaviour
|
// TODO: We probable need more clever processing of invalid calls, but for now default to Java-like behaviour
|
||||||
// TODO: Investigate why resolved call is not recorded for enum constructor call
|
|
||||||
if (resolvedCall == null && !(element instanceof JetDelegatorToSuperCall)) return true;
|
if (resolvedCall == null && !(element instanceof JetDelegatorToSuperCall)) return true;
|
||||||
if (resolvedCall != null && !resolvedCall.getStatus().isSuccess()) {
|
if (resolvedCall != null && !resolvedCall.getStatus().isSuccess()) {
|
||||||
|
// TODO: investigate why arguments are not recorded for enum constructor call
|
||||||
|
if (element instanceof JetDelegatorToSuperCall && element.getParent().getParent() instanceof JetEnumEntry) return false;
|
||||||
for (ValueArgument valueArgument : resolvedCall.getCall().getValueArguments()) {
|
for (ValueArgument valueArgument : resolvedCall.getCall().getValueArguments()) {
|
||||||
if (!(resolvedCall.getArgumentMapping(valueArgument) instanceof ArgumentMatch)) return true;
|
if (!(resolvedCall.getArgumentMapping(valueArgument) instanceof ArgumentMatch)) return true;
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+3
-3
@@ -4,9 +4,9 @@
|
|||||||
// ERROR: No value passed for parameter foo
|
// ERROR: No value passed for parameter foo
|
||||||
|
|
||||||
enum class E {
|
enum class E {
|
||||||
A
|
A,
|
||||||
B
|
B,
|
||||||
C
|
C;
|
||||||
|
|
||||||
val t: Int = <caret>foo
|
val t: Int = <caret>foo
|
||||||
}
|
}
|
||||||
+3
-3
@@ -4,9 +4,9 @@
|
|||||||
// ERROR: No value passed for parameter foo
|
// ERROR: No value passed for parameter foo
|
||||||
|
|
||||||
enum class E(foo: Int) {
|
enum class E(foo: Int) {
|
||||||
A : E()
|
A(),
|
||||||
B : E()
|
B(),
|
||||||
C : E()
|
C();
|
||||||
|
|
||||||
val t: Int = foo
|
val t: Int = foo
|
||||||
}
|
}
|
||||||
Vendored
+2
-2
@@ -4,9 +4,9 @@
|
|||||||
// ERROR: No value passed for parameter foo
|
// ERROR: No value passed for parameter foo
|
||||||
|
|
||||||
enum class E {
|
enum class E {
|
||||||
A
|
A,
|
||||||
B {
|
B {
|
||||||
val t: Int = <caret>foo
|
val t: Int = <caret>foo
|
||||||
}
|
},
|
||||||
C
|
C
|
||||||
}
|
}
|
||||||
+4
-4
@@ -4,9 +4,9 @@
|
|||||||
// ERROR: No value passed for parameter foo
|
// ERROR: No value passed for parameter foo
|
||||||
|
|
||||||
enum class E(val foo: Int) {
|
enum class E(val foo: Int) {
|
||||||
A : E()
|
A(),
|
||||||
B : E() {
|
B() {
|
||||||
val t: Int = foo
|
val t: Int = foo
|
||||||
}
|
},
|
||||||
C : E()
|
C()
|
||||||
}
|
}
|
||||||
+2
-2
@@ -1,4 +1,4 @@
|
|||||||
enum class E(n: Int) {
|
enum class E(n: Int) {
|
||||||
A : E(1)
|
A(1),
|
||||||
B : E(1)
|
B(1)
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
enum class <caret>E {
|
enum class <caret>E {
|
||||||
A
|
A,
|
||||||
B
|
B
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user