Change Signature: Check syntactic validity of types. Warn about unresolved types

This commit is contained in:
Alexey Sedunov
2015-12-17 19:07:53 +03:00
parent 784b250de8
commit f745f27694
3 changed files with 45 additions and 23 deletions
@@ -27,7 +27,4 @@ class KtTypeCodeFragment(
context: PsiElement? context: PsiElement?
) : KtCodeFragment(project, name, text, null, KtNodeTypes.TYPE_CODE_FRAGMENT, context) { ) : KtCodeFragment(project, name, text, null, KtNodeTypes.TYPE_CODE_FRAGMENT, context) {
override fun getContentElement() = findChildByClass(KtTypeReference::class.java) override fun getContentElement() = findChildByClass(KtTypeReference::class.java)
val hasTypeReference: Boolean
get() = getContentElement() != null
} }
@@ -22,13 +22,14 @@ import com.intellij.openapi.editor.event.DocumentAdapter
import com.intellij.openapi.editor.event.DocumentEvent import com.intellij.openapi.editor.event.DocumentEvent
import com.intellij.openapi.options.ConfigurationException import com.intellij.openapi.options.ConfigurationException
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.ui.VerticalFlowLayout import com.intellij.openapi.ui.VerticalFlowLayout
import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.util.text.StringUtil
import com.intellij.psi.JavaPsiFacade
import com.intellij.psi.PsiCodeFragment import com.intellij.psi.PsiCodeFragment
import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.refactoring.BaseRefactoringProcessor import com.intellij.refactoring.BaseRefactoringProcessor
import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.changeSignature.ChangeSignatureDialogBase import com.intellij.refactoring.changeSignature.ChangeSignatureDialogBase
import com.intellij.refactoring.changeSignature.MethodDescriptor import com.intellij.refactoring.changeSignature.MethodDescriptor
import com.intellij.refactoring.changeSignature.ParameterTableModelItemBase import com.intellij.refactoring.changeSignature.ParameterTableModelItemBase
@@ -46,9 +47,12 @@ import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.KotlinFileType
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
import org.jetbrains.kotlin.idea.core.refactoring.validateElementAndNotNull
import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringBundle import org.jetbrains.kotlin.idea.refactoring.KotlinRefactoringBundle
import org.jetbrains.kotlin.idea.refactoring.changeSignature.* import org.jetbrains.kotlin.idea.refactoring.changeSignature.*
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinMethodDescriptor.Kind import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinMethodDescriptor.Kind
import org.jetbrains.kotlin.idea.refactoring.validateElement
import org.jetbrains.kotlin.psi.KtExpressionCodeFragment import org.jetbrains.kotlin.psi.KtExpressionCodeFragment
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtTypeCodeFragment import org.jetbrains.kotlin.psi.KtTypeCodeFragment
@@ -329,32 +333,54 @@ public class KotlinChangeSignatureDialog(
validateButtons() validateButtons()
} }
override fun validateAndCommitData() = null override fun validateAndCommitData(): String? {
if (myMethod.canChangeReturnType() == MethodDescriptor.ReadWriteOption.ReadWrite &&
myReturnTypeCodeFragment.getTypeInfo(true, false).type == null) {
if (Messages.showOkCancelDialog(
myProject,
"Return type '${myReturnTypeCodeFragment!!.text}' cannot be resolved.\nContinue?",
RefactoringBundle.message("changeSignature.refactoring.name"),
Messages.getWarningIcon()
) != Messages.OK) {
return ChangeSignatureDialogBase.EXIT_SILENTLY
}
}
for (item in parametersTableModel.items) {
if (item.typeCodeFragment.getTypeInfo(true, false).type == null) {
val paramText = if (item.parameter != parametersTableModel.receiver) "parameter '${item.parameter.name}'" else "receiver"
if (Messages.showOkCancelDialog(
myProject,
"Type '${item.typeCodeFragment.text}' for $paramText cannot be resolved.\nContinue?",
RefactoringBundle.message("changeSignature.refactoring.name"),
Messages.getWarningIcon()
) != Messages.OK) {
return ChangeSignatureDialogBase.EXIT_SILENTLY
}
}
}
return null
}
override fun canRun() { override fun canRun() {
if (myNamePanel.isVisible() if (myNamePanel.isVisible && myMethod.canChangeName() && !KotlinNameSuggester.isIdentifier(methodName)) {
&& myMethod.canChangeName()
&& !JavaPsiFacade.getInstance(myProject).getNameHelper().isIdentifier(getMethodName())) {
throw ConfigurationException(KotlinRefactoringBundle.message("function.name.is.invalid")) throw ConfigurationException(KotlinRefactoringBundle.message("function.name.is.invalid"))
} }
if (myMethod.canChangeReturnType() === MethodDescriptor.ReadWriteOption.ReadWrite && !hasTypeReference(myReturnTypeCodeFragment)) { if (myMethod.canChangeReturnType() === MethodDescriptor.ReadWriteOption.ReadWrite) {
throw ConfigurationException(KotlinRefactoringBundle.message("return.type.is.invalid")) (myReturnTypeCodeFragment as? KtTypeCodeFragment)
?.validateElement(KotlinRefactoringBundle.message("return.type.is.invalid"))
} }
val parameterInfos = parametersTableModel.getItems() for (item in parametersTableModel.items) {
val parameterName = item.parameter.name
for (item in parameterInfos) { if (item.parameter != parametersTableModel.receiver && !KotlinNameSuggester.isIdentifier(parameterName)) {
val parameterName = item.parameter.getName()
if (item.parameter != parametersTableModel.getReceiver()
&& !JavaPsiFacade.getInstance(myProject).getNameHelper().isIdentifier(parameterName)) {
throw ConfigurationException(KotlinRefactoringBundle.message("parameter.name.is.invalid", parameterName)) throw ConfigurationException(KotlinRefactoringBundle.message("parameter.name.is.invalid", parameterName))
} }
if (!hasTypeReference(item.typeCodeFragment)) { (item.typeCodeFragment as? KtTypeCodeFragment)
throw ConfigurationException(KotlinRefactoringBundle.message("parameter.type.is.invalid", item.typeCodeFragment.getText())) ?.validateElement(KotlinRefactoringBundle.message("parameter.type.is.invalid", item.typeCodeFragment.text))
}
} }
} }
@@ -446,8 +472,5 @@ public class KotlinChangeSignatureDialog(
parametersModel.getReceiver(), parametersModel.getReceiver(),
defaultValueContext) defaultValueContext)
} }
private fun hasTypeReference(codeFragment: PsiCodeFragment?): Boolean
= (codeFragment as? KtTypeCodeFragment)?.hasTypeReference ?: false
} }
} }
@@ -676,7 +676,9 @@ public fun (() -> Any).runRefactoringWithPostprocessing(
} }
@Throws(ConfigurationException::class) @Throws(ConfigurationException::class)
public fun KtElement.validateElement(errorMessage: String) { public fun KtElement?.validateElement(errorMessage: String) {
if (this == null) throw ConfigurationException(errorMessage)
try { try {
AnalyzingUtils.checkForSyntacticErrors(this) AnalyzingUtils.checkForSyntacticErrors(this)
} }