Fix 'Redundant qualifier name' warnings & refactoring in idea

This commit is contained in:
Dmitry Gridin
2019-04-09 21:07:31 +07:00
parent 646f325f57
commit f3faae7bb4
50 changed files with 779 additions and 763 deletions
@@ -35,21 +35,21 @@ import javax.swing.JLabel
import javax.swing.JPanel import javax.swing.JPanel
class KotlinGenerateEqualsWizard( class KotlinGenerateEqualsWizard(
project: Project, project: Project,
klass: KtClass, klass: KtClass,
properties: List<KtNamedDeclaration>, properties: List<KtNamedDeclaration>,
needEquals: Boolean, needEquals: Boolean,
needHashCode: Boolean needHashCode: Boolean
) : AbstractGenerateEqualsWizard<KtClass, KtNamedDeclaration, KotlinMemberInfo>( ) : AbstractGenerateEqualsWizard<KtClass, KtNamedDeclaration, KotlinMemberInfo>(
project, KotlinGenerateEqualsWizard.BuilderImpl(klass, properties, needEquals, needHashCode) project, BuilderImpl(klass, properties, needEquals, needHashCode)
) { ) {
private object MemberInfoModelImpl : AbstractMemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>() private object MemberInfoModelImpl : AbstractMemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>()
private class BuilderImpl( private class BuilderImpl(
private val klass: KtClass, private val klass: KtClass,
properties: List<KtNamedDeclaration>, properties: List<KtNamedDeclaration>,
needEquals: Boolean, needEquals: Boolean,
needHashCode: Boolean needHashCode: Boolean
) : AbstractGenerateEqualsWizard.Builder<KtClass, KtNamedDeclaration, KotlinMemberInfo>() { ) : AbstractGenerateEqualsWizard.Builder<KtClass, KtNamedDeclaration, KotlinMemberInfo>() {
private val equalsPanel: KotlinMemberSelectionPanel? private val equalsPanel: KotlinMemberSelectionPanel?
private val hashCodePanel: KotlinMemberSelectionPanel? private val hashCodePanel: KotlinMemberSelectionPanel?
@@ -60,13 +60,13 @@ class KotlinGenerateEqualsWizard(
init { init {
equalsPanel = if (needEquals) { equalsPanel = if (needEquals) {
KotlinMemberSelectionPanel("Choose p&roperties to be included in equals()", memberInfos, null).apply { KotlinMemberSelectionPanel("Choose properties to be included in equals()", memberInfos, null).apply {
table.memberInfoModel = MemberInfoModelImpl table.memberInfoModel = MemberInfoModelImpl
} }
} else null } else null
hashCodePanel = if (needHashCode) { hashCodePanel = if (needHashCode) {
KotlinMemberSelectionPanel("Choose p&roperties to be included in hashCode()", memberInfos, null).apply { KotlinMemberSelectionPanel("Choose properties to be included in hashCode()", memberInfos, null).apply {
table.memberInfoModel = MemberInfoModelImpl table.memberInfoModel = MemberInfoModelImpl
} }
} else null } else null
@@ -31,7 +31,7 @@ import java.awt.datatransfer.DataFlavor
import java.io.Serializable import java.io.Serializable
class KotlinReferenceTransferableData( class KotlinReferenceTransferableData(
val data: Array<KotlinReferenceData> val data: Array<KotlinReferenceData>
) : TextBlockTransferableData, Cloneable, Serializable { ) : TextBlockTransferableData, Cloneable, Serializable {
override fun getFlavor() = KotlinReferenceData.dataFlavor override fun getFlavor() = KotlinReferenceData.dataFlavor
@@ -56,15 +56,15 @@ class KotlinReferenceTransferableData(
return i return i
} }
public override fun clone() = KotlinReferenceTransferableData(Array(data.size, { data[it].clone() })) public override fun clone() = KotlinReferenceTransferableData(Array(data.size) { data[it].clone() })
} }
class KotlinReferenceData( class KotlinReferenceData(
var startOffset: Int, var startOffset: Int,
var endOffset: Int, var endOffset: Int,
val fqName: String, val fqName: String,
val isQualifiable: Boolean, val isQualifiable: Boolean,
val kind: KotlinReferenceData.Kind val kind: Kind
) : Cloneable, Serializable { ) : Cloneable, Serializable {
enum class Kind { enum class Kind {
@@ -87,8 +87,7 @@ class KotlinReferenceData(
public override fun clone(): KotlinReferenceData { public override fun clone(): KotlinReferenceData {
try { try {
return super.clone() as KotlinReferenceData return super.clone() as KotlinReferenceData
} } catch (e: CloneNotSupportedException) {
catch (e: CloneNotSupportedException) {
throw RuntimeException() throw RuntimeException()
} }
} }
@@ -97,14 +96,14 @@ class KotlinReferenceData(
val dataFlavor: DataFlavor? by lazy { val dataFlavor: DataFlavor? by lazy {
try { try {
val dataClass = KotlinReferenceData::class.java val dataClass = KotlinReferenceData::class.java
DataFlavor(DataFlavor.javaJVMLocalObjectMimeType + ";class=" + dataClass.name, DataFlavor(
"KotlinReferenceData", DataFlavor.javaJVMLocalObjectMimeType + ";class=" + dataClass.name,
dataClass.classLoader) "KotlinReferenceData",
} dataClass.classLoader
catch (e: NoClassDefFoundError) { )
} catch (e: NoClassDefFoundError) {
null null
} } catch (e: IllegalArgumentException) {
catch (e: IllegalArgumentException) {
null null
} }
} }
@@ -28,7 +28,7 @@ import org.jetbrains.kotlin.psi.*
class KotlinSpellcheckingStrategy : SpellcheckingStrategy() { class KotlinSpellcheckingStrategy : SpellcheckingStrategy() {
private val plainTextTokenizer = TokenizerBase<KtLiteralStringTemplateEntry>(PlainTextSplitter.getInstance()) private val plainTextTokenizer = TokenizerBase<KtLiteralStringTemplateEntry>(PlainTextSplitter.getInstance())
private val emptyTokenizer = SpellcheckingStrategy.EMPTY_TOKENIZER private val emptyTokenizer = EMPTY_TOKENIZER
override fun getTokenizer(element: PsiElement?): Tokenizer<out PsiElement?> { override fun getTokenizer(element: PsiElement?): Tokenizer<out PsiElement?> {
return when (element) { return when (element) {
@@ -44,7 +44,7 @@ class KotlinMigrationProjectComponent(val project: Project) {
init { init {
val connection = project.messageBus.connect() val connection = project.messageBus.connect()
connection.subscribe(ProjectDataImportListener.TOPIC, ProjectDataImportListener { connection.subscribe(ProjectDataImportListener.TOPIC, ProjectDataImportListener {
KotlinMigrationProjectComponent.getInstanceIfNotDisposed(project)?.onImportFinished() getInstanceIfNotDisposed(project)?.onImportFinished()
}) })
} }
@@ -165,8 +165,7 @@ class KotlinMigrationProjectComponent(val project: Project) {
val changedFiles = ChangeListManager.getInstance(project).affectedPaths val changedFiles = ChangeListManager.getInstance(project).affectedPaths
for (changedFile in changedFiles) { for (changedFile in changedFiles) {
val extension = changedFile.extension when (changedFile.extension) {
when (extension) {
"gradle" -> return true "gradle" -> return true
"properties" -> return true "properties" -> return true
"kts" -> return true "kts" -> return true
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.idea.editor package org.jetbrains.kotlin.idea.editor
import com.intellij.codeInsight.CodeInsightSettings import com.intellij.codeInsight.CodeInsightSettings
import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegate
import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegate.Result import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegate.Result
import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegateAdapter import com.intellij.codeInsight.editorActions.enter.EnterHandlerDelegateAdapter
import com.intellij.injected.editor.EditorWindow import com.intellij.injected.editor.EditorWindow
@@ -55,7 +54,7 @@ class KotlinMultilineStringEnterHandler : EnterHandlerDelegateAdapter() {
override fun preprocessEnter( override fun preprocessEnter(
file: PsiFile, editor: Editor, caretOffset: Ref<Int>, caretAdvance: Ref<Int>, dataContext: DataContext, file: PsiFile, editor: Editor, caretOffset: Ref<Int>, caretAdvance: Ref<Int>, dataContext: DataContext,
originalHandler: EditorActionHandler? originalHandler: EditorActionHandler?
): EnterHandlerDelegate.Result { ): Result {
val offset = caretOffset.get().toInt() val offset = caretOffset.get().toInt()
if (editor !is EditorWindow) { if (editor !is EditorWindow) {
return preprocessEnter(file, editor, offset, originalHandler, dataContext) return preprocessEnter(file, editor, offset, originalHandler, dataContext)
@@ -194,7 +193,7 @@ class KotlinMultilineStringEnterHandler : EnterHandlerDelegateAdapter() {
val marginCharToInsert = if (marginChar != null && val marginCharToInsert = if (marginChar != null &&
!prefixStripped.startsWith(marginChar) && !prefixStripped.startsWith(marginChar) &&
!nonBlankNotFirstLines.isEmpty() && nonBlankNotFirstLines.isNotEmpty() &&
nonBlankNotFirstLines.none { it.trimStart().startsWith(marginChar) } nonBlankNotFirstLines.none { it.trimStart().startsWith(marginChar) }
) { ) {
@@ -242,11 +241,11 @@ class KotlinMultilineStringEnterHandler : EnterHandlerDelegateAdapter() {
} }
companion object { companion object {
val DEFAULT_TRIM_MARGIN_CHAR = '|' const val DEFAULT_TRIM_MARGIN_CHAR = '|'
val TRIM_INDENT_CALL = "trimIndent" const val TRIM_INDENT_CALL = "trimIndent"
val TRIM_MARGIN_CALL = "trimMargin" const val TRIM_MARGIN_CALL = "trimMargin"
val MULTILINE_QUOTE = "\"\"\"" const val MULTILINE_QUOTE = "\"\"\""
class MultilineSettings(project: Project) { class MultilineSettings(project: Project) {
private val kotlinIndentOptions = private val kotlinIndentOptions =
@@ -286,7 +285,7 @@ class KotlinMultilineStringEnterHandler : EnterHandlerDelegateAdapter() {
else -> return null else -> return null
} }
return element.parents.firstIsInstanceOrNull<KtStringTemplateExpression>() return element.parents.firstIsInstanceOrNull()
} }
fun inMultilineString(element: PsiElement?, offset: Int) = fun inMultilineString(element: PsiElement?, offset: Int) =
@@ -54,9 +54,9 @@ class KotlinCodeBlockSelectioner : ExtendWordSelectionHandlerBase() {
val start = findBlockContentStart(block) val start = findBlockContentStart(block)
val end = findBlockContentEnd(block) val end = findBlockContentEnd(block)
if (end > start) { if (end > start) {
result.addAll(ExtendWordSelectionHandlerBase.expandToWholeLine(editorText, TextRange(start, end))) result.addAll(expandToWholeLine(editorText, TextRange(start, end)))
} }
result.addAll(ExtendWordSelectionHandlerBase.expandToWholeLine(editorText, block.textRange!!)) result.addAll(expandToWholeLine(editorText, block.textRange!!))
return result return result
} }
@@ -26,6 +26,6 @@ class KotlinDocCommentSelectioner : ExtendWordSelectionHandlerBase() {
override fun canSelect(e: PsiElement) = e is KDoc override fun canSelect(e: PsiElement) = e is KDoc
override fun select(e: PsiElement, editorText: CharSequence, cursorOffset: Int, editor: Editor): List<TextRange>? { override fun select(e: PsiElement, editorText: CharSequence, cursorOffset: Int, editor: Editor): List<TextRange>? {
return ExtendWordSelectionHandlerBase.expandToWholeLine(editorText, e.textRange) return expandToWholeLine(editorText, e.textRange)
} }
} }
@@ -18,8 +18,8 @@ import kotlin.reflect.KProperty
class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvider() { class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvider() {
override fun getLanguage() = KotlinLanguage.INSTANCE override fun getLanguage() = KotlinLanguage.INSTANCE
override fun getCodeSample(settingsType: LanguageCodeStyleSettingsProvider.SettingsType): String = when (settingsType) { override fun getCodeSample(settingsType: SettingsType): String = when (settingsType) {
LanguageCodeStyleSettingsProvider.SettingsType.WRAPPING_AND_BRACES_SETTINGS -> SettingsType.WRAPPING_AND_BRACES_SETTINGS ->
""" """
@Deprecated("Foo") public class ThisIsASampleClass : Comparable<*>, Appendable { @Deprecated("Foo") public class ThisIsASampleClass : Comparable<*>, Appendable {
val test = val test =
@@ -71,7 +71,7 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
fun veryLongExpressionBodyMethod() = "abc" fun veryLongExpressionBodyMethod() = "abc"
""".trimIndent() """.trimIndent()
LanguageCodeStyleSettingsProvider.SettingsType.BLANK_LINES_SETTINGS -> SettingsType.BLANK_LINES_SETTINGS ->
""" """
class Foo { class Foo {
private var field1: Int = 1 private var field1: Int = 1
@@ -169,13 +169,13 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
override fun getLanguageName(): String = KotlinLanguage.NAME override fun getLanguageName(): String = KotlinLanguage.NAME
override fun customizeSettings(consumer: CodeStyleSettingsCustomizable, settingsType: LanguageCodeStyleSettingsProvider.SettingsType) { override fun customizeSettings(consumer: CodeStyleSettingsCustomizable, settingsType: SettingsType) {
fun showCustomOption(field: KProperty<*>, title: String, groupName: String? = null, vararg options: Any) { fun showCustomOption(field: KProperty<*>, title: String, groupName: String? = null, vararg options: Any) {
consumer.showCustomOption(KotlinCodeStyleSettings::class.java, field.name, title, groupName, *options) consumer.showCustomOption(KotlinCodeStyleSettings::class.java, field.name, title, groupName, *options)
} }
when (settingsType) { when (settingsType) {
LanguageCodeStyleSettingsProvider.SettingsType.SPACING_SETTINGS -> { SettingsType.SPACING_SETTINGS -> {
consumer.showStandardOptions( consumer.showStandardOptions(
"SPACE_AROUND_ASSIGNMENT_OPERATORS", "SPACE_AROUND_ASSIGNMENT_OPERATORS",
"SPACE_AROUND_LOGICAL_OPERATORS", "SPACE_AROUND_LOGICAL_OPERATORS",
@@ -190,7 +190,7 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
"SPACE_BEFORE_WHILE_PARENTHESES", "SPACE_BEFORE_WHILE_PARENTHESES",
"SPACE_BEFORE_FOR_PARENTHESES", "SPACE_BEFORE_FOR_PARENTHESES",
"SPACE_BEFORE_CATCH_PARENTHESES" "SPACE_BEFORE_CATCH_PARENTHESES"
); )
showCustomOption( showCustomOption(
KotlinCodeStyleSettings::SPACE_AROUND_RANGE, KotlinCodeStyleSettings::SPACE_AROUND_RANGE,
@@ -252,7 +252,7 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
CodeStyleSettingsCustomizable.SPACES_BEFORE_PARENTHESES CodeStyleSettingsCustomizable.SPACES_BEFORE_PARENTHESES
) )
} }
LanguageCodeStyleSettingsProvider.SettingsType.WRAPPING_AND_BRACES_SETTINGS -> { SettingsType.WRAPPING_AND_BRACES_SETTINGS -> {
consumer.showStandardOptions( consumer.showStandardOptions(
// "ALIGN_MULTILINE_CHAINED_METHODS", // "ALIGN_MULTILINE_CHAINED_METHODS",
"RIGHT_MARGIN", "RIGHT_MARGIN",
@@ -364,7 +364,7 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
CodeStyleSettingsCustomizable.WRAPPING_IF_STATEMENT CodeStyleSettingsCustomizable.WRAPPING_IF_STATEMENT
) )
} }
LanguageCodeStyleSettingsProvider.SettingsType.BLANK_LINES_SETTINGS -> { SettingsType.BLANK_LINES_SETTINGS -> {
consumer.showStandardOptions( consumer.showStandardOptions(
"KEEP_BLANK_LINES_IN_CODE", "KEEP_BLANK_LINES_IN_CODE",
"KEEP_BLANK_LINES_IN_DECLARATIONS", "KEEP_BLANK_LINES_IN_DECLARATIONS",
@@ -377,8 +377,8 @@ class KotlinLanguageCodeStyleSettingsProvider : LanguageCodeStyleSettingsProvide
CodeStyleSettingsCustomizable.BLANK_LINES CodeStyleSettingsCustomizable.BLANK_LINES
) )
} }
LanguageCodeStyleSettingsProvider.SettingsType.COMMENTER_SETTINGS -> { SettingsType.COMMENTER_SETTINGS -> {
consumer.showAllStandardOptions(); consumer.showAllStandardOptions()
} }
else -> consumer.showStandardOptions() else -> consumer.showStandardOptions()
} }
@@ -16,8 +16,8 @@
package org.jetbrains.kotlin.idea.goto package org.jetbrains.kotlin.idea.goto
import com.intellij.ide.util.DefaultPsiElementCellRenderer
import com.intellij.ide.util.PlatformModuleRendererFactory import com.intellij.ide.util.PlatformModuleRendererFactory
import com.intellij.ide.util.PsiElementListCellRenderer
import com.intellij.ide.util.gotoByName.GotoFileCellRenderer import com.intellij.ide.util.gotoByName.GotoFileCellRenderer
import com.intellij.navigation.NavigationItem import com.intellij.navigation.NavigationItem
import com.intellij.openapi.util.Iconable import com.intellij.openapi.util.Iconable
@@ -30,7 +30,6 @@ import com.intellij.ui.ColoredListCellRenderer
import com.intellij.ui.JBColor import com.intellij.ui.JBColor
import com.intellij.ui.SimpleTextAttributes import com.intellij.ui.SimpleTextAttributes
import com.intellij.util.ui.FilePathSplittingPolicy import com.intellij.util.ui.FilePathSplittingPolicy
import com.intellij.ide.util.DefaultPsiElementCellRenderer
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.psi.KtNamedFunction import org.jetbrains.kotlin.psi.KtNamedFunction
@@ -58,8 +57,8 @@ internal class KotlinSearchEverywherePsiRenderer(private val myList: JList<*>) :
layout = object : BorderLayout() { layout = object : BorderLayout() {
override fun layoutContainer(target: Container) { override fun layoutContainer(target: Container) {
super.layoutContainer(target) super.layoutContainer(target)
val right = getLayoutComponent(BorderLayout.EAST) val right = getLayoutComponent(EAST)
val left = getLayoutComponent(BorderLayout.WEST) val left = getLayoutComponent(WEST)
//IDEA-140824 //IDEA-140824
if (right != null && left != null && left.bounds.x + left.bounds.width > right.bounds.x) { if (right != null && left != null && left.bounds.x + left.bounds.width > right.bounds.x) {
@@ -96,10 +95,10 @@ internal class KotlinSearchEverywherePsiRenderer(private val myList: JList<*>) :
var width = myList.width var width = myList.width
if (width == 0) width += 800 if (width == 0) width += 800
val path = FilePathSplittingPolicy.SPLIT_BY_SEPARATOR.getOptimalTextForComponent( val path = FilePathSplittingPolicy.SPLIT_BY_SEPARATOR.getOptimalTextForComponent(
name, name,
File(relativePath), File(relativePath),
this, this,
width - myRightComponentWidth - 16 - 10 width - myRightComponentWidth - 16 - 10
) )
return "($path)" return "($path)"
} }
@@ -37,7 +37,7 @@ import javax.swing.JPanel
import javax.swing.JTree import javax.swing.JTree
class KotlinOverrideHierarchyBrowser( class KotlinOverrideHierarchyBrowser(
project: Project, baseElement: PsiElement project: Project, baseElement: PsiElement
) : MethodHierarchyBrowserBase(project, baseElement) { ) : MethodHierarchyBrowserBase(project, baseElement) {
override fun createTrees(trees: MutableMap<String, JTree>) { override fun createTrees(trees: MutableMap<String, JTree>) {
val actionManager = ActionManager.getInstance() val actionManager = ActionManager.getInstance()
@@ -49,25 +49,25 @@ class KotlinOverrideHierarchyBrowser(
BaseOnThisMethodAction().registerCustomShortcutSet(actionManager.getAction(IdeActions.ACTION_METHOD_HIERARCHY).shortcutSet, tree) BaseOnThisMethodAction().registerCustomShortcutSet(actionManager.getAction(IdeActions.ACTION_METHOD_HIERARCHY).shortcutSet, tree)
trees.put(MethodHierarchyBrowserBase.METHOD_TYPE, tree) trees[METHOD_TYPE] = tree
} }
override fun createLegendPanel(): JPanel? = override fun createLegendPanel(): JPanel? =
MethodHierarchyBrowserBase.createStandardLegendPanel( createStandardLegendPanel(
KotlinBundle.message("hierarchy.legend.member.is.defined.in.class"), KotlinBundle.message("hierarchy.legend.member.is.defined.in.class"),
KotlinBundle.message("hierarchy.legend.member.defined.in.superclass"), KotlinBundle.message("hierarchy.legend.member.defined.in.superclass"),
KotlinBundle.message("hierarchy.legend.member.should.be.defined") KotlinBundle.message("hierarchy.legend.member.should.be.defined")
) )
override fun getElementFromDescriptor(descriptor: HierarchyNodeDescriptor) = descriptor.psiElement override fun getElementFromDescriptor(descriptor: HierarchyNodeDescriptor) = descriptor.psiElement
override fun isApplicableElement(psiElement: PsiElement): Boolean = override fun isApplicableElement(psiElement: PsiElement): Boolean =
psiElement.isOverrideHierarchyElement() psiElement.isOverrideHierarchyElement()
override fun createHierarchyTreeStructure(typeName: String, psiElement: PsiElement): HierarchyTreeStructure? = override fun createHierarchyTreeStructure(typeName: String, psiElement: PsiElement): HierarchyTreeStructure? =
if (typeName == MethodHierarchyBrowserBase.METHOD_TYPE) KotlinOverrideTreeStructure(myProject, psiElement as KtCallableDeclaration) else null if (typeName == METHOD_TYPE) KotlinOverrideTreeStructure(myProject, psiElement as KtCallableDeclaration) else null
override fun getComparator() = JavaHierarchyUtil.getComparator(myProject)!! override fun getComparator() = JavaHierarchyUtil.getComparator(myProject)
override fun getContentDisplayName(typeName: String, element: PsiElement): String? { override fun getContentDisplayName(typeName: String, element: PsiElement): String? {
val targetElement = element.unwrapped val targetElement = element.unwrapped
@@ -28,8 +28,8 @@ import com.intellij.psi.PsiMember
import com.intellij.ui.LayeredIcon import com.intellij.ui.LayeredIcon
import com.intellij.ui.RowIcon import com.intellij.ui.RowIcon
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMemberDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor import org.jetbrains.kotlin.idea.caches.resolve.unsafeResolveToDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaMemberDescriptor
import org.jetbrains.kotlin.psi.KtNamedDeclaration import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -39,10 +39,10 @@ import org.jetbrains.kotlin.util.findCallableMemberBySignature
import java.awt.Font import java.awt.Font
import javax.swing.Icon import javax.swing.Icon
class KotlinOverrideHierarchyNodeDescriptor ( class KotlinOverrideHierarchyNodeDescriptor(
parentNode: HierarchyNodeDescriptor?, parentNode: HierarchyNodeDescriptor?,
klass: PsiElement, klass: PsiElement,
baseElement: PsiElement baseElement: PsiElement
) : HierarchyNodeDescriptor(klass.project, parentNode, klass, parentNode == null) { ) : HierarchyNodeDescriptor(klass.project, parentNode, klass, parentNode == null) {
private val baseElement = baseElement.createSmartPointer() private val baseElement = baseElement.createSmartPointer()
@@ -79,7 +79,8 @@ class KotlinOverrideHierarchyNodeDescriptor (
} }
val isAbstractClass = classDescriptor.modality == Modality.ABSTRACT val isAbstractClass = classDescriptor.modality == Modality.ABSTRACT
val hasBaseImplementation = DescriptorUtils.getAllOverriddenDeclarations(callableDescriptor).any { it.modality != Modality.ABSTRACT } val hasBaseImplementation =
DescriptorUtils.getAllOverriddenDeclarations(callableDescriptor).any { it.modality != Modality.ABSTRACT }
return if (isAbstractClass || hasBaseImplementation) AllIcons.Hierarchy.MethodNotDefined else AllIcons.Hierarchy.ShouldDefineMethod return if (isAbstractClass || hasBaseImplementation) AllIcons.Hierarchy.MethodNotDefined else AllIcons.Hierarchy.ShouldDefineMethod
} }
@@ -115,7 +116,7 @@ class KotlinOverrideHierarchyNodeDescriptor (
if (myIsBase) { if (myIsBase) {
val icon = LayeredIcon(2) val icon = LayeredIcon(2)
icon.setIcon(newIcon, 0) icon.setIcon(newIcon, 0)
icon.setIcon(AllIcons.Hierarchy.Base, 1, -AllIcons.Hierarchy.Base.iconWidth / 2, 0) icon.setIcon(AllIcons.Actions.Forward, 1, -AllIcons.Actions.Forward.iconWidth / 2, 0)
newIcon = icon newIcon = icon
} }
@@ -134,7 +135,7 @@ class KotlinOverrideHierarchyNodeDescriptor (
classNameAttributes = TextAttributes(myColor, null, null, null, Font.PLAIN) classNameAttributes = TextAttributes(myColor, null, null, null, Font.PLAIN)
} }
with (myHighlightedText.ending) { with(myHighlightedText.ending) {
addText(classDescriptor.name.asString(), classNameAttributes) addText(classDescriptor.name.asString(), classNameAttributes)
classDescriptor.parents.forEach { parentDescriptor -> classDescriptor.parents.forEach { parentDescriptor ->
when (parentDescriptor) { when (parentDescriptor) {
@@ -145,7 +146,7 @@ class KotlinOverrideHierarchyNodeDescriptor (
} }
} }
is PackageFragmentDescriptor -> { is PackageFragmentDescriptor -> {
addText(" (${parentDescriptor.fqName.asString()})", HierarchyNodeDescriptor.getPackageNameAttributes()) addText(" (${parentDescriptor.fqName.asString()})", getPackageNameAttributes())
return@forEach return@forEach
} }
} }
@@ -36,7 +36,7 @@ class KotlinRunLineMarkerContributor : RunLineMarkerContributor() {
val platform = function.containingKtFile.module?.platform ?: return null val platform = function.containingKtFile.module?.platform ?: return null
if (!platform.kind.tooling.acceptsAsEntryPoint(function)) return null if (!platform.kind.tooling.acceptsAsEntryPoint(function)) return null
return RunLineMarkerContributor.Info(AllIcons.RunConfigurations.TestState.Run, null, ExecutorAction.getActions(0)) return Info(AllIcons.RunConfigurations.TestState.Run, null, ExecutorAction.getActions(0))
} }
return null return null
@@ -40,8 +40,7 @@ class KotlinTestRunLineMarkerContributor : RunLineMarkerContributor() {
fun getTestStateIcon(url: String, project: Project): Icon? { fun getTestStateIcon(url: String, project: Project): Icon? {
val defaultIcon = AllIcons.RunConfigurations.TestState.Run val defaultIcon = AllIcons.RunConfigurations.TestState.Run
val state = TestStateStorage.getInstance(project).getState(url) ?: return defaultIcon val state = TestStateStorage.getInstance(project).getState(url) ?: return defaultIcon
val magnitude = TestIconMapper.getMagnitude(state.magnitude) return when (TestIconMapper.getMagnitude(state.magnitude)) {
return when (magnitude) {
TestStateInfo.Magnitude.ERROR_INDEX, TestStateInfo.Magnitude.ERROR_INDEX,
TestStateInfo.Magnitude.FAILED_INDEX -> AllIcons.RunConfigurations.TestState.Red2 TestStateInfo.Magnitude.FAILED_INDEX -> AllIcons.RunConfigurations.TestState.Red2
TestStateInfo.Magnitude.PASSED_INDEX, TestStateInfo.Magnitude.PASSED_INDEX,
@@ -51,7 +50,7 @@ class KotlinTestRunLineMarkerContributor : RunLineMarkerContributor() {
} }
} }
override fun getInfo(element: PsiElement): RunLineMarkerContributor.Info? { override fun getInfo(element: PsiElement): Info? {
val declaration = element.getStrictParentOfType<KtNamedDeclaration>() ?: return null val declaration = element.getStrictParentOfType<KtNamedDeclaration>() ?: return null
if (declaration.nameIdentifier != element) return null if (declaration.nameIdentifier != element) return null
@@ -64,6 +63,6 @@ class KotlinTestRunLineMarkerContributor : RunLineMarkerContributor() {
val targetPlatform = declaration.module?.platform ?: return null val targetPlatform = declaration.module?.platform ?: return null
val icon = targetPlatform.kind.tooling.getTestIcon(declaration, descriptor) ?: return null val icon = targetPlatform.kind.tooling.getTestIcon(declaration, descriptor) ?: return null
return RunLineMarkerContributor.Info(icon, { "Run Test" }, ExecutorAction.getActions()) return Info(icon, { "Run Test" }, ExecutorAction.getActions())
} }
} }
@@ -26,15 +26,18 @@ class RecursivePropertyAccessorInspection : AbstractKotlinInspection() {
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
return simpleNameExpressionVisitor { expression -> return simpleNameExpressionVisitor { expression ->
if (isRecursivePropertyAccess(expression)) { if (isRecursivePropertyAccess(expression)) {
holder.registerProblem(expression, holder.registerProblem(
"Recursive property accessor", expression,
ProblemHighlightType.GENERIC_ERROR_OR_WARNING, "Recursive property accessor",
ReplaceWithFieldFix()) ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
} ReplaceWithFieldFix()
else if (isRecursiveSyntheticPropertyAccess(expression)) { )
holder.registerProblem(expression, } else if (isRecursiveSyntheticPropertyAccess(expression)) {
"Recursive synthetic property accessor", holder.registerProblem(
ProblemHighlightType.GENERIC_ERROR_OR_WARNING) expression,
"Recursive synthetic property accessor",
ProblemHighlightType.GENERIC_ERROR_OR_WARNING
)
} }
} }
} }
@@ -55,7 +58,7 @@ class RecursivePropertyAccessorInspection : AbstractKotlinInspection() {
companion object { companion object {
private fun KtBinaryExpression?.isAssignmentTo(expression: KtSimpleNameExpression): Boolean = private fun KtBinaryExpression?.isAssignmentTo(expression: KtSimpleNameExpression): Boolean =
this != null && KtPsiUtil.isAssignment(this) && PsiTreeUtil.isAncestor(left, expression, false) this != null && KtPsiUtil.isAssignment(this) && PsiTreeUtil.isAncestor(left, expression, false)
private fun isSameAccessor(expression: KtSimpleNameExpression, isGetter: Boolean): Boolean { private fun isSameAccessor(expression: KtSimpleNameExpression, isGetter: Boolean): Boolean {
val binaryExpr = expression.getStrictParentOfType<KtBinaryExpression>() val binaryExpr = expression.getStrictParentOfType<KtBinaryExpression>()
@@ -64,8 +67,7 @@ class RecursivePropertyAccessorInspection : AbstractKotlinInspection() {
return KtTokens.AUGMENTED_ASSIGNMENTS.contains(binaryExpr?.operationToken) return KtTokens.AUGMENTED_ASSIGNMENTS.contains(binaryExpr?.operationToken)
} }
return true return true
} } else /* isSetter */ {
else /* isSetter */ {
if (binaryExpr.isAssignmentTo(expression)) { if (binaryExpr.isAssignmentTo(expression)) {
return true return true
} }
@@ -84,7 +86,7 @@ class RecursivePropertyAccessorInspection : AbstractKotlinInspection() {
if (element.parent is KtCallableReferenceExpression) return false if (element.parent is KtCallableReferenceExpression) return false
val bindingContext = element.analyze() val bindingContext = element.analyze()
val target = bindingContext[REFERENCE_TARGET, element] val target = bindingContext[REFERENCE_TARGET, element]
if (target != bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, propertyAccessor.property]) return false if (target != bindingContext[DECLARATION_TO_DESCRIPTOR, propertyAccessor.property]) return false
(element.parent as? KtQualifiedExpression)?.let { (element.parent as? KtQualifiedExpression)?.let {
if (it.receiverExpression.text != KtTokens.THIS_KEYWORD.value && !it.hasObjectReceiver(bindingContext)) return false if (it.receiverExpression.text != KtTokens.THIS_KEYWORD.value && !it.hasObjectReceiver(bindingContext)) return false
} }
@@ -104,11 +106,12 @@ class RecursivePropertyAccessorInspection : AbstractKotlinInspection() {
val syntheticDescriptor = bindingContext[REFERENCE_TARGET, element] as? SyntheticJavaPropertyDescriptor ?: return false val syntheticDescriptor = bindingContext[REFERENCE_TARGET, element] as? SyntheticJavaPropertyDescriptor ?: return false
val namedFunctionDescriptor = bindingContext[DECLARATION_TO_DESCRIPTOR, namedFunction] val namedFunctionDescriptor = bindingContext[DECLARATION_TO_DESCRIPTOR, namedFunction]
if (namedFunctionDescriptor != syntheticDescriptor.getMethod && if (namedFunctionDescriptor != syntheticDescriptor.getMethod &&
namedFunctionDescriptor != syntheticDescriptor.setMethod) return false namedFunctionDescriptor != syntheticDescriptor.setMethod
) return false
return isSameAccessor(element, isGetter) return isSameAccessor(element, isGetter)
} }
private fun KtQualifiedExpression.hasObjectReceiver(context: BindingContext) : Boolean { private fun KtQualifiedExpression.hasObjectReceiver(context: BindingContext): Boolean {
val receiver = receiverExpression as? KtReferenceExpression ?: return false val receiver = receiverExpression as? KtReferenceExpression ?: return false
return (context[REFERENCE_TARGET, receiver] as? ClassDescriptor)?.kind == ClassKind.OBJECT return (context[REFERENCE_TARGET, receiver] as? ClassDescriptor)?.kind == ClassKind.OBJECT
} }
@@ -88,7 +88,7 @@ class ReformatInspection : LocalInspectionTool() {
} }
private fun isEmptyLineReformat(whitespace: PsiWhiteSpace, change: FormattingChange): Boolean { private fun isEmptyLineReformat(whitespace: PsiWhiteSpace, change: FormattingChange): Boolean {
if (change !is FormattingChange.ReplaceWhiteSpace) return false if (change !is ReplaceWhiteSpace) return false
val beforeText = whitespace.text val beforeText = whitespace.text
val afterText = change.whiteSpace val afterText = change.whiteSpace
@@ -55,7 +55,7 @@ class FoldInitializerAndIfToElvisIntention :
} }
override fun applyTo(element: KtIfExpression, editor: Editor?) { override fun applyTo(element: KtIfExpression, editor: Editor?) {
val newElvis = FoldInitializerAndIfToElvisIntention.applyTo(element) val newElvis = applyTo(element)
editor?.caretModel?.moveToOffset(newElvis.right!!.textOffset) editor?.caretModel?.moveToOffset(newElvis.right!!.textOffset)
} }
@@ -29,16 +29,16 @@ import org.jetbrains.kotlin.kdoc.lexer.KDocTokens
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
class KDocTypedHandler : TypedHandlerDelegate() { class KDocTypedHandler : TypedHandlerDelegate() {
override fun beforeCharTyped(c: Char, project: Project, editor: Editor, file: PsiFile, fileType: FileType): TypedHandlerDelegate.Result { override fun beforeCharTyped(c: Char, project: Project, editor: Editor, file: PsiFile, fileType: FileType): Result {
if (overwriteClosingBracket(c, editor, file)) { if (overwriteClosingBracket(c, editor, file)) {
EditorModificationUtil.moveCaretRelatively(editor, 1) EditorModificationUtil.moveCaretRelatively(editor, 1)
return TypedHandlerDelegate.Result.STOP return Result.STOP
} }
return TypedHandlerDelegate.Result.CONTINUE return Result.CONTINUE
} }
override fun charTyped(c: Char, project: Project, editor: Editor, file: PsiFile): TypedHandlerDelegate.Result = override fun charTyped(c: Char, project: Project, editor: Editor, file: PsiFile): Result =
if (handleBracketTyped(c, project, editor, file)) TypedHandlerDelegate.Result.STOP else TypedHandlerDelegate.Result.CONTINUE if (handleBracketTyped(c, project, editor, file)) Result.STOP else Result.CONTINUE
private fun overwriteClosingBracket(c: Char, editor: Editor, file: PsiFile): Boolean { private fun overwriteClosingBracket(c: Char, editor: Editor, file: PsiFile): Boolean {
if (c != ']' && c != ')') return false if (c != ']' && c != ')') return false
@@ -18,11 +18,11 @@ interface Template<in TOuter> {
* A placeholder that is inserted inside [TOuter] * A placeholder that is inserted inside [TOuter]
*/ */
open class Placeholder<TOuter> { open class Placeholder<TOuter> {
private var contentStack = mutableListOf<(TOuter.(Placeholder<TOuter>.Exec) -> Unit)>() private var contentStack = mutableListOf<(TOuter.(Exec) -> Unit)>()
var meta: String = "" var meta: String = ""
operator fun invoke(meta: String = "", content: TOuter.(Placeholder<TOuter>.Exec) -> Unit) { operator fun invoke(meta: String = "", content: TOuter.(Exec) -> Unit) {
this.contentStack.add(content) this.contentStack.add(content)
this.meta = meta this.meta = meta
} }
@@ -48,10 +48,10 @@ open class Placeholder<TOuter> {
/** /**
* Placeholder that can appear multiple times * Placeholder that can appear multiple times
*/ */
open class PlaceholderList<TOuter, TInner>() { open class PlaceholderList<TOuter, TInner> {
private var items = ArrayList<PlaceholderItem<TInner>>() private var items = ArrayList<PlaceholderItem<TInner>>()
operator fun invoke(meta: String = "", content: TInner.(Placeholder<TInner>.Exec) -> Unit = {}) { operator fun invoke(meta: String = "", content: TInner.(Placeholder<TInner>.Exec) -> Unit = {}) {
val placeholder = PlaceholderItem<TInner>(items.size, items) val placeholder = PlaceholderItem(items.size, items)
placeholder(meta, content) placeholder(meta, content)
items.add(placeholder) items.add(placeholder)
} }
@@ -76,7 +76,7 @@ class PlaceholderItem<TOuter>(val index: Int, val collection: List<PlaceholderIt
/** /**
* Inserts every element of placeholder list * Inserts every element of placeholder list
*/ */
fun <TOuter, TInner> TOuter.each(items: PlaceholderList<TOuter, TInner>, itemTemplate: TOuter.(PlaceholderItem<TInner>) -> Unit): Unit { fun <TOuter, TInner> TOuter.each(items: PlaceholderList<TOuter, TInner>, itemTemplate: TOuter.(PlaceholderItem<TInner>) -> Unit) {
items.apply(this, itemTemplate) items.apply(this, itemTemplate)
} }
@@ -101,10 +101,10 @@ open class TemplatePlaceholder<TTemplate> {
fun <TTemplate : Template<TOuter>, TOuter> TOuter.insert(template: TTemplate, placeholder: TemplatePlaceholder<TTemplate>) { fun <TTemplate : Template<TOuter>, TOuter> TOuter.insert(template: TTemplate, placeholder: TemplatePlaceholder<TTemplate>) {
placeholder.apply(template) placeholder.apply(template)
with (template) { apply() } with(template) { apply() }
} }
fun <TOuter, TTemplate : Template<TOuter>> TOuter.insert(template: TTemplate, build: TTemplate.() -> Unit) { fun <TOuter, TTemplate : Template<TOuter>> TOuter.insert(template: TTemplate, build: TTemplate.() -> Unit) {
template.build() template.build()
with (template) { apply() } with(template) { apply() }
} }
@@ -268,7 +268,7 @@ abstract class KotlinParameterInfoWithCallHandlerBase<TArgumentList : KtElement,
val color = if (isResolvedToDescriptor(call, itemToShow, bindingContext)) val color = if (isResolvedToDescriptor(call, itemToShow, bindingContext))
KotlinParameterInfoWithCallHandlerBase.GREEN_BACKGROUND GREEN_BACKGROUND
else else
context.defaultParameterColor context.defaultParameterColor
@@ -118,7 +118,7 @@ enum class HintType(val desc: String, defaultEnabled: Boolean) {
companion object { companion object {
fun resolve(elem: PsiElement): HintType? { fun resolve(elem: PsiElement): HintType? {
val applicableTypes = HintType.values().filter { it.isApplicable(elem) } val applicableTypes = values().filter { it.isApplicable(elem) }
return applicableTypes.firstOrNull() return applicableTypes.firstOrNull()
} }
@@ -153,8 +153,7 @@ class KotlinInlayParameterHintsProvider : InlayParameterHintsProvider {
) )
override fun getHintInfo(element: PsiElement): HintInfo? { override fun getHintInfo(element: PsiElement): HintInfo? {
val hintType = HintType.resolve(element) ?: return null return when (val hintType = HintType.resolve(element) ?: return null) {
return when (hintType) {
HintType.PARAMETER_HINT -> { HintType.PARAMETER_HINT -> {
val parent = (element as? KtValueArgumentList)?.parent val parent = (element as? KtValueArgumentList)?.parent
(parent as? KtCallElement)?.let { getMethodInfo(it) } (parent as? KtCallElement)?.let { getMethodInfo(it) }
@@ -31,12 +31,12 @@ import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.core.ShortenReferences import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.core.TemplateKind import org.jetbrains.kotlin.idea.core.TemplateKind
import org.jetbrains.kotlin.idea.core.getFunctionBodyTextFromTemplate import org.jetbrains.kotlin.idea.core.getFunctionBodyTextFromTemplate
import org.jetbrains.kotlin.idea.core.implicitModality import org.jetbrains.kotlin.idea.core.implicitModality
import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -48,7 +48,7 @@ import org.jetbrains.kotlin.types.typeUtil.supertypes
class AddFunctionToSupertypeFix private constructor( class AddFunctionToSupertypeFix private constructor(
element: KtNamedFunction, element: KtNamedFunction,
private val functions: List<AddFunctionToSupertypeFix.FunctionData> private val functions: List<FunctionData>
) : KotlinQuickFixAction<KtNamedFunction>(element), LowPriorityAction { ) : KotlinQuickFixAction<KtNamedFunction>(element), LowPriorityAction {
init { init {
@@ -90,7 +90,7 @@ class AddFunctionToSupertypeFix private constructor(
ShortenReferences.DEFAULT.process(insertedFunctionElement) ShortenReferences.DEFAULT.process(insertedFunctionElement)
val modifierToken = insertedFunctionElement.modalityModifier()?.node?.elementType as? KtModifierKeywordToken val modifierToken = insertedFunctionElement.modalityModifier()?.node?.elementType as? KtModifierKeywordToken
?: return@executeWriteCommand ?: return@executeWriteCommand
if (insertedFunctionElement.implicitModality() == modifierToken) { if (insertedFunctionElement.implicitModality() == modifierToken) {
RemoveModifierFix(insertedFunctionElement, modifierToken, true).invoke() RemoveModifierFix(insertedFunctionElement, modifierToken, true).invoke()
} }
@@ -33,7 +33,6 @@ import org.jetbrains.kotlin.idea.inspections.KotlinUniversalQuickFix
import org.jetbrains.kotlin.idea.refactoring.canRefactor import org.jetbrains.kotlin.idea.refactoring.canRefactor
import org.jetbrains.kotlin.idea.util.runOnExpectAndAllActuals import org.jetbrains.kotlin.idea.util.runOnExpectAndAllActuals
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.lexer.KtTokens.* import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.containingClass import org.jetbrains.kotlin.psi.psiUtil.containingClass
@@ -49,7 +48,7 @@ open class AddModifierFix(
) : KotlinCrossLanguageQuickFixAction<KtModifierListOwner>(element), KotlinUniversalQuickFix { ) : KotlinCrossLanguageQuickFixAction<KtModifierListOwner>(element), KotlinUniversalQuickFix {
override fun getText(): String { override fun getText(): String {
val element = element ?: return "" val element = element ?: return ""
if (modifier in modalityModifiers || modifier in KtTokens.VISIBILITY_MODIFIERS || modifier == KtTokens.CONST_KEYWORD) { if (modifier in modalityModifiers || modifier in VISIBILITY_MODIFIERS || modifier == CONST_KEYWORD) {
return "Make ${getElementName(element)} ${modifier.value}" return "Make ${getElementName(element)} ${modifier.value}"
} }
return "Add '${modifier.value}' modifier" return "Add '${modifier.value}' modifier"
@@ -60,10 +59,10 @@ open class AddModifierFix(
private fun invokeOnElement(element: KtModifierListOwner?) { private fun invokeOnElement(element: KtModifierListOwner?) {
element?.addModifier(modifier) element?.addModifier(modifier)
if (modifier == KtTokens.ABSTRACT_KEYWORD && (element is KtProperty || element is KtNamedFunction)) { if (modifier == ABSTRACT_KEYWORD && (element is KtProperty || element is KtNamedFunction)) {
element.containingClass()?.run { element.containingClass()?.run {
if (!hasModifier(KtTokens.ABSTRACT_KEYWORD) && !hasModifier(KtTokens.SEALED_KEYWORD)) { if (!hasModifier(ABSTRACT_KEYWORD) && !hasModifier(SEALED_KEYWORD)) {
addModifier(KtTokens.ABSTRACT_KEYWORD) addModifier(ABSTRACT_KEYWORD)
} }
} }
} }
@@ -85,7 +84,7 @@ open class AddModifierFix(
companion object { companion object {
private fun KtModifierKeywordToken.isMultiplatformPersistent(): Boolean = private fun KtModifierKeywordToken.isMultiplatformPersistent(): Boolean =
this in KtTokens.MODALITY_MODIFIERS || this == KtTokens.INLINE_KEYWORD this in MODALITY_MODIFIERS || this == INLINE_KEYWORD
private val modalityModifiers = setOf(ABSTRACT_KEYWORD, OPEN_KEYWORD, FINAL_KEYWORD) private val modalityModifiers = setOf(ABSTRACT_KEYWORD, OPEN_KEYWORD, FINAL_KEYWORD)
@@ -133,7 +132,7 @@ open class AddModifierFix(
} }
if (modifier == ABSTRACT_KEYWORD if (modifier == ABSTRACT_KEYWORD
&& modifierListOwner is KtClass && modifierListOwner is KtClass
&& modifierListOwner.hasModifier(KtTokens.INLINE_KEYWORD) && modifierListOwner.hasModifier(INLINE_KEYWORD)
) return null ) return null
} }
INNER_KEYWORD -> { INNER_KEYWORD -> {
@@ -158,7 +157,7 @@ open class AddModifierFix(
val typeReference = diagnostic.psiElement as KtTypeReference val typeReference = diagnostic.psiElement as KtTypeReference
val declaration = typeReference.classForRefactor() ?: return null val declaration = typeReference.classForRefactor() ?: return null
if (declaration.isEnum() || declaration.isData()) return null if (declaration.isEnum() || declaration.isData()) return null
return AddModifierFix(declaration, KtTokens.OPEN_KEYWORD) return AddModifierFix(declaration, OPEN_KEYWORD)
} }
} }
@@ -173,7 +172,7 @@ open class AddModifierFix(
if (TypeUtils.isNullableType(type)) return null if (TypeUtils.isNullableType(type)) return null
if (KotlinBuiltIns.isPrimitiveType(type)) return null if (KotlinBuiltIns.isPrimitiveType(type)) return null
return AddModifierFix(property, KtTokens.LATEINIT_KEYWORD) return AddModifierFix(property, LATEINIT_KEYWORD)
} }
} }
} }
@@ -48,8 +48,8 @@ import org.jetbrains.kotlin.types.typeUtil.isUnit
import java.util.* import java.util.*
abstract class ChangeCallableReturnTypeFix( abstract class ChangeCallableReturnTypeFix(
element: KtCallableDeclaration, element: KtCallableDeclaration,
type: KotlinType type: KotlinType
) : KotlinQuickFixAction<KtCallableDeclaration>(element) { ) : KotlinQuickFixAction<KtCallableDeclaration>(element) {
private val changeFunctionLiteralReturnTypeFix: ChangeFunctionLiteralReturnTypeFix? private val changeFunctionLiteralReturnTypeFix: ChangeFunctionLiteralReturnTypeFix?
@@ -61,10 +61,10 @@ abstract class ChangeCallableReturnTypeFix(
init { init {
changeFunctionLiteralReturnTypeFix = if (element is KtFunctionLiteral) { changeFunctionLiteralReturnTypeFix = if (element is KtFunctionLiteral) {
val functionLiteralExpression = PsiTreeUtil.getParentOfType(element, KtLambdaExpression::class.java) ?: error("FunctionLiteral outside any FunctionLiteralExpression: " + element.getElementTextWithContext()) val functionLiteralExpression = PsiTreeUtil.getParentOfType(element, KtLambdaExpression::class.java)
?: error("FunctionLiteral outside any FunctionLiteralExpression: " + element.getElementTextWithContext())
ChangeFunctionLiteralReturnTypeFix(functionLiteralExpression, type) ChangeFunctionLiteralReturnTypeFix(functionLiteralExpression, type)
} } else {
else {
null null
} }
} }
@@ -80,8 +80,7 @@ abstract class ChangeCallableReturnTypeFix(
return "property $fullName" return "property $fullName"
} }
return "function $fullName" return "function $fullName"
} } else {
else {
return null return null
} }
} }
@@ -139,7 +138,7 @@ abstract class ChangeCallableReturnTypeFix(
override fun isAvailable(project: Project, editor: Editor?, file: KtFile): Boolean { override fun isAvailable(project: Project, editor: Editor?, file: KtFile): Boolean {
return !typeContainsError && return !typeContainsError &&
element !is KtConstructor<*> element !is KtConstructor<*>
} }
override fun invoke(project: Project, editor: Editor?, file: KtFile) { override fun invoke(project: Project, editor: Editor?, file: KtFile) {
@@ -147,14 +146,12 @@ abstract class ChangeCallableReturnTypeFix(
if (changeFunctionLiteralReturnTypeFix != null) { if (changeFunctionLiteralReturnTypeFix != null) {
changeFunctionLiteralReturnTypeFix.invoke(project, editor!!, file) changeFunctionLiteralReturnTypeFix.invoke(project, editor!!, file)
} } else {
else {
if (!(isUnitType && element is KtFunction && element.hasBlockBody())) { if (!(isUnitType && element is KtFunction && element.hasBlockBody())) {
var newTypeRef = KtPsiFactory(project).createType(typeSourceCode) var newTypeRef = KtPsiFactory(project).createType(typeSourceCode)
newTypeRef = element.setTypeReference(newTypeRef)!! newTypeRef = element.setTypeReference(newTypeRef)!!
ShortenReferences.DEFAULT.process(newTypeRef) ShortenReferences.DEFAULT.process(newTypeRef)
} } else {
else {
element.typeReference = null element.typeReference = null
} }
} }
@@ -166,32 +163,33 @@ abstract class ChangeCallableReturnTypeFix(
val context = entry.analyze(BodyResolveMode.PARTIAL) val context = entry.analyze(BodyResolveMode.PARTIAL)
val resolvedCall = context.get(BindingContext.COMPONENT_RESOLVED_CALL, entry) ?: return null val resolvedCall = context.get(BindingContext.COMPONENT_RESOLVED_CALL, entry) ?: return null
val componentFunction = val componentFunction =
DescriptorToSourceUtils.descriptorToDeclaration(resolvedCall.candidateDescriptor) as? KtCallableDeclaration DescriptorToSourceUtils.descriptorToDeclaration(resolvedCall.candidateDescriptor) as? KtCallableDeclaration
?: return null ?: return null
val expectedType = context[BindingContext.TYPE, entry.typeReference!!] ?: return null val expectedType = context[BindingContext.TYPE, entry.typeReference!!] ?: return null
return ChangeCallableReturnTypeFix.ForCalled(componentFunction, expectedType) return ForCalled(componentFunction, expectedType)
} }
} }
object HasNextFunctionTypeMismatchFactory : KotlinSingleIntentionActionFactory() { object HasNextFunctionTypeMismatchFactory : KotlinSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? { override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val expression = QuickFixUtil.getParentElementOfType(diagnostic, KtExpression::class.java) val expression = QuickFixUtil.getParentElementOfType(diagnostic, KtExpression::class.java)
?: error("HAS_NEXT_FUNCTION_TYPE_MISMATCH reported on element that is not within any expression") ?: error("HAS_NEXT_FUNCTION_TYPE_MISMATCH reported on element that is not within any expression")
val context = expression.analyze(BodyResolveMode.PARTIAL) val context = expression.analyze(BodyResolveMode.PARTIAL)
val resolvedCall = context[BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, expression] ?: return null val resolvedCall = context[BindingContext.LOOP_RANGE_HAS_NEXT_RESOLVED_CALL, expression] ?: return null
val hasNextDescriptor = resolvedCall.candidateDescriptor val hasNextDescriptor = resolvedCall.candidateDescriptor
val hasNextFunction = DescriptorToSourceUtils.descriptorToDeclaration(hasNextDescriptor) as KtFunction? ?: return null val hasNextFunction = DescriptorToSourceUtils.descriptorToDeclaration(hasNextDescriptor) as KtFunction? ?: return null
return ChangeCallableReturnTypeFix.ForCalled(hasNextFunction, hasNextDescriptor.builtIns.booleanType) return ForCalled(hasNextFunction, hasNextDescriptor.builtIns.booleanType)
} }
} }
object CompareToTypeMismatchFactory : KotlinSingleIntentionActionFactory() { object CompareToTypeMismatchFactory : KotlinSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? { override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val expression = QuickFixUtil.getParentElementOfType(diagnostic, KtBinaryExpression::class.java) ?: error("COMPARE_TO_TYPE_MISMATCH reported on element that is not within any expression") val expression = QuickFixUtil.getParentElementOfType(diagnostic, KtBinaryExpression::class.java)
?: error("COMPARE_TO_TYPE_MISMATCH reported on element that is not within any expression")
val resolvedCall = expression.resolveToCall() ?: return null val resolvedCall = expression.resolveToCall() ?: return null
val compareToDescriptor = resolvedCall.candidateDescriptor val compareToDescriptor = resolvedCall.candidateDescriptor
val compareTo = DescriptorToSourceUtils.descriptorToDeclaration(compareToDescriptor) as? KtFunction ?: return null val compareTo = DescriptorToSourceUtils.descriptorToDeclaration(compareToDescriptor) as? KtFunction ?: return null
return ChangeCallableReturnTypeFix.ForCalled(compareTo, compareToDescriptor.builtIns.intType) return ForCalled(compareTo, compareToDescriptor.builtIns.intType)
} }
} }
@@ -205,7 +203,7 @@ abstract class ChangeCallableReturnTypeFix(
val matchingReturnType = QuickFixUtil.findLowerBoundOfOverriddenCallablesReturnTypes(descriptor) val matchingReturnType = QuickFixUtil.findLowerBoundOfOverriddenCallablesReturnTypes(descriptor)
if (matchingReturnType != null) { if (matchingReturnType != null) {
actions.add(ChangeCallableReturnTypeFix.OnType(function, matchingReturnType)) actions.add(OnType(function, matchingReturnType))
} }
val functionType = descriptor.returnType ?: return actions val functionType = descriptor.returnType ?: return actions
@@ -221,7 +219,7 @@ abstract class ChangeCallableReturnTypeFix(
if (overriddenMismatchingFunctions.size == 1) { if (overriddenMismatchingFunctions.size == 1) {
val overriddenFunction = DescriptorToSourceUtils.descriptorToDeclaration(overriddenMismatchingFunctions[0]) val overriddenFunction = DescriptorToSourceUtils.descriptorToDeclaration(overriddenMismatchingFunctions[0])
if (overriddenFunction is KtFunction) { if (overriddenFunction is KtFunction) {
actions.add(ChangeCallableReturnTypeFix.ForOverridden(overriddenFunction, functionType)) actions.add(ForOverridden(overriddenFunction, functionType))
} }
} }
@@ -232,14 +230,14 @@ abstract class ChangeCallableReturnTypeFix(
object ChangingReturnTypeToUnitFactory : KotlinSingleIntentionActionFactory() { object ChangingReturnTypeToUnitFactory : KotlinSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? { override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val function = QuickFixUtil.getParentElementOfType(diagnostic, KtFunction::class.java) ?: return null val function = QuickFixUtil.getParentElementOfType(diagnostic, KtFunction::class.java) ?: return null
return ChangeCallableReturnTypeFix.ForEnclosing(function, function.builtIns.unitType) return ForEnclosing(function, function.builtIns.unitType)
} }
} }
object ChangingReturnTypeToNothingFactory : KotlinSingleIntentionActionFactory() { object ChangingReturnTypeToNothingFactory : KotlinSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? { override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val function = QuickFixUtil.getParentElementOfType(diagnostic, KtFunction::class.java) ?: return null val function = QuickFixUtil.getParentElementOfType(diagnostic, KtFunction::class.java) ?: return null
return ChangeCallableReturnTypeFix.ForEnclosing(function, function.builtIns.nothingType) return ForEnclosing(function, function.builtIns.nothingType)
} }
} }
@@ -247,7 +245,8 @@ abstract class ChangeCallableReturnTypeFix(
fun getDestructuringDeclarationEntryThatTypeMismatchComponentFunction(diagnostic: Diagnostic): KtDestructuringDeclarationEntry { fun getDestructuringDeclarationEntryThatTypeMismatchComponentFunction(diagnostic: Diagnostic): KtDestructuringDeclarationEntry {
val componentName = COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH.cast(diagnostic).a val componentName = COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH.cast(diagnostic).a
val componentIndex = DataClassDescriptorResolver.getComponentIndex(componentName.asString()) val componentIndex = DataClassDescriptorResolver.getComponentIndex(componentName.asString())
val multiDeclaration = QuickFixUtil.getParentElementOfType(diagnostic, KtDestructuringDeclaration::class.java) ?: error("COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH reported on expression that is not within any multi declaration") val multiDeclaration = QuickFixUtil.getParentElementOfType(diagnostic, KtDestructuringDeclaration::class.java)
?: error("COMPONENT_FUNCTION_RETURN_TYPE_MISMATCH reported on expression that is not within any multi declaration")
return multiDeclaration.entries[componentIndex - 1] return multiDeclaration.entries[componentIndex - 1]
} }
} }
@@ -51,8 +51,7 @@ open class ChangeVariableTypeFix(element: KtVariableDeclaration, type: KotlinTyp
val container = element.unsafeResolveToDescriptor().containingDeclaration as? ClassDescriptor val container = element.unsafeResolveToDescriptor().containingDeclaration as? ClassDescriptor
val containerName = container?.name?.takeUnless { it.isSpecial }?.asString() val containerName = container?.name?.takeUnless { it.isSpecial }?.asString()
if (containerName != null) "'$containerName.$name'" else "'$name'" if (containerName != null) "'$containerName.$name'" else "'$name'"
} } else {
else {
null null
} }
} }
@@ -63,8 +62,7 @@ open class ChangeVariableTypeFix(element: KtVariableDeclaration, type: KotlinTyp
val variablePresentation = variablePresentation() val variablePresentation = variablePresentation()
return if (variablePresentation != null) { return if (variablePresentation != null) {
"Change type of $variablePresentation to '$typePresentation'" "Change type of $variablePresentation to '$typePresentation'"
} } else {
else {
"Change type to '$typePresentation'" "Change type to '$typePresentation'"
} }
} }
@@ -80,11 +78,9 @@ open class ChangeVariableTypeFix(element: KtVariableDeclaration, type: KotlinTyp
} }
} }
override fun getFamilyName() override fun getFamilyName() = KotlinBundle.message("change.type.family")
= KotlinBundle.message("change.type.family")
override fun isAvailable(project: Project, editor: Editor?, file: KtFile) override fun isAvailable(project: Project, editor: Editor?, file: KtFile) = !typeContainsError
= !typeContainsError
override fun invoke(project: Project, editor: Editor?, file: KtFile) { override fun invoke(project: Project, editor: Editor?, file: KtFile) {
val element = element ?: return val element = element ?: return
@@ -141,25 +137,29 @@ open class ChangeVariableTypeFix(element: KtVariableDeclaration, type: KotlinTyp
if (overriddenPropertyType != null) { if (overriddenPropertyType != null) {
if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(propertyType, overriddenPropertyType)) { if (!KotlinTypeChecker.DEFAULT.isSubtypeOf(propertyType, overriddenPropertyType)) {
overriddenMismatchingProperties.add(overriddenProperty) overriddenMismatchingProperties.add(overriddenProperty)
} } else if (overriddenProperty.isVar && !KotlinTypeChecker.DEFAULT.equalTypes(
else if (overriddenProperty.isVar && !KotlinTypeChecker.DEFAULT.equalTypes(overriddenPropertyType, propertyType)) { overriddenPropertyType,
propertyType
)
) {
canChangeOverriddenPropertyType = false canChangeOverriddenPropertyType = false
} }
if (overriddenProperty.isVar && lowerBoundOfOverriddenPropertiesTypes != null && if (overriddenProperty.isVar && lowerBoundOfOverriddenPropertiesTypes != null &&
!KotlinTypeChecker.DEFAULT.equalTypes(lowerBoundOfOverriddenPropertiesTypes, overriddenPropertyType)) { !KotlinTypeChecker.DEFAULT.equalTypes(lowerBoundOfOverriddenPropertiesTypes, overriddenPropertyType)
) {
lowerBoundOfOverriddenPropertiesTypes = null lowerBoundOfOverriddenPropertiesTypes = null
} }
} }
} }
if (lowerBoundOfOverriddenPropertiesTypes != null) { if (lowerBoundOfOverriddenPropertiesTypes != null) {
actions.add(ChangeVariableTypeFix.OnType(property, lowerBoundOfOverriddenPropertiesTypes)) actions.add(OnType(property, lowerBoundOfOverriddenPropertiesTypes))
} }
if (overriddenMismatchingProperties.size == 1 && canChangeOverriddenPropertyType) { if (overriddenMismatchingProperties.size == 1 && canChangeOverriddenPropertyType) {
val overriddenProperty = DescriptorToSourceUtils.descriptorToDeclaration(overriddenMismatchingProperties.single()) val overriddenProperty = DescriptorToSourceUtils.descriptorToDeclaration(overriddenMismatchingProperties.single())
if (overriddenProperty is KtProperty) { if (overriddenProperty is KtProperty) {
actions.add(ChangeVariableTypeFix.ForOverridden(overriddenProperty, propertyType)) actions.add(ForOverridden(overriddenProperty, propertyType))
} }
} }
} }
@@ -17,9 +17,12 @@
package org.jetbrains.kotlin.idea.quickfix package org.jetbrains.kotlin.idea.quickfix
import com.intellij.codeInsight.intention.IntentionAction import com.intellij.codeInsight.intention.IntentionAction
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithVisibility
import org.jetbrains.kotlin.descriptors.DescriptorWithRelation
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.descriptors.EffectiveVisibility.Permissiveness.LESS import org.jetbrains.kotlin.descriptors.EffectiveVisibility.Permissiveness.LESS
import org.jetbrains.kotlin.descriptors.Visibilities.* import org.jetbrains.kotlin.descriptors.Visibilities.*
import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.diagnostics.Diagnostic import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory3 import org.jetbrains.kotlin.diagnostics.DiagnosticFactory3
import org.jetbrains.kotlin.idea.core.toDescriptor import org.jetbrains.kotlin.idea.core.toDescriptor
@@ -32,12 +35,12 @@ import java.util.*
object ChangeVisibilityOnExposureFactory : KotlinIntentionActionsFactory() { object ChangeVisibilityOnExposureFactory : KotlinIntentionActionsFactory() {
private fun addFixToTargetVisibility( private fun addFixToTargetVisibility(
modifierListOwner: KtModifierListOwner, modifierListOwner: KtModifierListOwner,
descriptor: DeclarationDescriptorWithVisibility, descriptor: DeclarationDescriptorWithVisibility,
targetVisibility: Visibility, targetVisibility: Visibility,
boundVisibility: Visibility, boundVisibility: Visibility,
protectedAllowed: Boolean, protectedAllowed: Boolean,
fixes: MutableList<IntentionAction> fixes: MutableList<IntentionAction>
) { ) {
val possibleVisibilities = when (targetVisibility) { val possibleVisibilities = when (targetVisibility) {
PROTECTED -> if (protectedAllowed) listOf(boundVisibility, PROTECTED) else listOf(boundVisibility) PROTECTED -> if (protectedAllowed) listOf(boundVisibility, PROTECTED) else listOf(boundVisibility)
@@ -55,7 +58,7 @@ object ChangeVisibilityOnExposureFactory : KotlinIntentionActionsFactory() {
val exposedDiagnostic = factory.cast(diagnostic) val exposedDiagnostic = factory.cast(diagnostic)
val exposedDescriptor = exposedDiagnostic.b.descriptor as? DeclarationDescriptorWithVisibility ?: return emptyList() val exposedDescriptor = exposedDiagnostic.b.descriptor as? DeclarationDescriptorWithVisibility ?: return emptyList()
val exposedDeclaration = val exposedDeclaration =
DescriptorToSourceUtils.getSourceFromDescriptor(exposedDescriptor) as? KtModifierListOwner ?: return emptyList() DescriptorToSourceUtils.getSourceFromDescriptor(exposedDescriptor) as? KtModifierListOwner ?: return emptyList()
val exposedVisibility = exposedDiagnostic.c val exposedVisibility = exposedDiagnostic.c
val userVisibility = exposedDiagnostic.a val userVisibility = exposedDiagnostic.a
val (targetUserVisibility, targetExposedVisibility) = when (exposedVisibility.relation(userVisibility)) { val (targetUserVisibility, targetExposedVisibility) = when (exposedVisibility.relation(userVisibility)) {
@@ -67,15 +70,19 @@ object ChangeVisibilityOnExposureFactory : KotlinIntentionActionsFactory() {
val protectedAllowed = exposedDeclaration.parent == userDeclaration?.parent val protectedAllowed = exposedDeclaration.parent == userDeclaration?.parent
if (userDeclaration != null) { if (userDeclaration != null) {
val userDescriptor = userDeclaration.toDescriptor() as? DeclarationDescriptorWithVisibility val userDescriptor = userDeclaration.toDescriptor() as? DeclarationDescriptorWithVisibility
if (userDescriptor != null && Visibilities.isVisibleIgnoringReceiver(exposedDescriptor, userDescriptor)) { if (userDescriptor != null && isVisibleIgnoringReceiver(exposedDescriptor, userDescriptor)) {
addFixToTargetVisibility(userDeclaration, userDescriptor, addFixToTargetVisibility(
targetUserVisibility, PRIVATE, userDeclaration, userDescriptor,
protectedAllowed, result) targetUserVisibility, PRIVATE,
protectedAllowed, result
)
} }
} }
addFixToTargetVisibility(exposedDeclaration, exposedDescriptor, addFixToTargetVisibility(
targetExposedVisibility, PUBLIC, exposedDeclaration, exposedDescriptor,
protectedAllowed, result) targetExposedVisibility, PUBLIC,
protectedAllowed, result
)
return result return result
} }
} }
@@ -27,20 +27,20 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.parents import org.jetbrains.kotlin.psi.psiUtil.parents
sealed class CreateLabelFix( sealed class CreateLabelFix(
expression: KtLabelReferenceExpression expression: KtLabelReferenceExpression
) : KotlinQuickFixAction<KtLabelReferenceExpression>(expression) { ) : KotlinQuickFixAction<KtLabelReferenceExpression>(expression) {
class ForLoop(expression: KtLabelReferenceExpression) : CreateLabelFix(expression) { class ForLoop(expression: KtLabelReferenceExpression) : CreateLabelFix(expression) {
override val chooserTitle = "Select loop statement to label" override val chooserTitle = "Select loop statement to label"
override fun getCandidateExpressions(labelReferenceExpression: KtLabelReferenceExpression) = override fun getCandidateExpressions(labelReferenceExpression: KtLabelReferenceExpression) =
labelReferenceExpression.getContainingLoops().toList() labelReferenceExpression.getContainingLoops().toList()
} }
class ForLambda(expression: KtLabelReferenceExpression) : CreateLabelFix(expression) { class ForLambda(expression: KtLabelReferenceExpression) : CreateLabelFix(expression) {
override val chooserTitle = "Select lambda to label" override val chooserTitle = "Select lambda to label"
override fun getCandidateExpressions(labelReferenceExpression: KtLabelReferenceExpression) = override fun getCandidateExpressions(labelReferenceExpression: KtLabelReferenceExpression) =
labelReferenceExpression.getContainingLambdas().toList() labelReferenceExpression.getContainingLambdas().toList()
} }
override fun getFamilyName() = "Create label" override fun getFamilyName() = "Create label"
@@ -70,39 +70,38 @@ sealed class CreateLabelFix(
} }
chooseContainerElementIfNecessary( chooseContainerElementIfNecessary(
containers, containers,
editor, editor,
chooserTitle, chooserTitle,
true, true,
{ it }, { it },
{ {
doCreateLabel(expression, it, project) doCreateLabel(expression, it, project)
} }
) )
} }
companion object : KotlinSingleIntentionActionFactory() { companion object : KotlinSingleIntentionActionFactory() {
private fun KtLabelReferenceExpression.getContainingLoops(): Sequence<KtLoopExpression> { private fun KtLabelReferenceExpression.getContainingLoops(): Sequence<KtLoopExpression> {
return parents return parents
.takeWhile { !(it is KtDeclarationWithBody || it is KtClassBody || it is KtFile) } .takeWhile { !(it is KtDeclarationWithBody || it is KtClassBody || it is KtFile) }
.filterIsInstance<KtLoopExpression>() .filterIsInstance<KtLoopExpression>()
} }
private fun KtLabelReferenceExpression.getContainingLambdas(): Sequence<KtLambdaExpression> { private fun KtLabelReferenceExpression.getContainingLambdas(): Sequence<KtLambdaExpression> {
return parents return parents
.takeWhile { !(it is KtDeclarationWithBody && it !is KtFunctionLiteral || it is KtClassBody || it is KtFile) } .takeWhile { !(it is KtDeclarationWithBody && it !is KtFunctionLiteral || it is KtClassBody || it is KtFile) }
.filterIsInstance<KtLambdaExpression>() .filterIsInstance<KtLambdaExpression>()
} }
override fun createAction(diagnostic: Diagnostic): IntentionAction? { override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val labelReferenceExpression = diagnostic.psiElement as? KtLabelReferenceExpression ?: return null val labelReferenceExpression = diagnostic.psiElement as? KtLabelReferenceExpression ?: return null
val parentExpression = (labelReferenceExpression.parent as? KtContainerNode)?.parent return when ((labelReferenceExpression.parent as? KtContainerNode)?.parent) {
return when (parentExpression) {
is KtBreakExpression, is KtContinueExpression -> { is KtBreakExpression, is KtContinueExpression -> {
if (labelReferenceExpression.getContainingLoops().any()) CreateLabelFix.ForLoop(labelReferenceExpression) else null if (labelReferenceExpression.getContainingLoops().any()) ForLoop(labelReferenceExpression) else null
} }
is KtReturnExpression -> { is KtReturnExpression -> {
if (labelReferenceExpression.getContainingLambdas().any()) CreateLabelFix.ForLambda(labelReferenceExpression) else null if (labelReferenceExpression.getContainingLambdas().any()) ForLambda(labelReferenceExpression) else null
} }
else -> null else -> null
} }
@@ -168,7 +168,7 @@ class QuickFixFactoryForTypeMismatchError : KotlinIntentionActionsFactory() {
actions.add(CastExpressionFix(diagnosticElement.getTopMostQualifiedForSelectorIfAny(), expectedType)) actions.add(CastExpressionFix(diagnosticElement.getTopMostQualifiedForSelectorIfAny(), expectedType))
} }
if (!expectedType.isMarkedNullable && org.jetbrains.kotlin.types.TypeUtils.isNullableType(expressionType)) { if (!expectedType.isMarkedNullable && TypeUtils.isNullableType(expressionType)) {
val nullableExpected = expectedType.makeNullable() val nullableExpected = expectedType.makeNullable()
if (expressionType.isSubtypeOf(nullableExpected)) { if (expressionType.isSubtypeOf(nullableExpected)) {
actions.add(AddExclExclCallFix(diagnosticElement.getTopMostQualifiedForSelectorIfAny())) actions.add(AddExclExclCallFix(diagnosticElement.getTopMostQualifiedForSelectorIfAny()))
@@ -21,7 +21,10 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Errors.* import org.jetbrains.kotlin.diagnostics.Errors.*
import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementAsConstructorParameter import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementAsConstructorParameter
import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler
import org.jetbrains.kotlin.idea.inspections.* import org.jetbrains.kotlin.idea.inspections.AddModifierFixFactory
import org.jetbrains.kotlin.idea.inspections.InfixCallFixActionFactory
import org.jetbrains.kotlin.idea.inspections.PlatformUnresolvedProvider
import org.jetbrains.kotlin.idea.inspections.RemoveAnnotationFix
import org.jetbrains.kotlin.idea.intentions.AbstractAddAccessorsIntention import org.jetbrains.kotlin.idea.intentions.AbstractAddAccessorsIntention
import org.jetbrains.kotlin.idea.intentions.AddValVarToConstructorParameterAction import org.jetbrains.kotlin.idea.intentions.AddValVarToConstructorParameterAction
import org.jetbrains.kotlin.idea.intentions.ConvertPropertyInitializerToGetterIntention import org.jetbrains.kotlin.idea.intentions.ConvertPropertyInitializerToGetterIntention
@@ -46,7 +49,6 @@ import org.jetbrains.kotlin.idea.quickfix.replaceWith.DeprecatedSymbolUsageFix
import org.jetbrains.kotlin.idea.quickfix.replaceWith.DeprecatedSymbolUsageInWholeProjectFix import org.jetbrains.kotlin.idea.quickfix.replaceWith.DeprecatedSymbolUsageInWholeProjectFix
import org.jetbrains.kotlin.idea.quickfix.replaceWith.ReplaceProtectedToPublishedApiCallFix import org.jetbrains.kotlin.idea.quickfix.replaceWith.ReplaceProtectedToPublishedApiCallFix
import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs import org.jetbrains.kotlin.js.resolve.diagnostics.ErrorsJs
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.lexer.KtTokens.* import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.psi.KtClass import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtClassOrObject
@@ -455,10 +457,10 @@ class QuickFixRegistrar : QuickFixContributor {
NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION.registerFactory(ConstFixFactory) NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION.registerFactory(ConstFixFactory)
OPERATOR_MODIFIER_REQUIRED.registerFactory(AddModifierFixFactory(KtTokens.OPERATOR_KEYWORD)) OPERATOR_MODIFIER_REQUIRED.registerFactory(AddModifierFixFactory(OPERATOR_KEYWORD))
OPERATOR_MODIFIER_REQUIRED.registerFactory(ImportForMissingOperatorFactory) OPERATOR_MODIFIER_REQUIRED.registerFactory(ImportForMissingOperatorFactory)
INFIX_MODIFIER_REQUIRED.registerFactory(AddModifierFixFactory(KtTokens.INFIX_KEYWORD)) INFIX_MODIFIER_REQUIRED.registerFactory(AddModifierFixFactory(INFIX_KEYWORD))
INFIX_MODIFIER_REQUIRED.registerFactory(InfixCallFixActionFactory) INFIX_MODIFIER_REQUIRED.registerFactory(InfixCallFixActionFactory)
UNDERSCORE_IS_RESERVED.registerFactory(RenameUnderscoreFix) UNDERSCORE_IS_RESERVED.registerFactory(RenameUnderscoreFix)
@@ -530,7 +532,7 @@ class QuickFixRegistrar : QuickFixContributor {
NO_ACTUAL_FOR_EXPECT.registerFactory(CreateActualFix) NO_ACTUAL_FOR_EXPECT.registerFactory(CreateActualFix)
NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS.registerFactory(AddActualFix) NO_ACTUAL_CLASS_MEMBER_FOR_EXPECTED_CLASS.registerFactory(AddActualFix)
ACTUAL_MISSING.registerFactory(AddModifierFix.createFactory(KtTokens.ACTUAL_KEYWORD)) ACTUAL_MISSING.registerFactory(AddModifierFix.createFactory(ACTUAL_KEYWORD))
CAST_NEVER_SUCCEEDS.registerFactory(ReplacePrimitiveCastWithNumberConversionFix) CAST_NEVER_SUCCEEDS.registerFactory(ReplacePrimitiveCastWithNumberConversionFix)
@@ -26,8 +26,10 @@ import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
class RemoveNullableFix(element: KtNullableType, class RemoveNullableFix(
private val typeOfError: RemoveNullableFix.NullableKind) : KotlinQuickFixAction<KtNullableType>(element) { element: KtNullableType,
private val typeOfError: NullableKind
) : KotlinQuickFixAction<KtNullableType>(element) {
enum class NullableKind(val message: String) { enum class NullableKind(val message: String) {
REDUNDANT("Remove redundant '?'"), REDUNDANT("Remove redundant '?'"),
SUPERTYPE("Remove '?'"), SUPERTYPE("Remove '?'"),
@@ -244,7 +244,7 @@ sealed class CreateCallableFromCallActionFactory<E : KtExpression>(
receiverType: TypeInfo, receiverType: TypeInfo,
possibleContainers: List<KtElement> possibleContainers: List<KtElement>
) = super.doCreateCallableInfo(expression, analysisResult, name, receiverType, possibleContainers)?.let { ) = super.doCreateCallableInfo(expression, analysisResult, name, receiverType, possibleContainers)?.let {
ByImplicitExtensionReceiver.getCallableWithReceiverInsideExtension( getCallableWithReceiverInsideExtension(
it, it,
expression, expression,
analysisResult.bindingContext, analysisResult.bindingContext,
@@ -70,7 +70,7 @@ val ClassKind.actionPriority: IntentionActionPriority
get() = if (this == ANNOTATION_CLASS) IntentionActionPriority.LOW else IntentionActionPriority.NORMAL get() = if (this == ANNOTATION_CLASS) IntentionActionPriority.LOW else IntentionActionPriority.NORMAL
data class ClassInfo( data class ClassInfo(
val kind: ClassKind = ClassKind.DEFAULT, val kind: ClassKind = DEFAULT,
val name: String, val name: String,
private val targetParents: List<PsiElement>, private val targetParents: List<PsiElement>,
val expectedTypeInfo: TypeInfo, val expectedTypeInfo: TypeInfo,
@@ -81,7 +81,7 @@ data class ClassInfo(
) { ) {
val applicableParents by lazy { val applicableParents by lazy {
targetParents.filter { targetParents.filter {
if (kind == ClassKind.OBJECT && it is KtClass && (it.isInner() || it.isLocal)) return@filter false if (kind == OBJECT && it is KtClass && (it.isInner() || it.isLocal)) return@filter false
true true
} }
} }
@@ -124,7 +124,7 @@ open class CreateClassFromUsageFix<E : KtElement> protected constructor(
} }
} }
if (classInfo.kind != ClassKind.ENUM_ENTRY && parents.find { it is PsiPackage } == null) { if (classInfo.kind != ENUM_ENTRY && parents.find { it is PsiPackage } == null) {
parents += SeparateFileWrapper(PsiManager.getInstance(project)) parents += SeparateFileWrapper(PsiManager.getInstance(project))
} }
} }
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.idea.quickfix.crossLanguage
import com.intellij.codeInsight.daemon.QuickFixBundle import com.intellij.codeInsight.daemon.QuickFixBundle
import com.intellij.lang.jvm.actions.ChangeParametersRequest import com.intellij.lang.jvm.actions.ChangeParametersRequest
import com.intellij.lang.jvm.actions.ExpectedParameter import com.intellij.lang.jvm.actions.ExpectedParameter
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.text.StringUtil import com.intellij.openapi.util.text.StringUtil
@@ -26,7 +25,10 @@ import org.jetbrains.kotlin.load.java.NOT_NULL_ANNOTATIONS
import org.jetbrains.kotlin.load.java.NULLABLE_ANNOTATIONS import org.jetbrains.kotlin.load.java.NULLABLE_ANNOTATIONS
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.* import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtParameterList
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
@@ -35,7 +35,10 @@ import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.getDeepestSuperDeclarations import org.jetbrains.kotlin.idea.core.getDeepestSuperDeclarations
import org.jetbrains.kotlin.idea.core.getDirectlyOverriddenDeclarations import org.jetbrains.kotlin.idea.core.getDirectlyOverriddenDeclarations
import org.jetbrains.kotlin.idea.util.* import org.jetbrains.kotlin.idea.util.actualsForExpected
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.idea.util.isExpectDeclaration
import org.jetbrains.kotlin.idea.util.liftToExpected
import org.jetbrains.kotlin.psi.KtBlockExpression import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtDeclaration import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtDeclarationWithBody import org.jetbrains.kotlin.psi.KtDeclarationWithBody
@@ -47,16 +50,17 @@ import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope import org.jetbrains.kotlin.resolve.scopes.utils.memberScopeAsImportingScope
import java.util.* import java.util.*
abstract class CallableRefactoring<out T: CallableDescriptor>( abstract class CallableRefactoring<out T : CallableDescriptor>(
val project: Project, val project: Project,
callableDescriptor: T, callableDescriptor: T,
val commandName: String) { val commandName: String
) {
private val LOG = Logger.getInstance(CallableRefactoring::class.java) private val LOG = Logger.getInstance(CallableRefactoring::class.java)
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
val callableDescriptor = callableDescriptor.liftToExpected() as? T ?: callableDescriptor val callableDescriptor = callableDescriptor.liftToExpected() as? T ?: callableDescriptor
private val kind = (callableDescriptor as? CallableMemberDescriptor)?.kind ?: CallableMemberDescriptor.Kind.DECLARATION private val kind = (callableDescriptor as? CallableMemberDescriptor)?.kind ?: DECLARATION
protected open fun forcePerformForSelectedFunctionOnly(): Boolean { protected open fun forcePerformForSelectedFunctionOnly(): Boolean {
return false return false
@@ -76,16 +80,20 @@ abstract class CallableRefactoring<out T: CallableDescriptor>(
}.map { it.liftToExpected() as? CallableDescriptor ?: it } }.map { it.liftToExpected() as? CallableDescriptor ?: it }
} }
private fun showSuperFunctionWarningDialog(superCallables: Collection<CallableDescriptor>, private fun showSuperFunctionWarningDialog(
callableFromEditor: CallableDescriptor, superCallables: Collection<CallableDescriptor>,
options: List<String>): Int { callableFromEditor: CallableDescriptor,
options: List<String>
): Int {
val superString = superCallables.joinToString(prefix = "\n ", separator = ",\n ", postfix = ".\n\n") { val superString = superCallables.joinToString(prefix = "\n ", separator = ",\n ", postfix = ".\n\n") {
it.containingDeclaration.name.asString() it.containingDeclaration.name.asString()
} }
val message = KotlinBundle.message("x.overrides.y.in.class.list", val message = KotlinBundle.message(
DescriptorRenderer.COMPACT.render(callableFromEditor), "x.overrides.y.in.class.list",
superString, DescriptorRenderer.COMPACT.render(callableFromEditor),
"refactor") superString,
"refactor"
)
val title = IdeBundle.message("title.warning")!! val title = IdeBundle.message("title.warning")!!
val icon = Messages.getQuestionIcon() val icon = Messages.getQuestionIcon()
return Messages.showDialog(message, title, options.toTypedArray(), 0, icon) return Messages.showDialog(message, title, options.toTypedArray(), 0, icon)
@@ -99,10 +107,9 @@ abstract class CallableRefactoring<out T: CallableDescriptor>(
val unmodifiableFile = element.containingFile?.virtualFile?.presentableUrl val unmodifiableFile = element.containingFile?.virtualFile?.presentableUrl
if (unmodifiableFile != null) { if (unmodifiableFile != null) {
val message = RefactoringBundle.message("refactoring.cannot.be.performed") + "\n" + val message = RefactoringBundle.message("refactoring.cannot.be.performed") + "\n" +
IdeBundle.message("error.message.cannot.modify.file.0", unmodifiableFile) IdeBundle.message("error.message.cannot.modify.file.0", unmodifiableFile)
Messages.showErrorDialog(project, message, CommonBundle.getErrorTitle()!!) Messages.showErrorDialog(project, message, CommonBundle.getErrorTitle()!!)
} } else {
else {
LOG.error("Could not find file for Psi element: " + element.text) LOG.error("Could not find file for Psi element: " + element.text)
} }
@@ -127,14 +134,13 @@ abstract class CallableRefactoring<out T: CallableDescriptor>(
fun buildDialogOptions(isSingleFunctionSelected: Boolean): List<String> { fun buildDialogOptions(isSingleFunctionSelected: Boolean): List<String> {
return if (isSingleFunctionSelected) { return if (isSingleFunctionSelected) {
arrayListOf(Messages.YES_BUTTON, Messages.NO_BUTTON, Messages.CANCEL_BUTTON) arrayListOf(Messages.YES_BUTTON, Messages.NO_BUTTON, Messages.CANCEL_BUTTON)
} } else {
else {
arrayListOf(Messages.OK_BUTTON, Messages.CANCEL_BUTTON) arrayListOf(Messages.OK_BUTTON, Messages.CANCEL_BUTTON)
} }
} }
if (kind == SYNTHESIZED) { if (kind == SYNTHESIZED) {
LOG.error("Change signature refactoring should not be called for synthesized member " + callableDescriptor) LOG.error("Change signature refactoring should not be called for synthesized member $callableDescriptor")
return false return false
} }
@@ -146,7 +152,7 @@ abstract class CallableRefactoring<out T: CallableDescriptor>(
assert(!closestModifiableDescriptors.isEmpty()) { "Should contain original declaration or some of its super declarations" } assert(!closestModifiableDescriptors.isEmpty()) { "Should contain original declaration or some of its super declarations" }
val deepestSuperDeclarations = val deepestSuperDeclarations =
(callableDescriptor as? CallableMemberDescriptor)?.getDeepestSuperDeclarations() (callableDescriptor as? CallableMemberDescriptor)?.getDeepestSuperDeclarations()
?: listOf(callableDescriptor) ?: listOf(callableDescriptor)
if (ApplicationManager.getApplication()!!.isUnitTestMode) { if (ApplicationManager.getApplication()!!.isUnitTestMode) {
performRefactoring(deepestSuperDeclarations) performRefactoring(deepestSuperDeclarations)
@@ -183,11 +189,10 @@ fun getAffectedCallables(project: Project, descriptorsForChange: Collection<Call
return baseCallables + baseCallables.flatMapTo(HashSet<PsiElement>()) { callable -> return baseCallables + baseCallables.flatMapTo(HashSet<PsiElement>()) { callable ->
if (callable is KtDeclaration && callable.isExpectDeclaration()) { if (callable is KtDeclaration && callable.isExpectDeclaration()) {
callable.actualsForExpected() callable.actualsForExpected()
} } else {
else {
callable.toLightMethods().flatMap { psiMethod -> callable.toLightMethods().flatMap { psiMethod ->
val overrides = OverridingMethodsSearch.search(psiMethod).findAll() val overrides = OverridingMethodsSearch.search(psiMethod).findAll()
overrides.map { method -> method.namedUnwrappedElement ?: method} overrides.map { method -> method.namedUnwrappedElement ?: method }
} }
} }
} }
@@ -200,10 +205,8 @@ fun DeclarationDescriptor.getContainingScope(): LexicalScope? {
val lastStatement = block.statements.last() val lastStatement = block.statements.last()
val bindingContext = lastStatement.analyze() val bindingContext = lastStatement.analyze()
lastStatement.getResolutionScope(bindingContext, lastStatement.getResolutionFacade()) lastStatement.getResolutionScope(bindingContext, lastStatement.getResolutionFacade())
} } else {
else { when (val containingDescriptor = containingDeclaration ?: return null) {
val containingDescriptor = containingDeclaration ?: return null
when (containingDescriptor) {
is ClassDescriptorWithResolutionScopes -> containingDescriptor.scopeForInitializerResolution is ClassDescriptorWithResolutionScopes -> containingDescriptor.scopeForInitializerResolution
is PackageFragmentDescriptor -> LexicalScope.Base(containingDescriptor.getMemberScope().memberScopeAsImportingScope(), this) is PackageFragmentDescriptor -> LexicalScope.Base(containingDescriptor.getMemberScope().memberScopeAsImportingScope(), this)
else -> null else -> null
@@ -36,7 +36,6 @@ import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaOrKotlinMemberDescriptor import org.jetbrains.kotlin.idea.caches.resolve.util.getJavaOrKotlinMemberDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.util.javaResolutionFacade
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinMethodDescriptor.Kind import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinMethodDescriptor.Kind
import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.KotlinCallableDefinitionUsage import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.KotlinCallableDefinitionUsage
@@ -57,22 +56,26 @@ import org.jetbrains.kotlin.utils.keysToMap
import java.util.* import java.util.*
open class KotlinChangeInfo( open class KotlinChangeInfo(
val methodDescriptor: KotlinMethodDescriptor, val methodDescriptor: KotlinMethodDescriptor,
private var name: String = methodDescriptor.name, private var name: String = methodDescriptor.name,
var newReturnTypeInfo: KotlinTypeInfo = KotlinTypeInfo(true, methodDescriptor.baseDescriptor.returnType), var newReturnTypeInfo: KotlinTypeInfo = KotlinTypeInfo(true, methodDescriptor.baseDescriptor.returnType),
var newVisibility: Visibility = methodDescriptor.visibility, var newVisibility: Visibility = methodDescriptor.visibility,
parameterInfos: List<KotlinParameterInfo> = methodDescriptor.parameters, parameterInfos: List<KotlinParameterInfo> = methodDescriptor.parameters,
receiver: KotlinParameterInfo? = methodDescriptor.receiver, receiver: KotlinParameterInfo? = methodDescriptor.receiver,
val context: PsiElement, val context: PsiElement,
primaryPropagationTargets: Collection<PsiElement> = emptyList() primaryPropagationTargets: Collection<PsiElement> = emptyList()
) : ChangeInfo, UserDataHolder by UserDataHolderBase() { ) : ChangeInfo, UserDataHolder by UserDataHolderBase() {
private class JvmOverloadSignature( private class JvmOverloadSignature(
val method: PsiMethod, val method: PsiMethod,
val mandatoryParams: Set<KtParameter>, val mandatoryParams: Set<KtParameter>,
val defaultValues: Set<KtExpression> val defaultValues: Set<KtExpression>
) { ) {
fun constrainBy(other: JvmOverloadSignature): JvmOverloadSignature { fun constrainBy(other: JvmOverloadSignature): JvmOverloadSignature {
return JvmOverloadSignature(method, mandatoryParams.intersect(other.mandatoryParams), defaultValues.intersect(other.defaultValues)) return JvmOverloadSignature(
method,
mandatoryParams.intersect(other.mandatoryParams),
defaultValues.intersect(other.defaultValues)
)
} }
} }
@@ -105,8 +108,8 @@ open class KotlinChangeInfo(
private val isParameterSetOrOrderChangedLazy: Boolean by lazy { private val isParameterSetOrOrderChangedLazy: Boolean by lazy {
val signatureParameters = getNonReceiverParameters() val signatureParameters = getNonReceiverParameters()
methodDescriptor.receiver != receiverParameterInfo || methodDescriptor.receiver != receiverParameterInfo ||
signatureParameters.size != methodDescriptor.parametersCount || signatureParameters.size != methodDescriptor.parametersCount ||
signatureParameters.indices.any { i -> signatureParameters[i].oldIndex != i } signatureParameters.indices.any { i -> signatureParameters[i].oldIndex != i }
} }
private var isPrimaryMethodUpdated: Boolean = false private var isPrimaryMethodUpdated: Boolean = false
@@ -142,11 +145,11 @@ open class KotlinChangeInfo(
newParameters[index] = parameterInfo newParameters[index] = parameterInfo
} }
@JvmOverloads fun addParameter(parameterInfo: KotlinParameterInfo, atIndex: Int = -1) { @JvmOverloads
fun addParameter(parameterInfo: KotlinParameterInfo, atIndex: Int = -1) {
if (atIndex >= 0) { if (atIndex >= 0) {
newParameters.add(atIndex, parameterInfo) newParameters.add(atIndex, parameterInfo)
} } else {
else {
newParameters.add(parameterInfo) newParameters.add(parameterInfo)
} }
} }
@@ -164,7 +167,7 @@ open class KotlinChangeInfo(
} }
fun hasParameter(parameterInfo: KotlinParameterInfo): Boolean = fun hasParameter(parameterInfo: KotlinParameterInfo): Boolean =
parameterInfo in newParameters parameterInfo in newParameters
override fun isGenerateDelegate(): Boolean = false override fun isGenerateDelegate(): Boolean = false
@@ -230,7 +233,7 @@ open class KotlinChangeInfo(
private fun renderReturnTypeIfNeeded(): String? { private fun renderReturnTypeIfNeeded(): String? {
val typeInfo = newReturnTypeInfo val typeInfo = newReturnTypeInfo
if (kind != Kind.FUNCTION) return null if (kind != Kind.FUNCTION) return null
if (typeInfo.type?.isUnit() ?: false) return null if (typeInfo.type?.isUnit() == true) return null
return typeInfo.render() return typeInfo.render()
} }
@@ -244,8 +247,7 @@ open class KotlinChangeInfo(
if (isCustomizedVisibility) { if (isCustomizedVisibility) {
buffer.append(' ').append(newVisibility).append(" constructor ") buffer.append(' ').append(newVisibility).append(" constructor ")
} }
} } else {
else {
if (!DescriptorUtils.isLocal(inheritedCallable.originalCallableDescriptor) && isCustomizedVisibility) { if (!DescriptorUtils.isLocal(inheritedCallable.originalCallableDescriptor) && isCustomizedVisibility) {
buffer.append(newVisibility).append(' ') buffer.append(newVisibility).append(' ')
} }
@@ -257,8 +259,7 @@ open class KotlinChangeInfo(
val typeInfo = it.currentTypeInfo val typeInfo = it.currentTypeInfo
if (typeInfo.type != null && typeInfo.type.isNonExtensionFunctionType) { if (typeInfo.type != null && typeInfo.type.isNonExtensionFunctionType) {
buffer.append("(${typeInfo.render()})") buffer.append("(${typeInfo.render()})")
} } else {
else {
buffer.append(typeInfo.render()) buffer.append(typeInfo.render())
} }
buffer.append('.') buffer.append('.')
@@ -276,7 +277,7 @@ open class KotlinChangeInfo(
fun isRefactoringTarget(inheritedCallableDescriptor: CallableDescriptor?): Boolean { fun isRefactoringTarget(inheritedCallableDescriptor: CallableDescriptor?): Boolean {
return inheritedCallableDescriptor != null return inheritedCallableDescriptor != null
&& method == DescriptorToSourceUtils.descriptorToDeclaration(inheritedCallableDescriptor) && method == DescriptorToSourceUtils.descriptorToDeclaration(inheritedCallableDescriptor)
} }
fun getNewParametersSignature(inheritedCallable: KotlinCallableDefinitionUsage<*>): String { fun getNewParametersSignature(inheritedCallable: KotlinCallableDefinitionUsage<*>): String {
@@ -284,7 +285,7 @@ open class KotlinChangeInfo(
} }
fun getNewParametersSignatureWithoutParentheses( fun getNewParametersSignatureWithoutParentheses(
inheritedCallable: KotlinCallableDefinitionUsage<*> inheritedCallable: KotlinCallableDefinitionUsage<*>
): String { ): String {
val signatureParameters = getNonReceiverParameters() val signatureParameters = getNonReceiverParameters()
@@ -322,18 +323,18 @@ open class KotlinChangeInfo(
} }
private fun <Parameter> makeSignatures( private fun <Parameter> makeSignatures(
parameters: List<Parameter>, parameters: List<Parameter>,
psiMethods: List<PsiMethod>, psiMethods: List<PsiMethod>,
getPsi: (Parameter) -> KtParameter, getPsi: (Parameter) -> KtParameter,
getDefaultValue: (Parameter) -> KtExpression? getDefaultValue: (Parameter) -> KtExpression?
): List<JvmOverloadSignature> { ): List<JvmOverloadSignature> {
val defaultValueCount = parameters.count { getDefaultValue(it) != null } val defaultValueCount = parameters.count { getDefaultValue(it) != null }
if (psiMethods.size != defaultValueCount + 1) return emptyList() if (psiMethods.size != defaultValueCount + 1) return emptyList()
val mandatoryParams = parameters.toMutableList() val mandatoryParams = parameters.toMutableList()
val defaultValues = ArrayList<KtExpression>() val defaultValues = ArrayList<KtExpression>()
return psiMethods.map { return psiMethods.map { method ->
JvmOverloadSignature(it, mandatoryParams.asSequence().map(getPsi).toSet(), defaultValues.toSet()).apply { JvmOverloadSignature(method, mandatoryParams.asSequence().map(getPsi).toSet(), defaultValues.toSet()).apply {
val param = mandatoryParams.removeLast { getDefaultValue(it) != null } ?: return@apply val param = mandatoryParams.removeLast { getDefaultValue(it) != null } ?: return@apply
defaultValues.add(getDefaultValue(param)!!) defaultValues.add(getDefaultValue(param)!!)
} }
@@ -357,8 +358,9 @@ open class KotlinChangeInfo(
fun matchOriginalAndCurrentMethods(currentPsiMethods: List<PsiMethod>): Map<PsiMethod, PsiMethod> { fun matchOriginalAndCurrentMethods(currentPsiMethods: List<PsiMethod>): Map<PsiMethod, PsiMethod> {
if (!(isPrimaryMethodUpdated if (!(isPrimaryMethodUpdated
&& originalBaseFunctionDescriptor is FunctionDescriptor && originalBaseFunctionDescriptor is FunctionDescriptor
&& originalBaseFunctionDescriptor.findJvmOverloadsAnnotation() != null)) { && originalBaseFunctionDescriptor.findJvmOverloadsAnnotation() != null)
) {
return (originalPsiMethods.zip(currentPsiMethods)).toMap() return (originalPsiMethods.zip(currentPsiMethods)).toMap()
} }
@@ -384,30 +386,31 @@ open class KotlinChangeInfo(
* So we resort to this hack and pass around "default" type (void) and visibility (package-local) * So we resort to this hack and pass around "default" type (void) and visibility (package-local)
*/ */
fun createJavaChangeInfo(originalPsiMethod: PsiMethod, fun createJavaChangeInfo(
currentPsiMethod: PsiMethod, originalPsiMethod: PsiMethod,
newName: String, currentPsiMethod: PsiMethod,
newReturnType: PsiType?, newName: String,
newParameters: Array<ParameterInfoImpl> newReturnType: PsiType?,
newParameters: Array<ParameterInfoImpl>
): JavaChangeInfo? { ): JavaChangeInfo? {
val newVisibility = if (isPrimaryMethodUpdated) val newVisibility = if (isPrimaryMethodUpdated)
VisibilityUtil.getVisibilityModifier(currentPsiMethod.modifierList) VisibilityUtil.getVisibilityModifier(currentPsiMethod.modifierList)
else else
PsiModifier.PACKAGE_LOCAL PsiModifier.PACKAGE_LOCAL
val propagationTargets = primaryPropagationTargets.asSequence() val propagationTargets = primaryPropagationTargets.asSequence()
.mapNotNull { it.getRepresentativeLightMethod() } .mapNotNull { it.getRepresentativeLightMethod() }
.toSet() .toSet()
val javaChangeInfo = ChangeSignatureProcessor( val javaChangeInfo = ChangeSignatureProcessor(
method.project, method.project,
originalPsiMethod, originalPsiMethod,
false, false,
newVisibility, newVisibility,
newName, newName,
CanonicalTypes.createTypeWrapper(newReturnType ?: PsiType.VOID), CanonicalTypes.createTypeWrapper(newReturnType ?: PsiType.VOID),
newParameters, newParameters,
arrayOf<ThrownExceptionInfo>(), arrayOf<ThrownExceptionInfo>(),
propagationTargets, propagationTargets,
emptySet() emptySet()
).changeInfo ).changeInfo
javaChangeInfo.updateMethod(currentPsiMethod) javaChangeInfo.updateMethod(currentPsiMethod)
@@ -415,9 +418,9 @@ open class KotlinChangeInfo(
} }
fun getJavaParameterInfos( fun getJavaParameterInfos(
originalPsiMethod: PsiMethod, originalPsiMethod: PsiMethod,
currentPsiMethod: PsiMethod, currentPsiMethod: PsiMethod,
newParameterList: List<KotlinParameterInfo> newParameterList: List<KotlinParameterInfo>
): MutableList<ParameterInfoImpl> { ): MutableList<ParameterInfoImpl> {
val defaultValuesToSkip = newParameterList.size - currentPsiMethod.parameterList.parametersCount val defaultValuesToSkip = newParameterList.size - currentPsiMethod.parameterList.parametersCount
val defaultValuesToRetain = newParameterList.count { it.defaultValueForParameter != null } - defaultValuesToSkip val defaultValuesToRetain = newParameterList.count { it.defaultValueForParameter != null } - defaultValuesToSkip
@@ -427,41 +430,42 @@ open class KotlinChangeInfo(
var defaultValuesRemained = defaultValuesToRetain var defaultValuesRemained = defaultValuesToRetain
for (param in newParameterList) { for (param in newParameterList) {
if (param.isNewParameter || param.defaultValueForParameter == null || defaultValuesRemained-- > 0) continue if (param.isNewParameter || param.defaultValueForParameter == null || defaultValuesRemained-- > 0) continue
newParameterList.asSequence().withIndex().filter { it.value.oldIndex >= param.oldIndex }.toList().forEach { oldIndices[it.index]-- } newParameterList.asSequence().withIndex().filter { it.value.oldIndex >= param.oldIndex }.toList()
.forEach { oldIndices[it.index]-- }
} }
defaultValuesRemained = defaultValuesToRetain defaultValuesRemained = defaultValuesToRetain
val oldParameterCount = originalPsiMethod.parameterList.parametersCount val oldParameterCount = originalPsiMethod.parameterList.parametersCount
var indexInCurrentPsiMethod = 0 var indexInCurrentPsiMethod = 0
return newParameterList.asSequence().withIndex() return newParameterList.asSequence().withIndex()
.mapNotNullTo(ArrayList()) map@ { pair -> .mapNotNullTo(ArrayList()) map@{ pair ->
val (i, info) = pair val (i, info) = pair
if (info.defaultValueForParameter != null && defaultValuesRemained-- <= 0) return@map null if (info.defaultValueForParameter != null && defaultValuesRemained-- <= 0) return@map null
val oldIndex = oldIndices[i] val oldIndex = oldIndices[i]
val javaOldIndex = when { val javaOldIndex = when {
methodDescriptor.receiver == null -> oldIndex methodDescriptor.receiver == null -> oldIndex
info == methodDescriptor.receiver -> 0 info == methodDescriptor.receiver -> 0
oldIndex >= 0 -> oldIndex + 1 oldIndex >= 0 -> oldIndex + 1
else -> -1 else -> -1
}
if (javaOldIndex >= oldParameterCount) return@map null
val type = if (isPrimaryMethodUpdated)
currentPsiMethod.parameterList.parameters[indexInCurrentPsiMethod++].type
else
PsiType.VOID
val defaultValue = info.defaultValueForCall ?: info.defaultValueForParameter
ParameterInfoImpl(javaOldIndex, info.name, type, defaultValue?.text ?: "")
} }
if (javaOldIndex >= oldParameterCount) return@map null
val type = if (isPrimaryMethodUpdated)
currentPsiMethod.parameterList.parameters[indexInCurrentPsiMethod++].type
else
PsiType.VOID
val defaultValue = info.defaultValueForCall ?: info.defaultValueForParameter
ParameterInfoImpl(javaOldIndex, info.name, type, defaultValue?.text ?: "")
}
} }
fun createJavaChangeInfoForFunctionOrGetter( fun createJavaChangeInfoForFunctionOrGetter(
originalPsiMethod: PsiMethod, originalPsiMethod: PsiMethod,
currentPsiMethod: PsiMethod, currentPsiMethod: PsiMethod,
isGetter: Boolean isGetter: Boolean
): JavaChangeInfo? { ): JavaChangeInfo? {
val newParameterList = listOfNotNull(receiverParameterInfo) + getNonReceiverParameters() val newParameterList = listOfNotNull(receiverParameterInfo) + getNonReceiverParameters()
val newJavaParameters = getJavaParameterInfos(originalPsiMethod, currentPsiMethod, newParameterList).toTypedArray() val newJavaParameters = getJavaParameterInfos(originalPsiMethod, currentPsiMethod, newParameterList).toTypedArray()
@@ -476,8 +480,7 @@ open class KotlinChangeInfo(
val newIndex = if (receiverParameterInfo != null) 1 else 0 val newIndex = if (receiverParameterInfo != null) 1 else 0
val setterParameter = currentPsiMethod.parameterList.parameters[newIndex] val setterParameter = currentPsiMethod.parameterList.parameters[newIndex]
newJavaParameters.add(ParameterInfoImpl(oldIndex, setterParameter.name, setterParameter.type)) newJavaParameters.add(ParameterInfoImpl(oldIndex, setterParameter.name, setterParameter.type))
} } else {
else {
newJavaParameters.add(ParameterInfoImpl(oldIndex, "receiver", PsiType.VOID)) newJavaParameters.add(ParameterInfoImpl(oldIndex, "receiver", PsiType.VOID))
} }
@@ -526,8 +529,8 @@ val KotlinChangeInfo.oldName: String?
fun KotlinChangeInfo.getAffectedCallables(): Collection<UsageInfo> = methodDescriptor.affectedCallables + propagationTargetUsageInfos fun KotlinChangeInfo.getAffectedCallables(): Collection<UsageInfo> = methodDescriptor.affectedCallables + propagationTargetUsageInfos
fun ChangeInfo.toJetChangeInfo( fun ChangeInfo.toJetChangeInfo(
originalChangeSignatureDescriptor: KotlinMethodDescriptor, originalChangeSignatureDescriptor: KotlinMethodDescriptor,
resolutionFacade: ResolutionFacade resolutionFacade: ResolutionFacade
): KotlinChangeInfo { ): KotlinChangeInfo {
val method = method as PsiMethod val method = method as PsiMethod
@@ -544,34 +547,38 @@ fun ChangeInfo.toJetChangeInfo(
val defaultValueText = info.defaultValue val defaultValueText = info.defaultValue
val defaultValueExpr = val defaultValueExpr =
when { when {
info is KotlinAwareJavaParameterInfoImpl -> info.kotlinDefaultValue info is KotlinAwareJavaParameterInfoImpl -> info.kotlinDefaultValue
language.`is`(JavaLanguage.INSTANCE) && !defaultValueText.isNullOrEmpty() -> { language.`is`(JavaLanguage.INSTANCE) && !defaultValueText.isNullOrEmpty() -> {
PsiElementFactory.SERVICE.getInstance(method.project) PsiElementFactory.SERVICE.getInstance(method.project)
.createExpressionFromText(defaultValueText!!, null) .createExpressionFromText(defaultValueText, null)
.j2k() .j2k()
}
else -> null
} }
else -> null
}
val parameterType = if (oldIndex >= 0) originalParameterDescriptors[oldIndex].type else currentType val parameterType = if (oldIndex >= 0) originalParameterDescriptors[oldIndex].type else currentType
val originalKtParameter = originalParameterDescriptors.getOrNull(oldIndex)?.source?.getPsi() as? KtParameter val originalKtParameter = originalParameterDescriptors.getOrNull(oldIndex)?.source?.getPsi() as? KtParameter
val valOrVar = originalKtParameter?.valOrVarKeyword?.toValVar() ?: KotlinValVar.None val valOrVar = originalKtParameter?.valOrVarKeyword?.toValVar() ?: KotlinValVar.None
KotlinParameterInfo(callableDescriptor = functionDescriptor, KotlinParameterInfo(
originalIndex = oldIndex, callableDescriptor = functionDescriptor,
name = info.name, originalIndex = oldIndex,
originalTypeInfo = KotlinTypeInfo(false, parameterType), name = info.name,
defaultValueForCall = defaultValueExpr, originalTypeInfo = KotlinTypeInfo(false, parameterType),
valOrVar = valOrVar).apply { defaultValueForCall = defaultValueExpr,
valOrVar = valOrVar
).apply {
currentTypeInfo = KotlinTypeInfo(false, currentType) currentTypeInfo = KotlinTypeInfo(false, currentType)
} }
} }
return KotlinChangeInfo(originalChangeSignatureDescriptor, return KotlinChangeInfo(
newName, originalChangeSignatureDescriptor,
KotlinTypeInfo(true, functionDescriptor.returnType), newName,
functionDescriptor.visibility, KotlinTypeInfo(true, functionDescriptor.returnType),
newParameters, functionDescriptor.visibility,
null, newParameters,
method) null,
method
)
} }
@@ -20,7 +20,6 @@ import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Ref import com.intellij.openapi.util.Ref
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.refactoring.BaseRefactoringProcessor
import com.intellij.refactoring.RefactoringBundle import com.intellij.refactoring.RefactoringBundle
import com.intellij.refactoring.changeSignature.ChangeSignatureProcessorBase import com.intellij.refactoring.changeSignature.ChangeSignatureProcessorBase
import com.intellij.refactoring.changeSignature.ChangeSignatureUsageProcessor import com.intellij.refactoring.changeSignature.ChangeSignatureUsageProcessor
@@ -38,9 +37,9 @@ import org.jetbrains.kotlin.idea.refactoring.changeSignature.usages.KotlinWrappe
import java.util.* import java.util.*
class KotlinChangeSignatureProcessor( class KotlinChangeSignatureProcessor(
project: Project, project: Project,
changeInfo: KotlinChangeInfo, changeInfo: KotlinChangeInfo,
private val commandName: String private val commandName: String
) : ChangeSignatureProcessorBase(project, KotlinChangeInfoWrapper(changeInfo)) { ) : ChangeSignatureProcessorBase(project, KotlinChangeInfoWrapper(changeInfo)) {
val ktChangeInfo val ktChangeInfo
get() = changeInfo.delegate!! get() = changeInfo.delegate!!
@@ -80,7 +79,7 @@ class KotlinChangeSignatureProcessor(
if (!usageProcessors.all { it.setupDefaultValues(myChangeInfo, refUsages, myProject) }) return false if (!usageProcessors.all { it.setupDefaultValues(myChangeInfo, refUsages, myProject) }) return false
val conflictDescriptions = object: MultiMap<PsiElement, String>() { val conflictDescriptions = object : MultiMap<PsiElement, String>() {
override fun createCollection() = LinkedHashSet<String>() override fun createCollection() = LinkedHashSet<String>()
} }
usageProcessors.forEach { conflictDescriptions.putAllValues(it.findConflicts(myChangeInfo, refUsages)) } usageProcessors.forEach { conflictDescriptions.putAllValues(it.findConflicts(myChangeInfo, refUsages)) }
@@ -92,7 +91,7 @@ class KotlinChangeSignatureProcessor(
RenameUtil.removeConflictUsages(usagesSet) RenameUtil.removeConflictUsages(usagesSet)
if (!conflictDescriptions.isEmpty) { if (!conflictDescriptions.isEmpty) {
if (ApplicationManager.getApplication().isUnitTestMode) { if (ApplicationManager.getApplication().isUnitTestMode) {
throw BaseRefactoringProcessor.ConflictsInTestsException(conflictDescriptions.values()) throw ConflictsInTestsException(conflictDescriptions.values())
} }
val dialog = prepareConflictsDialog(conflictDescriptions, usages) val dialog = prepareConflictsDialog(conflictDescriptions, usages)
@@ -127,8 +126,7 @@ class KotlinChangeSignatureProcessor(
override fun performRefactoring(usages: Array<out UsageInfo>) { override fun performRefactoring(usages: Array<out UsageInfo>) {
try { try {
super.performRefactoring(usages) super.performRefactoring(usages)
} } finally {
finally {
changeInfo.invalidate() changeInfo.invalidate()
} }
} }
@@ -65,10 +65,10 @@ import java.util.*
import javax.swing.* import javax.swing.*
class KotlinChangeSignatureDialog( class KotlinChangeSignatureDialog(
project: Project, project: Project,
methodDescriptor: KotlinMethodDescriptor, methodDescriptor: KotlinMethodDescriptor,
context: PsiElement, context: PsiElement,
private val commandName: String? private val commandName: String?
) : ChangeSignatureDialogBase< ) : ChangeSignatureDialogBase<
KotlinParameterInfo, KotlinParameterInfo,
PsiElement, PsiElement,
@@ -76,15 +76,20 @@ class KotlinChangeSignatureDialog(
KotlinMethodDescriptor, KotlinMethodDescriptor,
ParameterTableModelItemBase<KotlinParameterInfo>, ParameterTableModelItemBase<KotlinParameterInfo>,
KotlinCallableParameterTableModel>(project, methodDescriptor, false, context) { KotlinCallableParameterTableModel>(project, methodDescriptor, false, context) {
override fun getFileType() = KotlinFileType.INSTANCE override fun getFileType(): KotlinFileType = KotlinFileType.INSTANCE
override fun createParametersInfoModel(descriptor: KotlinMethodDescriptor) = createParametersInfoModel(descriptor, myDefaultValueContext) override fun createParametersInfoModel(descriptor: KotlinMethodDescriptor) =
createParametersInfoModel(descriptor, myDefaultValueContext)
override fun createReturnTypeCodeFragment() = createReturnTypeCodeFragment(myProject, myMethod) override fun createReturnTypeCodeFragment() = createReturnTypeCodeFragment(myProject, myMethod)
private val parametersTableModel: KotlinCallableParameterTableModel get() = super.myParametersTableModel private val parametersTableModel: KotlinCallableParameterTableModel get() = super.myParametersTableModel
override fun getRowPresentation(item: ParameterTableModelItemBase<KotlinParameterInfo>, selected: Boolean, focused: Boolean): JComponent? { override fun getRowPresentation(
item: ParameterTableModelItemBase<KotlinParameterInfo>,
selected: Boolean,
focused: Boolean
): JComponent? {
val panel = JPanel(BorderLayout()) val panel = JPanel(BorderLayout())
val valOrVar = if (myMethod.kind === Kind.PRIMARY_CONSTRUCTOR) { val valOrVar = if (myMethod.kind === Kind.PRIMARY_CONSTRUCTOR) {
@@ -93,8 +98,7 @@ class KotlinChangeSignatureDialog(
KotlinValVar.Val -> "val " KotlinValVar.Val -> "val "
KotlinValVar.Var -> "var " KotlinValVar.Var -> "var "
} }
} } else {
else {
"" ""
} }
@@ -112,14 +116,13 @@ class KotlinChangeSignatureDialog(
override fun shouldHaveBorder() = false override fun shouldHaveBorder() = false
} }
val plainFont = EditorColorsManager.getInstance().globalScheme.getFont(EditorFontType.PLAIN) val plainFont = EditorColorsManager.getInstance().globalScheme.getFont(EditorFontType.PLAIN)
field.font = Font(plainFont.fontName, plainFont.style, 12) field.font = Font(plainFont.fontName, plainFont.style, 12)
if (selected && focused) { if (selected && focused) {
panel.background = UIUtil.getTableSelectionBackground() panel.background = UIUtil.getTableSelectionBackground()
field.setAsRendererWithSelection(UIUtil.getTableSelectionBackground(), UIUtil.getTableSelectionForeground()) field.setAsRendererWithSelection(UIUtil.getTableSelectionBackground(), UIUtil.getTableSelectionForeground())
} } else {
else {
panel.background = UIUtil.getTableBackground() panel.background = UIUtil.getTableBackground()
if (selected && !focused) { if (selected && !focused) {
panel.border = DottedBorder(UIUtil.getTableForeground()) panel.border = DottedBorder(UIUtil.getTableForeground())
@@ -136,7 +139,7 @@ class KotlinChangeSignatureDialog(
} }
private fun getColumnTextMaxLength(nameFunction: Function1<ParameterTableModelItemBase<KotlinParameterInfo>, String?>) = private fun getColumnTextMaxLength(nameFunction: Function1<ParameterTableModelItemBase<KotlinParameterInfo>, String?>) =
parametersTableModel.items.asSequence().map { nameFunction(it)?.length ?: 0 }.max() ?: 0 parametersTableModel.items.asSequence().map { nameFunction(it)?.length ?: 0 }.max() ?: 0
private fun getParamNamesMaxLength() = getColumnTextMaxLength { getPresentationName(it) } private fun getParamNamesMaxLength() = getColumnTextMaxLength { getPresentationName(it) }
@@ -147,17 +150,17 @@ class KotlinChangeSignatureDialog(
override fun isListTableViewSupported() = true override fun isListTableViewSupported() = true
override fun isEmptyRow(row: ParameterTableModelItemBase<KotlinParameterInfo>): Boolean { override fun isEmptyRow(row: ParameterTableModelItemBase<KotlinParameterInfo>): Boolean {
if (!row.parameter.name.isEmpty()) return false if (row.parameter.name.isNotEmpty()) return false
if (!row.parameter.typeText.isEmpty()) return false if (row.parameter.typeText.isNotEmpty()) return false
return true return true
} }
override fun createCallerChooser(title: String, treeToReuse: Tree?, callback: Consumer<Set<PsiElement>>) = override fun createCallerChooser(title: String, treeToReuse: Tree?, callback: Consumer<Set<PsiElement>>) =
KotlinCallerChooser(myMethod.method, myProject, title, treeToReuse, callback) KotlinCallerChooser(myMethod.method, myProject, title, treeToReuse, callback)
// Forbid receiver propagation // Forbid receiver propagation
override fun mayPropagateParameters() = override fun mayPropagateParameters() =
parameters.any { it.isNewParameter && it != parametersTableModel.receiver } parameters.any { it.isNewParameter && it != parametersTableModel.receiver }
override fun getTableEditor(table: JTable, item: ParameterTableModelItemBase<KotlinParameterInfo>): JBTableRowEditor? { override fun getTableEditor(table: JTable, item: ParameterTableModelItemBase<KotlinParameterInfo>): JBTableRowEditor? {
return object : JBTableRowEditor() { return object : JBTableRowEditor() {
@@ -169,7 +172,7 @@ class KotlinChangeSignatureDialog(
} }
private fun isDefaultColumnEnabled() = private fun isDefaultColumnEnabled() =
item.parameter.isNewParameter && item.parameter != myMethod.receiver item.parameter.isNewParameter && item.parameter != myMethod.receiver
override fun prepareEditor(table: JTable, row: Int) { override fun prepareEditor(table: JTable, row: Int) {
layout = BoxLayout(this, BoxLayout.X_AXIS) layout = BoxLayout(this, BoxLayout.X_AXIS)
@@ -185,18 +188,15 @@ class KotlinChangeSignatureDialog(
val document = PsiDocumentManager.getInstance(project).getDocument(item.typeCodeFragment) val document = PsiDocumentManager.getInstance(project).getDocument(item.typeCodeFragment)
editor = EditorTextField(document, project, fileType) editor = EditorTextField(document, project, fileType)
component = editor component = editor
} } else if (KotlinCallableParameterTableModel.isNameColumn(columnInfo)) {
else if (KotlinCallableParameterTableModel.isNameColumn(columnInfo)) {
editor = nameEditor editor = nameEditor
component = editor component = editor
updateNameEditor() updateNameEditor()
} } else if (KotlinCallableParameterTableModel.isDefaultValueColumn(columnInfo) && isDefaultColumnEnabled()) {
else if (KotlinCallableParameterTableModel.isDefaultValueColumn(columnInfo) && isDefaultColumnEnabled()) {
val document = PsiDocumentManager.getInstance(project).getDocument(item.defaultValueCodeFragment) val document = PsiDocumentManager.getInstance(project).getDocument(item.defaultValueCodeFragment)
editor = EditorTextField(document, project, fileType) editor = EditorTextField(document, project, fileType)
component = editor component = editor
} } else if (KotlinPrimaryConstructorParameterTableModel.isValVarColumn(columnInfo)) {
else if (KotlinPrimaryConstructorParameterTableModel.isValVarColumn(columnInfo)) {
val comboBox = JComboBox(KotlinValVar.values()) val comboBox = JComboBox(KotlinValVar.values())
comboBox.selectedItem = item.parameter.valOrVar comboBox.selectedItem = item.parameter.valOrVar
comboBox.addItemListener { comboBox.addItemListener {
@@ -205,8 +205,7 @@ class KotlinChangeSignatureDialog(
} }
component = comboBox component = comboBox
editor = null editor = null
} } else if (KotlinFunctionParameterTableModel.isReceiverColumn(columnInfo)) {
else if (KotlinFunctionParameterTableModel.isReceiverColumn(columnInfo)) {
val checkBox = JCheckBox() val checkBox = JCheckBox()
checkBox.isSelected = parametersTableModel.receiver == item.parameter checkBox.isSelected = parametersTableModel.receiver == item.parameter
checkBox.addItemListener { checkBox.addItemListener {
@@ -217,8 +216,7 @@ class KotlinChangeSignatureDialog(
} }
component = checkBox component = checkBox
editor = null editor = null
} } else
else
continue continue
val label = JBLabel(columnInfo.name, UIUtil.ComponentStyle.SMALL) val label = JBLabel(columnInfo.name, UIUtil.ComponentStyle.SMALL)
@@ -226,11 +224,11 @@ class KotlinChangeSignatureDialog(
if (editor != null) { if (editor != null) {
editor.addDocumentListener( editor.addDocumentListener(
object : DocumentListener { object : DocumentListener {
override fun documentChanged(e: DocumentEvent) { override fun documentChanged(e: DocumentEvent) {
fireDocumentChanged(e, columnFinal) fireDocumentChanged(e, columnFinal)
}
} }
}
) )
editor.setPreferredWidth(table.width / parametersTableModel.columnCount) editor.setPreferredWidth(table.width / parametersTableModel.columnCount)
} }
@@ -277,7 +275,7 @@ class KotlinChangeSignatureDialog(
intArrayOf(4, getParamNamesMaxLength(), getTypesMaxLength()) intArrayOf(4, getParamNamesMaxLength(), getTypesMaxLength())
var columnIndex = 0 var columnIndex = 0
for (i in (if (myMethod.kind === Kind.PRIMARY_CONSTRUCTOR) 0 else 1)..columnLetters.size - 1) { for (i in (if (myMethod.kind === Kind.PRIMARY_CONSTRUCTOR) 0 else 1) until columnLetters.size) {
val width = getColumnWidth(columnLetters[i]) val width = getColumnWidth(columnLetters[i])
if (x <= width) if (x <= width)
@@ -311,18 +309,20 @@ class KotlinChangeSignatureDialog(
} }
override fun calculateSignature(): String { override fun calculateSignature(): String {
val changeInfo = evaluateChangeInfo(parametersTableModel, val changeInfo = evaluateChangeInfo(
myReturnTypeCodeFragment, parametersTableModel,
getMethodDescriptor(), myReturnTypeCodeFragment,
visibility, getMethodDescriptor(),
methodName, visibility,
myDefaultValueContext, methodName,
true) myDefaultValueContext,
true
)
return changeInfo.getNewSignature(getMethodDescriptor().originalPrimaryCallable) return changeInfo.getNewSignature(getMethodDescriptor().originalPrimaryCallable)
} }
override fun createVisibilityControl() = ComboBoxVisibilityPanel( override fun createVisibilityControl() = ComboBoxVisibilityPanel(
arrayOf(Visibilities.INTERNAL, Visibilities.PRIVATE, Visibilities.PROTECTED, Visibilities.PUBLIC) arrayOf(Visibilities.INTERNAL, Visibilities.PRIVATE, Visibilities.PROTECTED, Visibilities.PUBLIC)
) )
override fun updateSignatureAlarmFired() { override fun updateSignatureAlarmFired() {
@@ -332,27 +332,30 @@ class KotlinChangeSignatureDialog(
override fun validateAndCommitData(): String? { override fun validateAndCommitData(): String? {
if (myMethod.canChangeReturnType() == MethodDescriptor.ReadWriteOption.ReadWrite && if (myMethod.canChangeReturnType() == MethodDescriptor.ReadWriteOption.ReadWrite &&
myReturnTypeCodeFragment.getTypeInfo(true, false).type == null) { myReturnTypeCodeFragment.getTypeInfo(isCovariant = true, forPreview = false).type == null
) {
if (Messages.showOkCancelDialog( if (Messages.showOkCancelDialog(
myProject, myProject,
"Return type '${myReturnTypeCodeFragment!!.text}' cannot be resolved.\nContinue?", "Return type '${myReturnTypeCodeFragment!!.text}' cannot be resolved.\nContinue?",
RefactoringBundle.message("changeSignature.refactoring.name"), RefactoringBundle.message("changeSignature.refactoring.name"),
Messages.getWarningIcon() Messages.getWarningIcon()
) != Messages.OK) { ) != Messages.OK
return ChangeSignatureDialogBase.EXIT_SILENTLY ) {
return EXIT_SILENTLY
} }
} }
for (item in parametersTableModel.items) { for (item in parametersTableModel.items) {
if (item.typeCodeFragment.getTypeInfo(true, false).type == null) { if (item.typeCodeFragment.getTypeInfo(isCovariant = true, forPreview = false).type == null) {
val paramText = if (item.parameter != parametersTableModel.receiver) "parameter '${item.parameter.name}'" else "receiver" val paramText = if (item.parameter != parametersTableModel.receiver) "parameter '${item.parameter.name}'" else "receiver"
if (Messages.showOkCancelDialog( if (Messages.showOkCancelDialog(
myProject, myProject,
"Type '${item.typeCodeFragment.text}' for $paramText cannot be resolved.\nContinue?", "Type '${item.typeCodeFragment.text}' for $paramText cannot be resolved.\nContinue?",
RefactoringBundle.message("changeSignature.refactoring.name"), RefactoringBundle.message("changeSignature.refactoring.name"),
Messages.getWarningIcon() Messages.getWarningIcon()
) != Messages.OK) { ) != Messages.OK
return ChangeSignatureDialogBase.EXIT_SILENTLY ) {
return EXIT_SILENTLY
} }
} }
} }
@@ -366,7 +369,7 @@ class KotlinChangeSignatureDialog(
if (myMethod.canChangeReturnType() === MethodDescriptor.ReadWriteOption.ReadWrite) { if (myMethod.canChangeReturnType() === MethodDescriptor.ReadWriteOption.ReadWrite) {
(myReturnTypeCodeFragment as? KtTypeCodeFragment) (myReturnTypeCodeFragment as? KtTypeCodeFragment)
?.validateElement(KotlinRefactoringBundle.message("return.type.is.invalid")) ?.validateElement(KotlinRefactoringBundle.message("return.type.is.invalid"))
} }
for (item in parametersTableModel.items) { for (item in parametersTableModel.items) {
@@ -377,18 +380,20 @@ class KotlinChangeSignatureDialog(
} }
(item.typeCodeFragment as? KtTypeCodeFragment) (item.typeCodeFragment as? KtTypeCodeFragment)
?.validateElement(KotlinRefactoringBundle.message("parameter.type.is.invalid", item.typeCodeFragment.text)) ?.validateElement(KotlinRefactoringBundle.message("parameter.type.is.invalid", item.typeCodeFragment.text))
} }
} }
override fun createRefactoringProcessor(): BaseRefactoringProcessor { override fun createRefactoringProcessor(): BaseRefactoringProcessor {
val changeInfo = evaluateChangeInfo(parametersTableModel, val changeInfo = evaluateChangeInfo(
myReturnTypeCodeFragment, parametersTableModel,
getMethodDescriptor(), myReturnTypeCodeFragment,
visibility, getMethodDescriptor(),
methodName, visibility,
myDefaultValueContext, methodName,
false) myDefaultValueContext,
false
)
changeInfo.primaryPropagationTargets = myMethodsToPropagateParameters ?: emptyList() changeInfo.primaryPropagationTargets = myMethodsToPropagateParameters ?: emptyList()
return KotlinChangeSignatureProcessor(myProject, changeInfo, commandName ?: title) return KotlinChangeSignatureProcessor(myProject, changeInfo, commandName ?: title)
} }
@@ -397,16 +402,19 @@ class KotlinChangeSignatureDialog(
override fun getSelectedIdx(): Int { override fun getSelectedIdx(): Int {
return myMethod.parameters.withIndex().firstOrNull { it.value.isNewParameter }?.index return myMethod.parameters.withIndex().firstOrNull { it.value.isNewParameter }?.index
?: super.getSelectedIdx() ?: super.getSelectedIdx()
} }
companion object { companion object {
private fun createParametersInfoModel(descriptor: KotlinMethodDescriptor, defaultValueContext: PsiElement): KotlinCallableParameterTableModel { private fun createParametersInfoModel(
descriptor: KotlinMethodDescriptor,
defaultValueContext: PsiElement
): KotlinCallableParameterTableModel {
val typeContext = getTypeCodeFragmentContext(descriptor.baseDeclaration) val typeContext = getTypeCodeFragmentContext(descriptor.baseDeclaration)
return when (descriptor.kind) { return when (descriptor.kind) {
KotlinMethodDescriptor.Kind.FUNCTION -> KotlinFunctionParameterTableModel(descriptor, typeContext, defaultValueContext) Kind.FUNCTION -> KotlinFunctionParameterTableModel(descriptor, typeContext, defaultValueContext)
KotlinMethodDescriptor.Kind.PRIMARY_CONSTRUCTOR -> KotlinPrimaryConstructorParameterTableModel(descriptor, typeContext, defaultValueContext) Kind.PRIMARY_CONSTRUCTOR -> KotlinPrimaryConstructorParameterTableModel(descriptor, typeContext, defaultValueContext)
KotlinMethodDescriptor.Kind.SECONDARY_CONSTRUCTOR -> KotlinSecondaryConstructorParameterTableModel(descriptor, typeContext, defaultValueContext) Kind.SECONDARY_CONSTRUCTOR -> KotlinSecondaryConstructorParameterTableModel(descriptor, typeContext, defaultValueContext)
} }
} }
@@ -425,21 +433,25 @@ class KotlinChangeSignatureDialog(
} }
private fun createReturnTypeCodeFragment(project: Project, method: KotlinMethodDescriptor) = private fun createReturnTypeCodeFragment(project: Project, method: KotlinMethodDescriptor) =
KtPsiFactory(project).createTypeCodeFragment(method.returnTypeInfo.render(), getTypeCodeFragmentContext(method.baseDeclaration)) KtPsiFactory(project).createTypeCodeFragment(method.returnTypeInfo.render(), getTypeCodeFragmentContext(method.baseDeclaration))
fun createRefactoringProcessorForSilentChangeSignature(project: Project, fun createRefactoringProcessorForSilentChangeSignature(
commandName: String, project: Project,
method: KotlinMethodDescriptor, commandName: String,
defaultValueContext: PsiElement): BaseRefactoringProcessor { method: KotlinMethodDescriptor,
defaultValueContext: PsiElement
): BaseRefactoringProcessor {
val parameterTableModel = createParametersInfoModel(method, defaultValueContext) val parameterTableModel = createParametersInfoModel(method, defaultValueContext)
parameterTableModel.setParameterInfos(method.parameters) parameterTableModel.setParameterInfos(method.parameters)
val changeInfo = evaluateChangeInfo(parameterTableModel, val changeInfo = evaluateChangeInfo(
createReturnTypeCodeFragment(project, method), parameterTableModel,
method, createReturnTypeCodeFragment(project, method),
method.visibility, method,
method.name, method.visibility,
defaultValueContext, method.name,
false) defaultValueContext,
false
)
return KotlinChangeSignatureProcessor(project, changeInfo, commandName) return KotlinChangeSignatureProcessor(project, changeInfo, commandName)
} }
@@ -455,13 +467,15 @@ class KotlinChangeSignatureDialog(
} }
} }
private fun evaluateChangeInfo(parametersModel: KotlinCallableParameterTableModel, private fun evaluateChangeInfo(
returnTypeCodeFragment: PsiCodeFragment?, parametersModel: KotlinCallableParameterTableModel,
methodDescriptor: KotlinMethodDescriptor, returnTypeCodeFragment: PsiCodeFragment?,
visibility: Visibility?, methodDescriptor: KotlinMethodDescriptor,
methodName: String, visibility: Visibility?,
defaultValueContext: PsiElement, methodName: String,
forPreview: Boolean): KotlinChangeInfo { defaultValueContext: PsiElement,
forPreview: Boolean
): KotlinChangeInfo {
val parameters = parametersModel.items.map { parameter -> val parameters = parametersModel.items.map { parameter ->
val parameterInfo = parameter.parameter val parameterInfo = parameter.parameter
@@ -476,13 +490,15 @@ class KotlinChangeSignatureDialog(
parameterInfo parameterInfo
} }
return KotlinChangeInfo(methodDescriptor.original, return KotlinChangeInfo(
methodName, methodDescriptor.original,
returnTypeCodeFragment.getTypeInfo(true, forPreview), methodName,
visibility ?: Visibilities.DEFAULT_VISIBILITY, returnTypeCodeFragment.getTypeInfo(true, forPreview),
parameters, visibility ?: Visibilities.DEFAULT_VISIBILITY,
parametersModel.receiver, parameters,
defaultValueContext) parametersModel.receiver,
defaultValueContext
)
} }
} }
} }
@@ -131,7 +131,7 @@ class KotlinCallableDefinitionUsage<T : PsiElement>(
val receiverTypeText = changeInfo.renderReceiverType(this) val receiverTypeText = changeInfo.renderReceiverType(this)
val receiverTypeRef = if (receiverTypeText != null) psiFactory.createType(receiverTypeText) else null val receiverTypeRef = if (receiverTypeText != null) psiFactory.createType(receiverTypeText) else null
val newReceiverTypeRef = element.setReceiverTypeReference(receiverTypeRef) val newReceiverTypeRef = element.setReceiverTypeReference(receiverTypeRef)
newReceiverTypeRef?.addToShorteningWaitSet(ShortenReferences.Options.DEFAULT) newReceiverTypeRef?.addToShorteningWaitSet(Options.DEFAULT)
} }
if (changeInfo.isVisibilityChanged() && !KtPsiUtil.isLocal(element as KtDeclaration)) { if (changeInfo.isVisibilityChanged() && !KtPsiUtil.isLocal(element as KtDeclaration)) {
@@ -25,6 +25,7 @@ import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet import org.jetbrains.kotlin.idea.codeInsight.shorten.addToShorteningWaitSet
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.core.moveFunctionLiteralOutsideParentheses import org.jetbrains.kotlin.idea.core.moveFunctionLiteralOutsideParentheses
import org.jetbrains.kotlin.idea.core.replaced import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinChangeInfo import org.jetbrains.kotlin.idea.refactoring.changeSignature.KotlinChangeInfo
@@ -33,7 +34,6 @@ import org.jetbrains.kotlin.idea.refactoring.changeSignature.isInsideOfCallerBod
import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.createNameCounterpartMap import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.createNameCounterpartMap
import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler import org.jetbrains.kotlin.idea.refactoring.introduce.introduceVariable.KotlinIntroduceVariableHandler
import org.jetbrains.kotlin.idea.refactoring.replaceListPsiAndKeepDelimiters import org.jetbrains.kotlin.idea.refactoring.replaceListPsiAndKeepDelimiters
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -55,9 +55,9 @@ import org.jetbrains.kotlin.utils.sure
import java.util.* import java.util.*
class KotlinFunctionCallUsage( class KotlinFunctionCallUsage(
element: KtCallElement, element: KtCallElement,
private val callee: KotlinCallableDefinitionUsage<*>, private val callee: KotlinCallableDefinitionUsage<*>,
forcedResolvedCall: ResolvedCall<*>? = null forcedResolvedCall: ResolvedCall<*>? = null
) : KotlinUsageInfo<KtCallElement>(element) { ) : KotlinUsageInfo<KtCallElement>(element) {
private val context = element.analyze(BodyResolveMode.FULL) private val context = element.analyze(BodyResolveMode.FULL)
private val resolvedCall = forcedResolvedCall ?: element.getResolvedCall(context) private val resolvedCall = forcedResolvedCall ?: element.getResolvedCall(context)
@@ -78,8 +78,7 @@ class KotlinFunctionCallUsage(
if (element.valueArgumentList != null) { if (element.valueArgumentList != null) {
if (changeInfo.isParameterSetOrOrderChanged) { if (changeInfo.isParameterSetOrOrderChanged) {
result = updateArgumentsAndReceiver(changeInfo, element, allUsages) result = updateArgumentsAndReceiver(changeInfo, element, allUsages)
} } else {
else {
changeArgumentNames(changeInfo, element) changeArgumentNames(changeInfo, element)
} }
} }
@@ -105,10 +104,10 @@ class KotlinFunctionCallUsage(
if (skipUnmatchedArgumentsCheck) return false if (skipUnmatchedArgumentsCheck) return false
if (!resolvedCall.call.valueArguments.all{ resolvedCall.getArgumentMapping(it) is ArgumentMatch }) return true if (!resolvedCall.call.valueArguments.all { resolvedCall.getArgumentMapping(it) is ArgumentMatch }) return true
val arguments = resolvedCall.valueArguments val arguments = resolvedCall.valueArguments
return !resolvedCall.resultingDescriptor.valueParameters.all{ arguments.containsKey(it) } return !resolvedCall.resultingDescriptor.valueParameters.all { arguments.containsKey(it) }
} }
private val isPropertyJavaUsage: Boolean private val isPropertyJavaUsage: Boolean
@@ -121,8 +120,7 @@ class KotlinFunctionCallUsage(
private fun changeNameIfNeeded(changeInfo: KotlinChangeInfo, element: KtCallElement) { private fun changeNameIfNeeded(changeInfo: KotlinChangeInfo, element: KtCallElement) {
if (!changeInfo.isNameChanged) return if (!changeInfo.isNameChanged) return
val callee = element.calleeExpression val callee = element.calleeExpression as? KtSimpleNameExpression ?: return
if (callee !is KtSimpleNameExpression) return
var newName = changeInfo.newName var newName = changeInfo.newName
if (isPropertyJavaUsage) { if (isPropertyJavaUsage) {
@@ -136,9 +134,9 @@ class KotlinFunctionCallUsage(
} }
private fun getReceiverExpressionIfMatched( private fun getReceiverExpressionIfMatched(
receiverValue: ReceiverValue?, receiverValue: ReceiverValue?,
originalDescriptor: DeclarationDescriptor, originalDescriptor: DeclarationDescriptor,
psiFactory: KtPsiFactory psiFactory: KtPsiFactory
): KtExpression? { ): KtExpression? {
if (receiverValue == null) return null if (receiverValue == null) return null
@@ -146,8 +144,7 @@ class KotlinFunctionCallUsage(
// to simplify checking against receiver value in the corresponding resolved call // to simplify checking against receiver value in the corresponding resolved call
val adjustedDescriptor = if (originalDescriptor is CallableDescriptor && originalDescriptor !is ReceiverParameterDescriptor) { val adjustedDescriptor = if (originalDescriptor is CallableDescriptor && originalDescriptor !is ReceiverParameterDescriptor) {
originalDescriptor.extensionReceiverParameter ?: return null originalDescriptor.extensionReceiverParameter ?: return null
} } else originalDescriptor
else originalDescriptor
val currentIsExtension = resolvedCall!!.extensionReceiver == receiverValue val currentIsExtension = resolvedCall!!.extensionReceiver == receiverValue
val originalIsExtension = adjustedDescriptor is ReceiverParameterDescriptor && adjustedDescriptor.value is ExtensionReceiver val originalIsExtension = adjustedDescriptor is ReceiverParameterDescriptor && adjustedDescriptor.value is ExtensionReceiver
@@ -174,9 +171,9 @@ class KotlinFunctionCallUsage(
} }
private fun substituteReferences( private fun substituteReferences(
expression: KtExpression, expression: KtExpression,
referenceMap: Map<PsiReference, DeclarationDescriptor>, referenceMap: Map<PsiReference, DeclarationDescriptor>,
psiFactory: KtPsiFactory psiFactory: KtPsiFactory
): KtExpression { ): KtExpression {
if (referenceMap.isEmpty() || resolvedCall == null) return expression if (referenceMap.isEmpty() || resolvedCall == null) return expression
@@ -199,28 +196,30 @@ class KotlinFunctionCallUsage(
addReceiver = false addReceiver = false
argumentExpression = argument.getArgumentExpression() argumentExpression = argument.getArgumentExpression()
} } else {
else {
addReceiver = descriptor !is ReceiverParameterDescriptor addReceiver = descriptor !is ReceiverParameterDescriptor
argumentExpression = argumentExpression =
getReceiverExpressionIfMatched(resolvedCall.extensionReceiver, descriptor, psiFactory) getReceiverExpressionIfMatched(resolvedCall.extensionReceiver, descriptor, psiFactory)
?: getReceiverExpressionIfMatched(resolvedCall.dispatchReceiver, descriptor, psiFactory) ?: getReceiverExpressionIfMatched(resolvedCall.dispatchReceiver, descriptor, psiFactory)
} }
if (argumentExpression == null) continue if (argumentExpression == null) continue
if (needSeparateVariable(argumentExpression) if (needSeparateVariable(argumentExpression)
&& PsiTreeUtil.getNonStrictParentOfType(element, && PsiTreeUtil.getNonStrictParentOfType(
KtConstructorDelegationCall::class.java, element,
KtSuperTypeListEntry::class.java, KtConstructorDelegationCall::class.java,
KtParameter::class.java) == null) { KtSuperTypeListEntry::class.java,
KtParameter::class.java
) == null
) {
KotlinIntroduceVariableHandler.doRefactoring( KotlinIntroduceVariableHandler.doRefactoring(
project, null, argumentExpression, project, null, argumentExpression,
isVar = false, isVar = false,
occurrencesToReplace = listOf(argumentExpression), occurrencesToReplace = listOf(argumentExpression),
onNonInteractiveFinish = { onNonInteractiveFinish = {
argumentExpression = psiFactory.createExpression(it.name!!) argumentExpression = psiFactory.createExpression(it.name!!)
}) })
} }
var expressionToReplace: KtExpression = nameCounterpartMap[ref.element] ?: continue var expressionToReplace: KtExpression = nameCounterpartMap[ref.element] ?: continue
@@ -239,8 +238,7 @@ class KotlinFunctionCallUsage(
val replacement = psiFactory.createExpression("${argumentExpression!!.text}.${expressionToReplace.text}") val replacement = psiFactory.createExpression("${argumentExpression!!.text}.${expressionToReplace.text}")
replacements.add(expressionToReplace to replacement) replacements.add(expressionToReplace to replacement)
} } else {
else {
replacements.add(expressionToReplace to argumentExpression!!) replacements.add(expressionToReplace to argumentExpression!!)
} }
} }
@@ -258,10 +256,10 @@ class KotlinFunctionCallUsage(
} }
class ArgumentInfo( class ArgumentInfo(
val parameter: KotlinParameterInfo, val parameter: KotlinParameterInfo,
val parameterIndex: Int, val parameterIndex: Int,
val resolvedArgument: ResolvedValueArgument?, val resolvedArgument: ResolvedValueArgument?,
val receiverValue: ReceiverValue? val receiverValue: ReceiverValue?
) { ) {
private val mainValueArgument: ValueArgument? private val mainValueArgument: ValueArgument?
get() = resolvedArgument?.arguments?.firstOrNull() get() = resolvedArgument?.arguments?.firstOrNull()
@@ -290,9 +288,9 @@ class KotlinFunctionCallUsage(
by NotNullablePsiCopyableUserDataProperty(Key.create("GENERATED_ARGUMENT_VALUE"), false) by NotNullablePsiCopyableUserDataProperty(Key.create("GENERATED_ARGUMENT_VALUE"), false)
private fun ArgumentInfo.getArgumentByDefaultValue( private fun ArgumentInfo.getArgumentByDefaultValue(
element: KtCallElement, element: KtCallElement,
allUsages: Array<out UsageInfo>, allUsages: Array<out UsageInfo>,
psiFactory: KtPsiFactory psiFactory: KtPsiFactory
): KtValueArgument { ): KtValueArgument {
val isInsideOfCallerBody = element.isInsideOfCallerBody(allUsages) val isInsideOfCallerBody = element.isInsideOfCallerBody(allUsages)
val defaultValueForCall = parameter.defaultValueForCall val defaultValueForCall = parameter.defaultValueForCall
@@ -311,12 +309,16 @@ class KotlinFunctionCallUsage(
} }
private fun ExpressionReceiver.wrapInvalidated(element: KtCallElement): ExpressionReceiver { private fun ExpressionReceiver.wrapInvalidated(element: KtCallElement): ExpressionReceiver {
return object: ExpressionReceiver by this { return object : ExpressionReceiver by this {
override val expression = element.getQualifiedExpressionForSelector()!!.receiverExpression override val expression = element.getQualifiedExpressionForSelector()!!.receiverExpression
} }
} }
private fun updateArgumentsAndReceiver(changeInfo: KotlinChangeInfo, element: KtCallElement, allUsages: Array<out UsageInfo>): KtElement { private fun updateArgumentsAndReceiver(
changeInfo: KotlinChangeInfo,
element: KtCallElement,
allUsages: Array<out UsageInfo>
): KtElement {
if (isPropertyJavaUsage) return updateJavaPropertyCall(changeInfo, element) if (isPropertyJavaUsage) return updateJavaPropertyCall(changeInfo, element)
val fullCallElement = element.getQualifiedExpressionForSelector() ?: element val fullCallElement = element.getQualifiedExpressionForSelector() ?: element
@@ -351,17 +353,17 @@ class KotlinFunctionCallUsage(
val lastParameterIndex = newParameters.lastIndex val lastParameterIndex = newParameters.lastIndex
var firstNamedIndex = newArgumentInfos.firstOrNull { var firstNamedIndex = newArgumentInfos.firstOrNull {
it.wasNamed it.wasNamed
|| (it.parameter.isNewParameter && purelyNamedCall) || (it.parameter.isNewParameter && purelyNamedCall)
|| (it.resolvedArgument is VarargValueArgument && it.parameterIndex < lastParameterIndex) || (it.resolvedArgument is VarargValueArgument && it.parameterIndex < lastParameterIndex)
}?.parameterIndex }?.parameterIndex
if (firstNamedIndex == null) { if (firstNamedIndex == null) {
val lastNonDefaultArgIndex = (lastParameterIndex downTo 0).firstOrNull { !newArgumentInfos[it].shouldSkip() } val lastNonDefaultArgIndex = (lastParameterIndex downTo 0).firstOrNull { !newArgumentInfos[it].shouldSkip() }
?: -1 ?: -1
firstNamedIndex = (0..lastNonDefaultArgIndex).firstOrNull { newArgumentInfos[it].shouldSkip() } firstNamedIndex = (0..lastNonDefaultArgIndex).firstOrNull { newArgumentInfos[it].shouldSkip() }
} }
val lastPositionalIndex = if (firstNamedIndex != null) firstNamedIndex - 1 else lastParameterIndex val lastPositionalIndex = if (firstNamedIndex != null) firstNamedIndex - 1 else lastParameterIndex
(lastPositionalIndex + 1 .. lastParameterIndex).forEach { newArgumentInfos[it].makeNamed(callee) } (lastPositionalIndex + 1..lastParameterIndex).forEach { newArgumentInfos[it].makeNamed(callee) }
val psiFactory = KtPsiFactory(element.project) val psiFactory = KtPsiFactory(element.project)
@@ -377,8 +379,7 @@ class KotlinFunctionCallUsage(
continue continue
} }
val resolvedArgument = argInfo.resolvedArgument when (val resolvedArgument = argInfo.resolvedArgument) {
when (resolvedArgument) {
null, is DefaultValueArgument -> addArgument(argInfo.getArgumentByDefaultValue(element, allUsages, psiFactory)) null, is DefaultValueArgument -> addArgument(argInfo.getArgumentByDefaultValue(element, allUsages, psiFactory))
is ExpressionValueArgument -> { is ExpressionValueArgument -> {
@@ -413,35 +414,34 @@ class KotlinFunctionCallUsage(
val lastNewArgument = newArgumentList.arguments.lastOrNull() val lastNewArgument = newArgumentList.arguments.lastOrNull()
val oldLastResolvedArgument = getResolvedValueArgument(lastNewParameter?.oldIndex ?: -1) as? ExpressionValueArgument val oldLastResolvedArgument = getResolvedValueArgument(lastNewParameter?.oldIndex ?: -1) as? ExpressionValueArgument
val lambdaArgumentNotTouched = val lambdaArgumentNotTouched =
lastOldArgument is KtLambdaArgument && oldLastResolvedArgument?.valueArgument == lastOldArgument lastOldArgument is KtLambdaArgument && oldLastResolvedArgument?.valueArgument == lastOldArgument
val newLambdaArgumentAddedLast = lastNewParameter != null val newLambdaArgumentAddedLast = lastNewParameter != null
&& lastNewParameter.isNewParameter && lastNewParameter.isNewParameter
&& lastNewParameter.defaultValueForCall is KtLambdaExpression && lastNewParameter.defaultValueForCall is KtLambdaExpression
&& lastNewArgument != null && lastNewArgument != null
&& !lastNewArgument.isNamed() && !lastNewArgument.isNamed()
if (lambdaArgumentNotTouched) { if (lambdaArgumentNotTouched) {
newArgumentList.removeArgument(newArgumentList.arguments.last()) newArgumentList.removeArgument(newArgumentList.arguments.last())
} } else {
else {
val lambdaArguments = element.lambdaArguments val lambdaArguments = element.lambdaArguments
if (lambdaArguments.isNotEmpty()) { if (lambdaArguments.isNotEmpty()) {
element.deleteChildRange(lambdaArguments.first(), lambdaArguments.last()) element.deleteChildRange(lambdaArguments.first(), lambdaArguments.last())
} }
} }
var oldArgumentList = element.valueArgumentList.sure { "Argument list is expected: " + element.text } val oldArgumentList = element.valueArgumentList.sure { "Argument list is expected: " + element.text }
replaceListPsiAndKeepDelimiters(oldArgumentList, newArgumentList) { arguments } replaceListPsiAndKeepDelimiters(oldArgumentList, newArgumentList) { arguments }
element.accept( element.accept(
object: KtTreeVisitorVoid() { object : KtTreeVisitorVoid() {
override fun visitArgument(argument: KtValueArgument) { override fun visitArgument(argument: KtValueArgument) {
if (argument.generatedArgumentValue) { if (argument.generatedArgumentValue) {
argument.generatedArgumentValue = false argument.generatedArgumentValue = false
argument.addToShorteningWaitSet(SHORTEN_ARGUMENTS_OPTIONS) argument.addToShorteningWaitSet(SHORTEN_ARGUMENTS_OPTIONS)
}
} }
} }
}
) )
var newElement: KtElement = element var newElement: KtElement = element
@@ -451,12 +451,11 @@ class KotlinFunctionCallUsage(
val extensionReceiverExpression = receiverArgument?.getArgumentExpression() val extensionReceiverExpression = receiverArgument?.getArgumentExpression()
val defaultValueForCall = newReceiverInfo.defaultValueForCall val defaultValueForCall = newReceiverInfo.defaultValueForCall
val receiver = extensionReceiverExpression?.let { psiFactory.createExpression(it.text) } val receiver = extensionReceiverExpression?.let { psiFactory.createExpression(it.text) }
?: defaultValueForCall ?: defaultValueForCall
?: psiFactory.createExpression("_") ?: psiFactory.createExpression("_")
psiFactory.createExpressionByPattern("$0.$1", receiver, element) psiFactory.createExpressionByPattern("$0.$1", receiver, element)
} } else {
else {
psiFactory.createExpression(element.text) psiFactory.createExpression(element.text)
} }
@@ -489,7 +488,7 @@ class KotlinFunctionCallUsage(
} }
companion object { companion object {
private val REVERSED_TEXT_OFFSET_COMPARATOR = Comparator<kotlin.Pair<KtElement, KtElement>> { p1, p2 -> private val REVERSED_TEXT_OFFSET_COMPARATOR = Comparator<Pair<KtElement, KtElement>> { p1, p2 ->
val offset1 = p1.first.startOffset val offset1 = p1.first.startOffset
val offset2 = p2.first.startOffset val offset2 = p2.first.startOffset
when { when {
@@ -499,7 +498,7 @@ class KotlinFunctionCallUsage(
} }
} }
private val SHORTEN_ARGUMENTS_OPTIONS = ShortenReferences.Options(true, true) private val SHORTEN_ARGUMENTS_OPTIONS = ShortenReferences.Options(removeThisLabels = true, removeThis = true)
private fun updateJavaPropertyCall(changeInfo: KotlinChangeInfo, element: KtCallElement): KtElement { private fun updateJavaPropertyCall(changeInfo: KotlinChangeInfo, element: KtCallElement): KtElement {
val newReceiverInfo = changeInfo.receiverParameterInfo val newReceiverInfo = changeInfo.receiverParameterInfo
@@ -520,8 +519,7 @@ class KotlinFunctionCallUsage(
if (originalReceiverInfo != null) { if (originalReceiverInfo != null) {
firstArgument?.replace(newReceiverArgument) firstArgument?.replace(newReceiverArgument)
} } else {
else {
arguments.addArgumentAfter(newReceiverArgument, null) arguments.addArgumentAfter(newReceiverArgument, null)
} }
} }
@@ -17,7 +17,6 @@
package org.jetbrains.kotlin.idea.refactoring.inline package org.jetbrains.kotlin.idea.refactoring.inline
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable import com.intellij.openapi.editor.ex.EditorSettingsExternalizable
import com.intellij.openapi.ui.DialogWrapper
import com.intellij.refactoring.JavaRefactoringSettings import com.intellij.refactoring.JavaRefactoringSettings
import org.jetbrains.kotlin.idea.codeInliner.UsageReplacementStrategy import org.jetbrains.kotlin.idea.codeInliner.UsageReplacementStrategy
import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.references.KtSimpleNameReference
@@ -25,11 +24,11 @@ import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.psi.KtProperty
class KotlinInlineValDialog( class KotlinInlineValDialog(
property: KtProperty, property: KtProperty,
reference: KtSimpleNameReference?, reference: KtSimpleNameReference?,
private val replacementStrategy: UsageReplacementStrategy, private val replacementStrategy: UsageReplacementStrategy,
private val assignmentToDelete: KtBinaryExpression?, private val assignmentToDelete: KtBinaryExpression?,
withPreview: Boolean = true withPreview: Boolean = true
) : AbstractKotlinInlineDialog(property, reference) { ) : AbstractKotlinInlineDialog(property, reference) {
private val isLocal = (callable as KtProperty).isLocal private val isLocal = (callable as KtProperty).isLocal
@@ -39,7 +38,7 @@ class KotlinInlineValDialog(
init { init {
setPreviewResults(withPreview && shouldBeShown()) setPreviewResults(withPreview && shouldBeShown())
if (simpleLocal) { if (simpleLocal) {
setDoNotAskOption(object : DialogWrapper.DoNotAskOption { setDoNotAskOption(object : DoNotAskOption {
override fun isToBeShown() = EditorSettingsExternalizable.getInstance().isShowInlineLocalDialog override fun isToBeShown() = EditorSettingsExternalizable.getInstance().isShowInlineLocalDialog
override fun setToBeShown(value: Boolean, exitCode: Int) { override fun setToBeShown(value: Boolean, exitCode: Int) {
@@ -62,10 +61,12 @@ class KotlinInlineValDialog(
public override fun doAction() { public override fun doAction() {
invokeRefactoring( invokeRefactoring(
KotlinInlineCallableProcessor(project, replacementStrategy, callable, reference, KotlinInlineCallableProcessor(
inlineThisOnly = isInlineThisOnly, project, replacementStrategy, callable, reference,
deleteAfter = !isInlineThisOnly && !isKeepTheDeclaration, inlineThisOnly = isInlineThisOnly,
statementToDelete = assignmentToDelete) deleteAfter = !isInlineThisOnly && !isKeepTheDeclaration,
statementToDelete = assignmentToDelete
)
) )
val settings = JavaRefactoringSettings.getInstance() val settings = JavaRefactoringSettings.getInstance()
@@ -30,18 +30,20 @@ import org.jetbrains.kotlin.idea.refactoring.introduce.extractionEngine.*
import org.jetbrains.kotlin.idea.refactoring.introduce.selectElementsWithTargetSibling import org.jetbrains.kotlin.idea.refactoring.introduce.selectElementsWithTargetSibling
import org.jetbrains.kotlin.idea.refactoring.introduce.validateExpressionElements import org.jetbrains.kotlin.idea.refactoring.introduce.validateExpressionElements
import org.jetbrains.kotlin.idea.util.psi.patternMatching.toRange import org.jetbrains.kotlin.idea.util.psi.patternMatching.toRange
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.KtBlockExpression
import org.jetbrains.kotlin.psi.KtFile
class ExtractKotlinFunctionHandler( class ExtractKotlinFunctionHandler(
private val allContainersEnabled: Boolean = false, private val allContainersEnabled: Boolean = false,
private val helper: ExtractionEngineHelper = ExtractKotlinFunctionHandler.InteractiveExtractionHelper) : RefactoringActionHandler { private val helper: ExtractionEngineHelper = InteractiveExtractionHelper
) : RefactoringActionHandler {
object InteractiveExtractionHelper : ExtractionEngineHelper(EXTRACT_FUNCTION) { object InteractiveExtractionHelper : ExtractionEngineHelper(EXTRACT_FUNCTION) {
override fun configureAndRun( override fun configureAndRun(
project: Project, project: Project,
editor: Editor, editor: Editor,
descriptorWithConflicts: ExtractableCodeDescriptorWithConflicts, descriptorWithConflicts: ExtractableCodeDescriptorWithConflicts,
onFinish: (ExtractionResult) -> Unit onFinish: (ExtractionResult) -> Unit
) { ) {
KotlinExtractFunctionDialog(descriptorWithConflicts.descriptor.extractionData.project, descriptorWithConflicts) { KotlinExtractFunctionDialog(descriptorWithConflicts.descriptor.extractionData.project, descriptorWithConflicts) {
doRefactor(it.currentConfiguration, onFinish) doRefactor(it.currentConfiguration, onFinish)
@@ -50,10 +52,10 @@ class ExtractKotlinFunctionHandler(
} }
fun doInvoke( fun doInvoke(
editor: Editor, editor: Editor,
file: KtFile, file: KtFile,
elements: List<PsiElement>, elements: List<PsiElement>,
targetSibling: PsiElement targetSibling: PsiElement
) { ) {
val adjustedElements = (elements.singleOrNull() as? KtBlockExpression)?.statements ?: elements val adjustedElements = (elements.singleOrNull() as? KtBlockExpression)?.statements ?: elements
val extractionData = ExtractionData(file, adjustedElements.toRange(false), targetSibling) val extractionData = ExtractionData(file, adjustedElements.toRange(false), targetSibling)
@@ -64,14 +66,14 @@ class ExtractKotlinFunctionHandler(
fun selectElements(editor: Editor, file: KtFile, continuation: (elements: List<PsiElement>, targetSibling: PsiElement) -> Unit) { fun selectElements(editor: Editor, file: KtFile, continuation: (elements: List<PsiElement>, targetSibling: PsiElement) -> Unit) {
selectElementsWithTargetSibling( selectElementsWithTargetSibling(
EXTRACT_FUNCTION, EXTRACT_FUNCTION,
editor, editor,
file, file,
"Select target code block", "Select target code block",
listOf(CodeInsightUtils.ElementKind.EXPRESSION), listOf(CodeInsightUtils.ElementKind.EXPRESSION),
::validateExpressionElements, ::validateExpressionElements,
{ elements, parent -> parent.getExtractionContainers(elements.size == 1, allContainersEnabled) }, { elements, parent -> parent.getExtractionContainers(elements.size == 1, allContainersEnabled) },
continuation continuation
) )
} }
@@ -29,12 +29,12 @@ import javax.swing.table.DefaultTableCellRenderer
open class ExtractFunctionParameterTablePanel : AbstractParameterTablePanel<Parameter, ExtractFunctionParameterTablePanel.ParameterInfo>() { open class ExtractFunctionParameterTablePanel : AbstractParameterTablePanel<Parameter, ExtractFunctionParameterTablePanel.ParameterInfo>() {
companion object { companion object {
val PARAMETER_TYPE_COLUMN = 2 const val PARAMETER_TYPE_COLUMN = 2
} }
class ParameterInfo( class ParameterInfo(
originalParameter: Parameter, originalParameter: Parameter,
val isReceiver: Boolean val isReceiver: Boolean
) : AbstractParameterTablePanel.AbstractParameterInfo<Parameter>(originalParameter) { ) : AbstractParameterTablePanel.AbstractParameterInfo<Parameter>(originalParameter) {
var type = originalParameter.parameterType var type = originalParameter.parameterType
@@ -45,7 +45,7 @@ open class ExtractFunctionParameterTablePanel : AbstractParameterTablePanel<Para
override fun toParameter() = originalParameter.copy(name, type) override fun toParameter() = originalParameter.copy(name, type)
} }
override fun createTableModel(): AbstractParameterTablePanel<Parameter, ParameterInfo>.TableModelBase = MyTableModel() override fun createTableModel(): TableModelBase = MyTableModel()
override fun createAdditionalColumns() { override fun createAdditionalColumns() {
with(table.columnModel.getColumn(PARAMETER_TYPE_COLUMN)) { with(table.columnModel.getColumn(PARAMETER_TYPE_COLUMN)) {
@@ -54,27 +54,27 @@ open class ExtractFunctionParameterTablePanel : AbstractParameterTablePanel<Para
private val myLabel = JBComboBoxLabel() private val myLabel = JBComboBoxLabel()
override fun getTableCellRendererComponent( override fun getTableCellRendererComponent(
table: JTable, value: Any, isSelected: Boolean, hasFocus: Boolean, row: Int, column: Int table: JTable, value: Any, isSelected: Boolean, hasFocus: Boolean, row: Int, column: Int
): Component { ): Component {
myLabel.text = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.renderType(value as KotlinType) myLabel.text = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_NO_ANNOTATIONS.renderType(value as KotlinType)
myLabel.background = if (isSelected) table.selectionBackground else table.background myLabel.background = if (isSelected) table.selectionBackground else table.background
myLabel.foreground = if (isSelected) table.selectionForeground else table.foreground myLabel.foreground = if (isSelected) table.selectionForeground else table.foreground
if (isSelected) { if (isSelected) {
myLabel.setSelectionIcon() myLabel.setSelectionIcon()
} } else {
else {
myLabel.setRegularIcon() myLabel.setRegularIcon()
} }
return myLabel return myLabel
} }
} }
cellEditor = object : AbstractTableCellEditor() { cellEditor = object : AbstractTableCellEditor() {
internal val myEditorComponent = JBComboBoxTableCellEditorComponent() val myEditorComponent = JBComboBoxTableCellEditorComponent()
override fun getCellEditorValue() = myEditorComponent.editorValue override fun getCellEditorValue() = myEditorComponent.editorValue
override fun getTableCellEditorComponent( override fun getTableCellEditorComponent(
table: JTable, value: Any, isSelected: Boolean, row: Int, column: Int): Component { table: JTable, value: Any, isSelected: Boolean, row: Int, column: Int
): Component {
val info = parameterInfos[row] val info = parameterInfos[row]
myEditorComponent.setCell(table, row, column) myEditorComponent.setCell(table, row, column)
@@ -90,13 +90,13 @@ open class ExtractFunctionParameterTablePanel : AbstractParameterTablePanel<Para
fun init(receiver: Parameter?, parameters: List<Parameter>) { fun init(receiver: Parameter?, parameters: List<Parameter>) {
parameterInfos = parameters.mapTo( parameterInfos = parameters.mapTo(
if (receiver != null) arrayListOf(ParameterInfo(receiver, true)) else arrayListOf() if (receiver != null) arrayListOf(ParameterInfo(receiver, true)) else arrayListOf()
) { ParameterInfo(it, false) } ) { ParameterInfo(it, false) }
super.init() super.init()
} }
private inner class MyTableModel : AbstractParameterTablePanel<Parameter, ParameterInfo>.TableModelBase() { private inner class MyTableModel : TableModelBase() {
override fun getColumnCount() = 3 override fun getColumnCount() = 3
override fun getValueAt(rowIndex: Int, columnIndex: Int): Any? { override fun getValueAt(rowIndex: Int, columnIndex: Int): Any? {
@@ -117,7 +117,7 @@ open class ExtractFunctionParameterTablePanel : AbstractParameterTablePanel<Para
override fun isCellEditable(rowIndex: Int, columnIndex: Int): Boolean { override fun isCellEditable(rowIndex: Int, columnIndex: Int): Boolean {
val info = parameterInfos[rowIndex] val info = parameterInfos[rowIndex]
return when (columnIndex) { return when (columnIndex) {
AbstractParameterTablePanel.PARAMETER_NAME_COLUMN -> super.isCellEditable(rowIndex, columnIndex) && !info.isReceiver PARAMETER_NAME_COLUMN -> super.isCellEditable(rowIndex, columnIndex) && !info.isReceiver
PARAMETER_TYPE_COLUMN -> isEnabled && info.isEnabled && info.originalParameter.getParameterTypeCandidates().size > 1 PARAMETER_TYPE_COLUMN -> isEnabled && info.isEnabled && info.originalParameter.getParameterTypeCandidates().size > 1
else -> super.isCellEditable(rowIndex, columnIndex) else -> super.isCellEditable(rowIndex, columnIndex)
} }
@@ -67,7 +67,6 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
import org.jetbrains.kotlin.resolve.scopes.LexicalScope import org.jetbrains.kotlin.resolve.scopes.LexicalScope
import org.jetbrains.kotlin.types.* import org.jetbrains.kotlin.types.*
import org.jetbrains.kotlin.types.typeUtil.makeNullable import org.jetbrains.kotlin.types.typeUtil.makeNullable
import org.jetbrains.kotlin.utils.DFS
import org.jetbrains.kotlin.utils.DFS.* import org.jetbrains.kotlin.utils.DFS.*
import java.util.* import java.util.*
@@ -407,7 +406,7 @@ internal fun ExtractionData.createTemporaryCodeBlock(): KtBlockExpression {
private fun KotlinType.collectReferencedTypes(processTypeArguments: Boolean): List<KotlinType> { private fun KotlinType.collectReferencedTypes(processTypeArguments: Boolean): List<KotlinType> {
if (!processTypeArguments) return Collections.singletonList(this) if (!processTypeArguments) return Collections.singletonList(this)
return DFS.dfsFromNode( return dfsFromNode(
this, this,
Neighbors<KotlinType> { current -> current.arguments.map { it.type } }, Neighbors<KotlinType> { current -> current.arguments.map { it.type } },
VisitedWithSet(), VisitedWithSet(),
@@ -168,7 +168,7 @@ class DuplicateInfo(
) )
fun ExtractableCodeDescriptor.findDuplicates(): List<DuplicateInfo> { fun ExtractableCodeDescriptor.findDuplicates(): List<DuplicateInfo> {
fun processWeakMatch(match: UnificationResult.WeaklyMatched, newControlFlow: ControlFlow): Boolean { fun processWeakMatch(match: WeaklyMatched, newControlFlow: ControlFlow): Boolean {
val valueCount = controlFlow.outputValues.size val valueCount = controlFlow.outputValues.size
val weakMatches = HashMap(match.weakMatches) val weakMatches = HashMap(match.weakMatches)
@@ -234,7 +234,7 @@ fun ExtractableCodeDescriptor.findDuplicates(): List<DuplicateInfo> {
controlFlow?.let { controlFlow?.let {
DuplicateInfo(range, it, unifierParameters.map { param -> DuplicateInfo(range, it, unifierParameters.map { param ->
match.substitution[param]!!.text!! match.substitution.getValue(param).text!!
}) })
} }
} }
@@ -254,14 +254,13 @@ private fun makeCall(
) { ) {
fun insertCall(anchor: PsiElement, wrappedCall: KtExpression): KtExpression? { fun insertCall(anchor: PsiElement, wrappedCall: KtExpression): KtExpression? {
val firstExpression = rangeToReplace.elements.firstOrNull { it is KtExpression } as? KtExpression val firstExpression = rangeToReplace.elements.firstOrNull { it is KtExpression } as? KtExpression
if (firstExpression?.isLambdaOutsideParentheses() ?: false) { if (firstExpression?.isLambdaOutsideParentheses() == true) {
val functionLiteralArgument = firstExpression?.getStrictParentOfType<KtLambdaArgument>()!! val functionLiteralArgument = firstExpression.getStrictParentOfType<KtLambdaArgument>()!!
return functionLiteralArgument.moveInsideParenthesesAndReplaceWith(wrappedCall, extractableDescriptor.originalContext) return functionLiteralArgument.moveInsideParenthesesAndReplaceWith(wrappedCall, extractableDescriptor.originalContext)
} }
if (anchor is KtOperationReferenceExpression) { if (anchor is KtOperationReferenceExpression) {
val operationExpression = anchor.parent as? KtOperationExpression ?: return null val newNameExpression = when (val operationExpression = anchor.parent as? KtOperationExpression ?: return null) {
val newNameExpression = when (operationExpression) {
is KtUnaryExpression -> OperatorToFunctionIntention.convert(operationExpression).second is KtUnaryExpression -> OperatorToFunctionIntention.convert(operationExpression).second
is KtBinaryExpression -> { is KtBinaryExpression -> {
InfixCallToOrdinaryIntention.convert(operationExpression).getCalleeExpressionIfAny() InfixCallToOrdinaryIntention.convert(operationExpression).getCalleeExpressionIfAny()
@@ -353,7 +352,7 @@ private fun makeCall(
fun wrapCall(outputValue: OutputValue, callText: String): List<PsiElement> { fun wrapCall(outputValue: OutputValue, callText: String): List<PsiElement> {
return when (outputValue) { return when (outputValue) {
is OutputValue.ExpressionValue -> { is ExpressionValue -> {
val exprText = if (outputValue.callSiteReturn) { val exprText = if (outputValue.callSiteReturn) {
val firstReturn = outputValue.originalExpressions.asSequence().filterIsInstance<KtReturnExpression>().firstOrNull() val firstReturn = outputValue.originalExpressions.asSequence().filterIsInstance<KtReturnExpression>().firstOrNull()
val label = firstReturn?.getTargetLabel()?.text ?: "" val label = firstReturn?.getTargetLabel()?.text ?: ""
@@ -397,7 +396,7 @@ private fun makeCall(
controlFlow.outputValues controlFlow.outputValues
.filter { it != defaultValue } .filter { it != defaultValue }
.flatMap { wrapCall(it, unboxingExpressions[it]!!) } .flatMap { wrapCall(it, unboxingExpressions.getValue(it)) }
.withIndex() .withIndex()
.forEach { .forEach {
val (i, e) = it val (i, e) = it
@@ -412,7 +411,7 @@ private fun makeCall(
if (!inlinableCall) { if (!inlinableCall) {
block.addBefore(newLine, anchorInBlock) block.addBefore(newLine, anchorInBlock)
} }
insertCall(anchor, wrapCall(it, unboxingExpressions[it]!!).first() as KtExpression)?.removeTemplateEntryBracesIfPossible() insertCall(anchor, wrapCall(it, unboxingExpressions.getValue(it)).first() as KtExpression)?.removeTemplateEntryBracesIfPossible()
} }
if (anchor.isValid) { if (anchor.isValid) {
@@ -533,7 +532,7 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
} }
val originalRef = resolveResult.originalRefExpr val originalRef = resolveResult.originalRefExpr
val newRef = descriptor.replacementMap[originalRef] val newRef = descriptor.replacementMap[originalRef]
.fold(currentRef as KtElement) { currentRef, replacement -> replacement(descriptor, currentRef) } .fold(currentRef as KtElement) { ref, replacement -> replacement(descriptor, ref) }
(newRef as? KtSimpleNameExpression)?.resolveResult = resolveResult (newRef as? KtSimpleNameExpression)?.resolveResult = resolveResult
} }
@@ -608,7 +607,7 @@ fun ExtractionGeneratorConfiguration.generateDeclaration(
} }
} else { } else {
(targetContainer.addAfter(declaration, anchor) as KtNamedDeclaration).apply { (targetContainer.addAfter(declaration, anchor) as KtNamedDeclaration).apply {
if (!(targetContainer is KtClassBody && (targetContainer.parent as? KtClass)?.isEnum() ?: false)) { if (!(targetContainer is KtClassBody && (targetContainer.parent as? KtClass)?.isEnum() == true)) {
targetContainer.addAfter(emptyLines, anchor) targetContainer.addAfter(emptyLines, anchor)
} }
} }
@@ -40,28 +40,27 @@ import org.jetbrains.kotlin.psi.KtProperty
import java.util.* import java.util.*
class KotlinIntroducePropertyHandler( class KotlinIntroducePropertyHandler(
val helper: ExtractionEngineHelper = KotlinIntroducePropertyHandler.InteractiveExtractionHelper val helper: ExtractionEngineHelper = InteractiveExtractionHelper
): RefactoringActionHandler { ) : RefactoringActionHandler {
object InteractiveExtractionHelper : ExtractionEngineHelper(INTRODUCE_PROPERTY) { object InteractiveExtractionHelper : ExtractionEngineHelper(INTRODUCE_PROPERTY) {
private fun getExtractionTarget(descriptor: ExtractableCodeDescriptor) = private fun getExtractionTarget(descriptor: ExtractableCodeDescriptor) =
propertyTargets.firstOrNull { it.isAvailable(descriptor) } propertyTargets.firstOrNull { it.isAvailable(descriptor) }
override fun validate(descriptor: ExtractableCodeDescriptor) = override fun validate(descriptor: ExtractableCodeDescriptor) =
descriptor.validate(getExtractionTarget(descriptor) ?: ExtractionTarget.FUNCTION) descriptor.validate(getExtractionTarget(descriptor) ?: ExtractionTarget.FUNCTION)
override fun configureAndRun( override fun configureAndRun(
project: Project, project: Project,
editor: Editor, editor: Editor,
descriptorWithConflicts: ExtractableCodeDescriptorWithConflicts, descriptorWithConflicts: ExtractableCodeDescriptorWithConflicts,
onFinish: (ExtractionResult) -> Unit onFinish: (ExtractionResult) -> Unit
) { ) {
val descriptor = descriptorWithConflicts.descriptor val descriptor = descriptorWithConflicts.descriptor
val target = getExtractionTarget(descriptor) val target = getExtractionTarget(descriptor)
if (target != null) { if (target != null) {
val options = ExtractionGeneratorOptions.DEFAULT.copy(target = target, delayInitialOccurrenceReplacement = true) val options = ExtractionGeneratorOptions.DEFAULT.copy(target = target, delayInitialOccurrenceReplacement = true)
doRefactor(ExtractionGeneratorConfiguration(descriptor, options), onFinish) doRefactor(ExtractionGeneratorConfiguration(descriptor, options), onFinish)
} } else {
else {
showErrorHint(project, editor, "Can't introduce property for this expression", INTRODUCE_PROPERTY) showErrorHint(project, editor, "Can't introduce property for this expression", INTRODUCE_PROPERTY)
} }
} }
@@ -69,16 +68,17 @@ class KotlinIntroducePropertyHandler(
fun selectElements(editor: Editor, file: KtFile, continuation: (elements: List<PsiElement>, targetSibling: PsiElement) -> Unit) { fun selectElements(editor: Editor, file: KtFile, continuation: (elements: List<PsiElement>, targetSibling: PsiElement) -> Unit) {
selectElementsWithTargetSibling( selectElementsWithTargetSibling(
INTRODUCE_PROPERTY, INTRODUCE_PROPERTY,
editor, editor,
file, file,
"Select target code block", "Select target code block",
listOf(CodeInsightUtils.ElementKind.EXPRESSION), listOf(CodeInsightUtils.ElementKind.EXPRESSION),
::validateExpressionElements, ::validateExpressionElements,
{ _, parent -> { _, parent ->
parent.getExtractionContainers(strict = true, includeAll = true).filter { it is KtClassBody || (it is KtFile && !it.isScript()) } parent.getExtractionContainers(strict = true, includeAll = true)
}, .filter { it is KtClassBody || (it is KtFile && !it.isScript()) }
continuation },
continuation
) )
} }
@@ -100,23 +100,21 @@ class KotlinIntroducePropertyHandler(
} }
val introducer = KotlinInplacePropertyIntroducer( val introducer = KotlinInplacePropertyIntroducer(
property = property, property = property,
editor = editor, editor = editor,
project = project, project = project,
title = INTRODUCE_PROPERTY, title = INTRODUCE_PROPERTY,
doNotChangeVar = false, doNotChangeVar = false,
exprType = descriptor.returnType, exprType = descriptor.returnType,
extractionResult = it, extractionResult = it,
availableTargets = propertyTargets.filter { it.isAvailable(descriptor) } availableTargets = propertyTargets.filter { target -> target.isAvailable(descriptor) }
) )
introducer.performInplaceRefactoring(LinkedHashSet(descriptor.suggestedNames)) introducer.performInplaceRefactoring(LinkedHashSet(descriptor.suggestedNames))
} } else {
else {
processDuplicatesSilently(it.duplicateReplacers, project) processDuplicatesSilently(it.duplicateReplacers, project)
} }
} }
} } else {
else {
showErrorHintByKey(project, editor, "cannot.refactor.no.expression", INTRODUCE_PROPERTY) showErrorHintByKey(project, editor, "cannot.refactor.no.expression", INTRODUCE_PROPERTY)
} }
} }
@@ -38,7 +38,6 @@ import org.jetbrains.kotlin.idea.util.psi.patternMatching.UnifierParameter
import org.jetbrains.kotlin.idea.util.psi.patternMatching.toRange import org.jetbrains.kotlin.idea.util.psi.patternMatching.toRange
import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.lexer.KtTokens.* import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -63,8 +62,10 @@ fun IntroduceTypeAliasData.analyze(): IntroduceTypeAliasAnalysisResult {
val dummyVar = psiFactory.createProperty("val a: Int").apply { val dummyVar = psiFactory.createProperty("val a: Int").apply {
typeReference!!.replace( typeReference!!.replace(
originalTypeElement.parent as? KtTypeReference ?: originalTypeElement.parent as? KtTypeReference ?: if (originalTypeElement is KtTypeElement) psiFactory.createType(
if (originalTypeElement is KtTypeElement) psiFactory.createType(originalTypeElement) else psiFactory.createType(originalTypeElement.text)) originalTypeElement
) else psiFactory.createType(originalTypeElement.text)
)
} }
val newTypeReference = dummyVar.typeReference!! val newTypeReference = dummyVar.typeReference!!
val newReferences = newTypeReference.collectDescendantsOfType<KtTypeReference> { it.resolveInfo != null } val newReferences = newTypeReference.collectDescendantsOfType<KtTypeReference> { it.resolveInfo != null }
@@ -86,12 +87,11 @@ fun IntroduceTypeAliasData.analyze(): IntroduceTypeAliasAnalysisResult {
} }
val equivalenceRepresentative = groupedReferencesToExtract val equivalenceRepresentative = groupedReferencesToExtract
.keySet() .keySet()
.firstOrNull { unifier.unify(it.reference, resolveInfo.reference).matched } .firstOrNull { unifier.unify(it.reference, resolveInfo.reference).matched }
if (equivalenceRepresentative != null) { if (equivalenceRepresentative != null) {
groupedReferencesToExtract.putValue(equivalenceRepresentative, resolveInfo) groupedReferencesToExtract.putValue(equivalenceRepresentative, resolveInfo)
} } else {
else {
groupedReferencesToExtract.putValue(resolveInfo, resolveInfo) groupedReferencesToExtract.putValue(resolveInfo, resolveInfo)
} }
@@ -109,7 +109,7 @@ fun IntroduceTypeAliasData.analyze(): IntroduceTypeAliasAnalysisResult {
val typeParameterNames = KotlinNameSuggester.suggestNamesForTypeParameters(brokenReferences.size, typeParameterNameValidator) val typeParameterNames = KotlinNameSuggester.suggestNamesForTypeParameters(brokenReferences.size, typeParameterNameValidator)
val typeParameters = (typeParameterNames zip brokenReferences).map { TypeParameter(it.first, groupedReferencesToExtract[it.second]) } val typeParameters = (typeParameterNames zip brokenReferences).map { TypeParameter(it.first, groupedReferencesToExtract[it.second]) }
if (typeParameters.any { it.typeReferenceInfos.any { it.reference.typeElement == originalTypeElement } }) { if (typeParameters.any { it.typeReferenceInfos.any { info -> info.reference.typeElement == originalTypeElement } }) {
return IntroduceTypeAliasAnalysisResult.Error("Type alias cannot refer to types which aren't accessible in the scope where it's defined") return IntroduceTypeAliasAnalysisResult.Error("Type alias cannot refer to types which aren't accessible in the scope where it's defined")
} }
@@ -122,13 +122,10 @@ fun IntroduceTypeAliasData.analyze(): IntroduceTypeAliasAnalysisResult {
return IntroduceTypeAliasAnalysisResult.Success(descriptor.copy(name = initialName)) return IntroduceTypeAliasAnalysisResult.Success(descriptor.copy(name = initialName))
} }
fun IntroduceTypeAliasData.getApplicableVisibilities(): List<KtModifierKeywordToken>{ fun IntroduceTypeAliasData.getApplicableVisibilities(): List<KtModifierKeywordToken> = when (targetSibling.parent) {
val parent = targetSibling.parent is KtClassBody -> listOf(PRIVATE_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD, PROTECTED_KEYWORD)
return when (parent) { is KtFile -> listOf(PRIVATE_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD)
is KtClassBody -> listOf(PRIVATE_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD, PROTECTED_KEYWORD) else -> emptyList()
is KtFile -> listOf(PRIVATE_KEYWORD, PUBLIC_KEYWORD, INTERNAL_KEYWORD)
else -> emptyList()
}
} }
fun IntroduceTypeAliasDescriptor.validate(): IntroduceTypeAliasDescriptorWithConflicts { fun IntroduceTypeAliasDescriptor.validate(): IntroduceTypeAliasDescriptorWithConflicts {
@@ -188,9 +185,11 @@ fun findDuplicates(typeAlias: KtTypeAlias): Map<KotlinPsiRange, () -> Unit> {
val typeArgumentList = callExpression.typeArgumentList val typeArgumentList = callExpression.typeArgumentList
if (arguments.isNotEmpty()) { if (arguments.isNotEmpty()) {
val newTypeArgumentList = psiFactory.createTypeArguments(typeArgumentsText) val newTypeArgumentList = psiFactory.createTypeArguments(typeArgumentsText)
typeArgumentList?.replace(newTypeArgumentList) ?: callExpression.addAfter(newTypeArgumentList, callExpression.calleeExpression) typeArgumentList?.replace(newTypeArgumentList) ?: callExpression.addAfter(
} newTypeArgumentList,
else { callExpression.calleeExpression
)
} else {
typeArgumentList?.delete() typeArgumentList?.delete()
} }
callExpression.calleeExpression?.replace(psiFactory.createExpression(aliasName)) callExpression.calleeExpression?.replace(psiFactory.createExpression(aliasName))
@@ -217,39 +216,38 @@ fun findDuplicates(typeAlias: KtTypeAlias): Map<KotlinPsiRange, () -> Unit> {
if (callElement != null) { if (callElement != null) {
occurrence = callElement occurrence = callElement
arguments = callElement.typeArguments.mapNotNull { it.typeReference?.typeElement } arguments = callElement.typeArguments.mapNotNull { it.typeReference?.typeElement }
} } else {
else {
val userType = element.getParentOfTypeAndBranch<KtUserType> { referenceExpression } val userType = element.getParentOfTypeAndBranch<KtUserType> { referenceExpression }
if (userType != null) { if (userType != null) {
occurrence = userType occurrence = userType
arguments = userType.typeArgumentsAsTypes.mapNotNull { it.typeElement } arguments = userType.typeArgumentsAsTypes.mapNotNull { it.typeElement }
} } else continue
else continue
} }
if (arguments.size != typeAliasDescriptor.declaredTypeParameters.size) continue if (arguments.size != typeAliasDescriptor.declaredTypeParameters.size) continue
if (TypeUtils.isNullableType(typeAliasDescriptor.underlyingType) if (TypeUtils.isNullableType(typeAliasDescriptor.underlyingType)
&& occurrence is KtUserType && occurrence is KtUserType
&& occurrence.parent !is KtNullableType) continue && occurrence.parent !is KtNullableType
) continue
rangesWithReplacers += occurrence.toRange() to { replaceOccurrence(occurrence, arguments) } rangesWithReplacers += occurrence.toRange() to { replaceOccurrence(occurrence, arguments) }
} }
} }
typeAlias typeAlias
.getTypeReference() .getTypeReference()
?.typeElement ?.typeElement
.toRange() .toRange()
.match(typeAlias.parent, unifier) .match(typeAlias.parent, unifier)
.asSequence() .asSequence()
.filter { !(it.range.getTextRange().intersects(aliasRange)) } .filter { !(it.range.getTextRange().intersects(aliasRange)) }
.mapNotNullTo(rangesWithReplacers) { match -> .mapNotNullTo(rangesWithReplacers) { match ->
val occurrence = match.range.elements.singleOrNull() as? KtTypeElement ?: return@mapNotNullTo null val occurrence = match.range.elements.singleOrNull() as? KtTypeElement ?: return@mapNotNullTo null
val arguments = unifierParameters.mapNotNull { (match.substitution[it] as? KtTypeReference)?.typeElement } val arguments = unifierParameters.mapNotNull { (match.substitution[it] as? KtTypeReference)?.typeElement }
if (arguments.size != unifierParameters.size) return@mapNotNullTo null if (arguments.size != unifierParameters.size) return@mapNotNullTo null
match.range to { replaceOccurrence(occurrence, arguments) } match.range to { replaceOccurrence(occurrence, arguments) }
} }
return rangesWithReplacers.toMap() return rangesWithReplacers.toMap()
} }
private var KtTypeReference.typeParameterInfo : TypeParameter? by CopyablePsiUserDataProperty(Key.create("TYPE_PARAMETER_INFO")) private var KtTypeReference.typeParameterInfo: TypeParameter? by CopyablePsiUserDataProperty(Key.create("TYPE_PARAMETER_INFO"))
fun IntroduceTypeAliasDescriptor.generateTypeAlias(previewOnly: Boolean = false): KtTypeAlias { fun IntroduceTypeAliasDescriptor.generateTypeAlias(previewOnly: Boolean = false): KtTypeAlias {
val originalElement = originalData.originalTypeElement val originalElement = originalData.originalTypeElement
@@ -263,11 +261,10 @@ fun IntroduceTypeAliasDescriptor.generateTypeAlias(previewOnly: Boolean = false)
val typeParameterNames = typeParameters.map { it.name } val typeParameterNames = typeParameters.map { it.name }
val typeAlias = if (originalElement is KtTypeElement) { val typeAlias = if (originalElement is KtTypeElement) {
psiFactory.createTypeAlias(name, typeParameterNames, originalElement) psiFactory.createTypeAlias(name, typeParameterNames, originalElement)
} } else {
else {
psiFactory.createTypeAlias(name, typeParameterNames, originalElement.text) psiFactory.createTypeAlias(name, typeParameterNames, originalElement.text)
} }
if (visibility != null && visibility != KtTokens.DEFAULT_VISIBILITY_KEYWORD) { if (visibility != null && visibility != DEFAULT_VISIBILITY_KEYWORD) {
typeAlias.addModifier(visibility) typeAlias.addModifier(visibility)
} }
@@ -279,8 +276,7 @@ fun IntroduceTypeAliasDescriptor.generateTypeAlias(previewOnly: Boolean = false)
fun replaceUsage() { fun replaceUsage() {
val aliasInstanceText = if (typeParameters.isNotEmpty()) { val aliasInstanceText = if (typeParameters.isNotEmpty()) {
"$name<${typeParameters.joinToString { it.typeReferenceInfos.first().reference.text }}>" "$name<${typeParameters.joinToString { it.typeReferenceInfos.first().reference.text }}>"
} } else {
else {
name name
} }
when (originalElement) { when (originalElement) {
@@ -300,8 +296,7 @@ fun IntroduceTypeAliasDescriptor.generateTypeAlias(previewOnly: Boolean = false)
return if (previewOnly) { return if (previewOnly) {
introduceTypeParameters() introduceTypeParameters()
typeAlias typeAlias
} } else {
else {
replaceUsage() replaceUsage()
introduceTypeParameters() introduceTypeParameters()
insertDeclaration(typeAlias, originalData.targetSibling) insertDeclaration(typeAlias, originalData.targetSibling)
@@ -29,9 +29,9 @@ import org.jetbrains.kotlin.psi.KtProperty
import javax.swing.Icon import javax.swing.Icon
class KotlinMemberSelectionTable( class KotlinMemberSelectionTable(
memberInfos: List<KotlinMemberInfo>, memberInfos: List<KotlinMemberInfo>,
memberInfoModel: MemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>?, memberInfoModel: MemberInfoModel<KtNamedDeclaration, KotlinMemberInfo>?,
abstractColumnHeader: String? abstractColumnHeader: String?
) : AbstractMemberSelectionTable<KtNamedDeclaration, KotlinMemberInfo>(memberInfos, memberInfoModel, abstractColumnHeader) { ) : AbstractMemberSelectionTable<KtNamedDeclaration, KotlinMemberInfo>(memberInfos, memberInfoModel, abstractColumnHeader) {
override fun getAbstractColumnValue(memberInfo: KotlinMemberInfo): Any? { override fun getAbstractColumnValue(memberInfo: KotlinMemberInfo): Any? {
if (memberInfo.isStatic || memberInfo.isCompanionMember) return null if (memberInfo.isStatic || memberInfo.isCompanionMember) return null
@@ -66,7 +66,7 @@ class KotlinMemberSelectionTable(
} }
override fun getOverrideIcon(memberInfo: KotlinMemberInfo): Icon? { override fun getOverrideIcon(memberInfo: KotlinMemberInfo): Icon? {
val defaultIcon = AbstractMemberSelectionTable.EMPTY_OVERRIDE_ICON val defaultIcon = EMPTY_OVERRIDE_ICON
val member = memberInfo.member val member = memberInfo.member
if (member !is KtNamedFunction && member !is KtProperty && member !is KtParameter) return defaultIcon if (member !is KtNamedFunction && member !is KtProperty && member !is KtParameter) return defaultIcon
@@ -30,7 +30,6 @@ import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.module.JpsModuleSourceRootType import org.jetbrains.jps.model.module.JpsModuleSourceRootType
import org.jetbrains.jps.model.module.JpsTypedModuleSourceRoot import org.jetbrains.jps.model.module.JpsTypedModuleSourceRoot
import org.jetbrains.jps.model.serialization.facet.JpsFacetSerializer import org.jetbrains.jps.model.serialization.facet.JpsFacetSerializer
import org.jetbrains.jps.model.serialization.module.JpsModuleRootModelSerializer
import org.jetbrains.jps.model.serialization.module.JpsModuleRootModelSerializer.* import org.jetbrains.jps.model.serialization.module.JpsModuleRootModelSerializer.*
import org.jetbrains.kotlin.analyzer.common.CommonPlatform import org.jetbrains.kotlin.analyzer.common.CommonPlatform
import org.jetbrains.kotlin.config.getFacetPlatformByConfigurationElement import org.jetbrains.kotlin.config.getFacetPlatformByConfigurationElement
@@ -74,7 +73,7 @@ class KotlinNonJvmSourceRootConverterProvider : ConverterProvider("kotlin-non-jv
val moduleSettingsImpl = moduleSettings as? ModuleSettingsImpl ?: return VirtualFile.EMPTY_ARRAY val moduleSettingsImpl = moduleSettings as? ModuleSettingsImpl ?: return VirtualFile.EMPTY_ARRAY
return contextImpl return contextImpl
.getClassRoots(element, moduleSettingsImpl) .getClassRoots(element, moduleSettingsImpl)
.mapNotNull { it.toVirtualFile()?.let { JarFileSystem.getInstance().getJarRootForLocalFile(it) } } .mapNotNull { it.toVirtualFile()?.let { file -> JarFileSystem.getInstance().getJarRootForLocalFile(file) } }
.toTypedArray() .toTypedArray()
} }
} }
@@ -83,7 +82,7 @@ class KotlinNonJvmSourceRootConverterProvider : ConverterProvider("kotlin-non-jv
override val explicitKind: PersistentLibraryKind<*>? override val explicitKind: PersistentLibraryKind<*>?
get() = (library as? LibraryEx)?.kind get() = (library as? LibraryEx)?.kind
override fun getRoots() = library.getFiles(OrderRootType.CLASSES) override fun getRoots(): Array<VirtualFile> = library.getFiles(OrderRootType.CLASSES)
} }
abstract val explicitKind: PersistentLibraryKind<*>? abstract val explicitKind: PersistentLibraryKind<*>?
@@ -109,16 +108,14 @@ class KotlinNonJvmSourceRootConverterProvider : ConverterProvider("kotlin-non-jv
private fun findProjectLibrary(name: String) = projectLibrariesByName[name]?.firstOrNull() private fun findProjectLibrary(name: String) = projectLibrariesByName[name]?.firstOrNull()
private fun createLibInfo(orderEntryElement: Element, moduleSettings: ModuleSettings): LibInfo? { private fun createLibInfo(orderEntryElement: Element, moduleSettings: ModuleSettings): LibInfo? {
val entryType = orderEntryElement.getAttributeValue(ORDER_ENTRY_TYPE_ATTR) return when (orderEntryElement.getAttributeValue(ORDER_ENTRY_TYPE_ATTR)) {
return when (entryType) { MODULE_LIBRARY_TYPE -> {
JpsModuleRootModelSerializer.MODULE_LIBRARY_TYPE -> {
orderEntryElement.getChild(LIBRARY_TAG)?.let { LibInfo.ByXml(it, context, moduleSettings) } orderEntryElement.getChild(LIBRARY_TAG)?.let { LibInfo.ByXml(it, context, moduleSettings) }
} }
JpsModuleRootModelSerializer.LIBRARY_TYPE -> { LIBRARY_TYPE -> {
val libraryName = orderEntryElement.getAttributeValue(NAME_ATTRIBUTE) ?: return null val libraryName = orderEntryElement.getAttributeValue(NAME_ATTRIBUTE) ?: return null
val level = orderEntryElement.getAttributeValue(LEVEL_ATTRIBUTE) when (orderEntryElement.getAttributeValue(LEVEL_ATTRIBUTE)) {
when (level) {
LibraryTablesRegistrar.PROJECT_LEVEL -> LibraryTablesRegistrar.PROJECT_LEVEL ->
findProjectLibrary(libraryName)?.let { LibInfo.ByXml(it, context, moduleSettings) } findProjectLibrary(libraryName)?.let { LibInfo.ByXml(it, context, moduleSettings) }
LibraryTablesRegistrar.APPLICATION_LEVEL -> LibraryTablesRegistrar.APPLICATION_LEVEL ->
@@ -147,8 +144,7 @@ class KotlinNonJvmSourceRootConverterProvider : ConverterProvider("kotlin-non-jv
.asSequence() .asSequence()
.mapNotNull { createLibInfo(it, this) } .mapNotNull { createLibInfo(it, this) }
.forEach { .forEach {
val platform = it.platform when (val platform = it.platform) {
when (platform) {
is CommonPlatform -> { is CommonPlatform -> {
if (!hasCommonStdlib && it.isStdlib) { if (!hasCommonStdlib && it.isStdlib) {
hasCommonStdlib = true hasCommonStdlib = true
@@ -189,7 +185,7 @@ class KotlinNonJvmSourceRootConverterProvider : ConverterProvider("kotlin-non-jv
if (settings.isExternalModule()) return false if (settings.isExternalModule()) return false
val hasMigrationRoots = settings.getSourceFolderElements().any { val hasMigrationRoots = settings.getSourceFolderElements().any {
JpsModuleRootModelSerializer.loadSourceRoot(it).rootType in rootTypesToMigrate loadSourceRoot(it).rootType in rootTypesToMigrate
} }
if (!hasMigrationRoots) { if (!hasMigrationRoots) {
return false return false
@@ -202,8 +198,8 @@ class KotlinNonJvmSourceRootConverterProvider : ConverterProvider("kotlin-non-jv
override fun process(settings: ModuleSettings) { override fun process(settings: ModuleSettings) {
for (sourceFolder in settings.getSourceFolderElements()) { for (sourceFolder in settings.getSourceFolderElements()) {
val contentRoot = sourceFolder.parent as? Element ?: continue val contentRoot = sourceFolder.parent as? Element ?: continue
val oldSourceRoot = JpsModuleRootModelSerializer.loadSourceRoot(sourceFolder) val oldSourceRoot = loadSourceRoot(sourceFolder)
val url = sourceFolder.getAttributeValue(JpsModuleRootModelSerializer.URL_ATTRIBUTE) val url = sourceFolder.getAttributeValue(URL_ATTRIBUTE)
val (newRootType, data) = oldSourceRoot.getMigratedSourceRootTypeWithProperties() ?: continue val (newRootType, data) = oldSourceRoot.getMigratedSourceRootTypeWithProperties() ?: continue
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
@@ -211,7 +207,7 @@ class KotlinNonJvmSourceRootConverterProvider : ConverterProvider("kotlin-non-jv
as? JpsTypedModuleSourceRoot<JpsElement> ?: continue as? JpsTypedModuleSourceRoot<JpsElement> ?: continue
contentRoot.removeContent(sourceFolder) contentRoot.removeContent(sourceFolder)
JpsModuleRootModelSerializer.saveSourceRoot(contentRoot, url, newSourceRoot) saveSourceRoot(contentRoot, url, newSourceRoot)
} }
} }
} }
@@ -41,7 +41,9 @@ import org.jetbrains.kotlin.cfg.pseudocode.instructions.eval.*
import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ReturnValueInstruction import org.jetbrains.kotlin.cfg.pseudocode.instructions.jumps.ReturnValueInstruction
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder import org.jetbrains.kotlin.cfg.pseudocodeTraverser.TraversalOrder
import org.jetbrains.kotlin.cfg.pseudocodeTraverser.traverse import org.jetbrains.kotlin.cfg.pseudocodeTraverser.traverse
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource
import org.jetbrains.kotlin.descriptors.VariableDescriptorWithAccessors
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.* import org.jetbrains.kotlin.idea.caches.resolve.*
import org.jetbrains.kotlin.idea.core.isOverridable import org.jetbrains.kotlin.idea.core.isOverridable
@@ -85,19 +87,19 @@ private fun KtDeclaration.processHierarchyUpward(scope: AnalysisScope, processor
.mapNotNull { it.source.getPsi() } .mapNotNull { it.source.getPsi() }
.filter { scope.contains(it) } .filter { scope.contains(it) }
.toList() .toList()
.forEach(processor) .forEach(processor)
} }
private fun KtFunction.processCalls(scope: SearchScope, processor: (UsageInfo) -> Unit) { private fun KtFunction.processCalls(scope: SearchScope, processor: (UsageInfo) -> Unit) {
processAllExactUsages( processAllExactUsages(
{ {
KotlinFunctionFindUsagesOptions(project).apply { KotlinFunctionFindUsagesOptions(project).apply {
isSearchForTextOccurrences = false isSearchForTextOccurrences = false
isSkipImportStatements = true isSkipImportStatements = true
searchScope = scope.intersectWith(useScope) searchScope = scope.intersectWith(useScope)
} }
}, },
processor processor
) )
} }
@@ -106,31 +108,32 @@ private enum class AccessKind {
} }
private fun KtDeclaration.processVariableAccesses( private fun KtDeclaration.processVariableAccesses(
scope: SearchScope, scope: SearchScope,
kind: AccessKind, kind: AccessKind,
processor: (UsageInfo) -> Unit processor: (UsageInfo) -> Unit
) { ) {
processAllExactUsages( processAllExactUsages(
{ {
KotlinPropertyFindUsagesOptions(project).apply { KotlinPropertyFindUsagesOptions(project).apply {
isReadAccess = kind == AccessKind.READ_ONLY || kind == AccessKind.READ_OR_WRITE isReadAccess = kind == AccessKind.READ_ONLY || kind == AccessKind.READ_OR_WRITE
isWriteAccess = kind == AccessKind.WRITE_ONLY || kind == AccessKind.WRITE_WITH_OPTIONAL_READ || kind == AccessKind.READ_OR_WRITE isWriteAccess =
isReadWriteAccess = kind == AccessKind.WRITE_WITH_OPTIONAL_READ || kind == AccessKind.READ_OR_WRITE kind == AccessKind.WRITE_ONLY || kind == AccessKind.WRITE_WITH_OPTIONAL_READ || kind == AccessKind.READ_OR_WRITE
isSearchForTextOccurrences = false isReadWriteAccess = kind == AccessKind.WRITE_WITH_OPTIONAL_READ || kind == AccessKind.READ_OR_WRITE
isSkipImportStatements = true isSearchForTextOccurrences = false
searchScope = scope.intersectWith(useScope) isSkipImportStatements = true
} searchScope = scope.intersectWith(useScope)
}, }
processor },
processor
) )
} }
private fun KtParameter.canProcess() = !isVarArg private fun KtParameter.canProcess() = !isVarArg
abstract class Slicer( abstract class Slicer(
protected val element: KtExpression, protected val element: KtExpression,
protected val processor: Processor<SliceUsage>, protected val processor: Processor<SliceUsage>,
protected val parentUsage: KotlinSliceUsage protected val parentUsage: KotlinSliceUsage
) { ) {
protected class PseudocodeCache { protected class PseudocodeCache {
private val computedPseudocodes = HashMap<KtElement, Pseudocode>() private val computedPseudocodes = HashMap<KtElement, Pseudocode>()
@@ -138,7 +141,8 @@ abstract class Slicer(
operator fun get(element: KtElement): Pseudocode? { operator fun get(element: KtElement): Pseudocode? {
val container = element.containingDeclarationForPseudocode ?: return null val container = element.containingDeclarationForPseudocode ?: return null
return computedPseudocodes.getOrPut(container) { return computedPseudocodes.getOrPut(container) {
container.getContainingPseudocode(container.analyzeWithContent())?.apply { computedPseudocodes[container] = this } ?: return null container.getContainingPseudocode(container.analyzeWithContent())?.apply { computedPseudocodes[container] = this }
?: return null
} }
} }
} }
@@ -146,8 +150,8 @@ abstract class Slicer(
protected val pseudocodeCache = PseudocodeCache() protected val pseudocodeCache = PseudocodeCache()
protected fun PsiElement.passToProcessor( protected fun PsiElement.passToProcessor(
lambdaLevel: Int = parentUsage.lambdaLevel, lambdaLevel: Int = parentUsage.lambdaLevel,
forcedExpressionMode: Boolean = false forcedExpressionMode: Boolean = false
) { ) {
processor.process(KotlinSliceUsage(this, parentUsage, lambdaLevel, forcedExpressionMode)) processor.process(KotlinSliceUsage(this, parentUsage, lambdaLevel, forcedExpressionMode))
} }
@@ -156,9 +160,9 @@ abstract class Slicer(
} }
class InflowSlicer( class InflowSlicer(
element: KtExpression, element: KtExpression,
processor: Processor<SliceUsage>, processor: Processor<SliceUsage>,
parentUsage: KotlinSliceUsage parentUsage: KotlinSliceUsage
) : Slicer(element, processor, parentUsage) { ) : Slicer(element, processor, parentUsage) {
private fun PsiElement.processHierarchyDownwardAndPass() { private fun PsiElement.processHierarchyDownwardAndPass() {
processHierarchyDownward(parentUsage.scope.toSearchScope()) { passToProcessor() } processHierarchyDownward(parentUsage.scope.toSearchScope()) { passToProcessor() }
@@ -167,7 +171,7 @@ class InflowSlicer(
private fun PsiElement.passToProcessorAsValue(lambdaLevel: Int = parentUsage.lambdaLevel) = passToProcessor(lambdaLevel, true) private fun PsiElement.passToProcessorAsValue(lambdaLevel: Int = parentUsage.lambdaLevel) = passToProcessor(lambdaLevel, true)
private fun KtDeclaration.processAssignments(accessSearchScope: SearchScope) { private fun KtDeclaration.processAssignments(accessSearchScope: SearchScope) {
processVariableAccesses(accessSearchScope, AccessKind.WRITE_WITH_OPTIONAL_READ) body@ { processVariableAccesses(accessSearchScope, AccessKind.WRITE_WITH_OPTIONAL_READ) body@{
val refElement = it.element ?: return@body val refElement = it.element ?: return@body
val refParent = refElement.parent val refParent = refElement.parent
@@ -176,8 +180,7 @@ class InflowSlicer(
val (accessKind, accessExpression) = refElement.readWriteAccessWithFullExpression(true) val (accessKind, accessExpression) = refElement.readWriteAccessWithFullExpression(true)
if (accessKind == ReferenceAccess.WRITE && accessExpression is KtBinaryExpression && accessExpression.operationToken == KtTokens.EQ) { if (accessKind == ReferenceAccess.WRITE && accessExpression is KtBinaryExpression && accessExpression.operationToken == KtTokens.EQ) {
accessExpression.right accessExpression.right
} } else {
else {
accessExpression accessExpression
} }
} }
@@ -191,9 +194,9 @@ class InflowSlicer(
} }
private fun KtPropertyAccessor.processBackingFieldAssignments() { private fun KtPropertyAccessor.processBackingFieldAssignments() {
forEachDescendantOfType<KtBinaryExpression> body@ { forEachDescendantOfType<KtBinaryExpression> body@{
if (it.operationToken != KtTokens.EQ) return@body if (it.operationToken != KtTokens.EQ) return@body
val lhs = it.left?.let { KtPsiUtil.safeDeparenthesize(it) } ?: return@body val lhs = it.left?.let { expression -> KtPsiUtil.safeDeparenthesize(expression) } ?: return@body
val rhs = it.right ?: return@body val rhs = it.right ?: return@body
if (!lhs.isBackingFieldReference()) return@body if (!lhs.isBackingFieldReference()) return@body
rhs.passToProcessor() rhs.passToProcessor()
@@ -229,8 +232,7 @@ class InflowSlicer(
if (isDefaultGetter) { if (isDefaultGetter) {
if (isDefaultSetter) { if (isDefaultSetter) {
processPropertyAssignments() processPropertyAssignments()
} } else {
else {
setter!!.processBackingFieldAssignments() setter!!.processBackingFieldAssignments()
} }
} }
@@ -249,17 +251,18 @@ class InflowSlicer(
if (function is KtNamedFunction if (function is KtNamedFunction
&& function.name == OperatorNameConventions.SET_VALUE.asString() && function.name == OperatorNameConventions.SET_VALUE.asString()
&& function.hasModifier(KtTokens.OPERATOR_KEYWORD)) { && function.hasModifier(KtTokens.OPERATOR_KEYWORD)
) {
ReferencesSearch ReferencesSearch
.search(function, parentUsage.scope.toSearchScope()) .search(function, parentUsage.scope.toSearchScope())
.filterIsInstance<KtPropertyDelegationMethodsReference>() .filterIsInstance<KtPropertyDelegationMethodsReference>()
.forEach { (it.element?.parent as? KtProperty)?.processPropertyAssignments() } .forEach { (it.element.parent as? KtProperty)?.processPropertyAssignments() }
} }
val parameterDescriptor = resolveToParameterDescriptorIfAny(BodyResolveMode.FULL) ?: return val parameterDescriptor = resolveToParameterDescriptorIfAny(BodyResolveMode.FULL) ?: return
(function as? KtFunction)?.processCalls(parentUsage.scope.toSearchScope()) body@ { (function as? KtFunction)?.processCalls(parentUsage.scope.toSearchScope()) body@{
val refElement = it.element ?: return@body val refElement = it.element ?: return@body
val refParent = refElement.parent val refParent = refElement.parent
@@ -267,8 +270,7 @@ class InflowSlicer(
refElement is KtExpression -> { refElement is KtExpression -> {
val callElement = refElement.getParentOfTypeAndBranch<KtCallElement> { calleeExpression } ?: return@body val callElement = refElement.getParentOfTypeAndBranch<KtCallElement> { calleeExpression } ?: return@body
val resolvedCall = callElement.resolveToCall() ?: return@body val resolvedCall = callElement.resolveToCall() ?: return@body
val resolvedArgument = resolvedCall.valueArguments[parameterDescriptor] ?: return@body when (val resolvedArgument = resolvedCall.valueArguments[parameterDescriptor] ?: return@body) {
when (resolvedArgument) {
is DefaultValueArgument -> defaultValue is DefaultValueArgument -> defaultValue
is ExpressionValueArgument -> resolvedArgument.valueArgument?.getArgumentExpression() is ExpressionValueArgument -> resolvedArgument.valueArgument?.getArgumentExpression()
else -> null else -> null
@@ -307,8 +309,8 @@ class InflowSlicer(
private fun KtExpression.isBackingFieldReference(): Boolean { private fun KtExpression.isBackingFieldReference(): Boolean {
return this is KtSimpleNameExpression && return this is KtSimpleNameExpression &&
getReferencedName() == SyntheticFieldDescriptor.NAME.asString() && getReferencedName() == SyntheticFieldDescriptor.NAME.asString() &&
resolveToCall()?.resultingDescriptor is SyntheticFieldDescriptor resolveToCall()?.resultingDescriptor is SyntheticFieldDescriptor
} }
private fun KtExpression.processExpression() { private fun KtExpression.processExpression() {
@@ -326,8 +328,7 @@ class InflowSlicer(
val pseudocode = pseudocodeCache[this] ?: return val pseudocode = pseudocodeCache[this] ?: return
val expressionValue = pseudocode.getElementValue(this) ?: return val expressionValue = pseudocode.getElementValue(this) ?: return
val createdAt = expressionValue.createdAt when (val createdAt = expressionValue.createdAt) {
when (createdAt) {
is ReadValueInstruction -> { is ReadValueInstruction -> {
if (createdAt.target == AccessTarget.BlackBox) { if (createdAt.target == AccessTarget.BlackBox) {
val originalElement = expressionValue.element as? KtExpression ?: return val originalElement = expressionValue.element as? KtExpression ?: return
@@ -340,10 +341,9 @@ class InflowSlicer(
val accessedDeclaration = accessedDescriptor.source.getPsi() ?: return val accessedDeclaration = accessedDescriptor.source.getPsi() ?: return
if (accessedDescriptor is SyntheticFieldDescriptor) { if (accessedDescriptor is SyntheticFieldDescriptor) {
val property = accessedDeclaration as? KtProperty ?: return val property = accessedDeclaration as? KtProperty ?: return
if (accessedDescriptor.propertyDescriptor.setter?.isDefault ?: true) { if (accessedDescriptor.propertyDescriptor.setter?.isDefault != false) {
property.processPropertyAssignments() property.processPropertyAssignments()
} } else {
else {
property.setter?.processBackingFieldAssignments() property.setter?.processBackingFieldAssignments()
} }
return return
@@ -369,8 +369,7 @@ class InflowSlicer(
val resultingDescriptor = resolvedCall.resultingDescriptor val resultingDescriptor = resolvedCall.resultingDescriptor
if (resultingDescriptor is FunctionInvokeDescriptor) { if (resultingDescriptor is FunctionInvokeDescriptor) {
(resolvedCall.dispatchReceiver as? ExpressionReceiver)?.expression?.passToProcessorAsValue(parentUsage.lambdaLevel + 1) (resolvedCall.dispatchReceiver as? ExpressionReceiver)?.expression?.passToProcessorAsValue(parentUsage.lambdaLevel + 1)
} } else {
else {
resultingDescriptor.source.getPsi()?.processHierarchyDownwardAndPass() resultingDescriptor.source.getPsi()?.processHierarchyDownwardAndPass()
} }
} }
@@ -390,9 +389,9 @@ class InflowSlicer(
} }
class OutflowSlicer( class OutflowSlicer(
element: KtExpression, element: KtExpression,
processor: Processor<SliceUsage>, processor: Processor<SliceUsage>,
parentUsage: KotlinSliceUsage parentUsage: KotlinSliceUsage
) : Slicer(element, processor, parentUsage) { ) : Slicer(element, processor, parentUsage) {
private fun KtDeclaration.processVariable() { private fun KtDeclaration.processVariable() {
processHierarchyUpward(parentUsage.scope) { processHierarchyUpward(parentUsage.scope) {
@@ -400,7 +399,7 @@ class OutflowSlicer(
val withDereferences = parentUsage.params.showInstanceDereferences val withDereferences = parentUsage.params.showInstanceDereferences
val accessKind = if (withDereferences) AccessKind.READ_OR_WRITE else AccessKind.READ_ONLY val accessKind = if (withDereferences) AccessKind.READ_OR_WRITE else AccessKind.READ_ONLY
(this as? KtDeclaration)?.processVariableAccesses(parentUsage.scope.toSearchScope(), accessKind) body@ { (this as? KtDeclaration)?.processVariableAccesses(parentUsage.scope.toSearchScope(), accessKind) body@{
val refElement = it.element val refElement = it.element
if (refElement !is KtExpression) { if (refElement !is KtExpression) {
refElement?.passToProcessor() refElement?.passToProcessor()
@@ -442,22 +441,19 @@ class OutflowSlicer(
processHierarchyUpward(parentUsage.scope) { processHierarchyUpward(parentUsage.scope) {
if (this is KtFunction) { if (this is KtFunction) {
processCalls(parentUsage.scope.toSearchScope()) { processCalls(parentUsage.scope.toSearchScope()) {
val refElement = it.element when (val refElement = it.element) {
when { null -> (it.reference as? LightMemberReference)?.element?.passToProcessor()
refElement == null -> (it.reference as? LightMemberReference)?.element?.passToProcessor() is KtExpression -> {
refElement is KtExpression -> {
refElement.getCallElementForExactCallee()?.passToProcessor() refElement.getCallElementForExactCallee()?.passToProcessor()
refElement.getCallableReferenceForExactCallee()?.passToProcessor(parentUsage.lambdaLevel + 1) refElement.getCallableReferenceForExactCallee()?.passToProcessor(parentUsage.lambdaLevel + 1)
} }
else -> refElement.passToProcessor() else -> refElement.passToProcessor()
} }
} }
} } else if (this is PsiMethod && language == JavaLanguage.INSTANCE) {
else if (this is PsiMethod && language == JavaLanguage.INSTANCE) {
// todo: work around the bug in JavaSliceProvider.transform() // todo: work around the bug in JavaSliceProvider.transform()
processor.process(JavaSliceUsage.createRootUsage(this, parentUsage.params)) processor.process(JavaSliceUsage.createRootUsage(this, parentUsage.params))
} } else {
else {
passToProcessor() passToProcessor()
} }
} }
@@ -465,26 +461,26 @@ class OutflowSlicer(
} }
val funExpression = when (this) { val funExpression = when (this) {
is KtFunctionLiteral -> parent as? KtLambdaExpression is KtFunctionLiteral -> parent as? KtLambdaExpression
is KtNamedFunction -> this is KtNamedFunction -> this
else -> null else -> null
} ?: return } ?: return
(funExpression as PsiElement).passToProcessor(parentUsage.lambdaLevel + 1, true) (funExpression as PsiElement).passToProcessor(parentUsage.lambdaLevel + 1, true)
} }
private fun processDereferenceIsNeeded( private fun processDereferenceIsNeeded(
expression: KtExpression, expression: KtExpression,
pseudoValue: PseudoValue, pseudoValue: PseudoValue,
instr: InstructionWithReceivers instr: InstructionWithReceivers
) { ) {
if (!parentUsage.params.showInstanceDereferences) return if (!parentUsage.params.showInstanceDereferences) return
val receiver = instr.receiverValues[pseudoValue] val receiver = instr.receiverValues[pseudoValue]
val resolvedCall = when (instr) { val resolvedCall = when (instr) {
is CallInstruction -> instr.resolvedCall is CallInstruction -> instr.resolvedCall
is ReadValueInstruction -> (instr.target as? AccessTarget.Call)?.resolvedCall is ReadValueInstruction -> (instr.target as? AccessTarget.Call)?.resolvedCall
else -> null else -> null
} ?: return } ?: return
if (receiver != null && resolvedCall.dispatchReceiver == receiver) { if (receiver != null && resolvedCall.dispatchReceiver == receiver) {
processor.process(KotlinSliceDereferenceUsage(expression, parentUsage, parentUsage.lambdaLevel)) processor.process(KotlinSliceDereferenceUsage(expression, parentUsage, parentUsage.lambdaLevel))
@@ -513,15 +509,15 @@ class OutflowSlicer(
is CallInstruction -> { is CallInstruction -> {
if (parentUsage.lambdaLevel > 0 && instr.receiverValues[pseudoValue] != null) { if (parentUsage.lambdaLevel > 0 && instr.receiverValues[pseudoValue] != null) {
instr.element.passToProcessor(parentUsage.lambdaLevel - 1) instr.element.passToProcessor(parentUsage.lambdaLevel - 1)
} } else {
else {
instr.arguments[pseudoValue]?.source?.getPsi()?.passToProcessor() instr.arguments[pseudoValue]?.source?.getPsi()?.passToProcessor()
} }
} }
is ReturnValueInstruction -> instr.subroutine.passToProcessor() is ReturnValueInstruction -> instr.subroutine.passToProcessor()
is MagicInstruction -> when (instr.kind) { is MagicInstruction -> when (instr.kind) {
MagicKind.NOT_NULL_ASSERTION, MagicKind.CAST -> instr.outputValue.element?.passToProcessor() MagicKind.NOT_NULL_ASSERTION, MagicKind.CAST -> instr.outputValue.element?.passToProcessor()
else -> { } else -> {
}
} }
} }
} }
@@ -63,8 +63,8 @@ class KotlinCreateTestIntention : SelfTargetingRangeIntention<KtNamedDeclaration
if (element.resolveToDescriptorIfAny() == null) return null if (element.resolveToDescriptorIfAny() == null) return null
return TextRange( return TextRange(
element.startOffset, element.startOffset,
element.getSuperTypeList()?.startOffset ?: element.getBody()?.startOffset ?: element.endOffset element.getSuperTypeList()?.startOffset ?: element.body?.startOffset ?: element.endOffset
) )
} }
@@ -105,8 +105,8 @@ class KotlinCreateTestIntention : SelfTargetingRangeIntention<KtNamedDeclaration
val baseName = kotlinFile.nameWithoutExtension val baseName = kotlinFile.nameWithoutExtension
val psiDir = kotlinFile.parent!!.toPsiDirectory(project)!! val psiDir = kotlinFile.parent!!.toPsiDirectory(project)!!
return generateSequence(0) { it + 1 } return generateSequence(0) { it + 1 }
.map { "$baseName$it" } .map { "$baseName$it" }
.first { psiDir.findFile("$it.java") == null && findTestClass(psiDir, it) == null } .first { psiDir.findFile("$it.java") == null && findTestClass(psiDir, it) == null }
} }
// Based on the com.intellij.testIntegration.createTest.CreateTestAction.CreateTestAction.invoke() // Based on the com.intellij.testIntegration.createTest.CreateTestAction.CreateTestAction.invoke()
@@ -114,18 +114,20 @@ class KotlinCreateTestIntention : SelfTargetingRangeIntention<KtNamedDeclaration
val srcModule = ModuleUtilCore.findModuleForPsiElement(element) ?: return val srcModule = ModuleUtilCore.findModuleForPsiElement(element) ?: return
val propertiesComponent = PropertiesComponent.getInstance() val propertiesComponent = PropertiesComponent.getInstance()
val testFolders = HashSet<VirtualFile>() val testFolders = HashSet<VirtualFile>()
CreateTestAction.checkForTestRoots(srcModule, testFolders) checkForTestRoots(srcModule, testFolders)
if (testFolders.isEmpty() && !propertiesComponent.getBoolean("create.test.in.the.same.root")) { if (testFolders.isEmpty() && !propertiesComponent.getBoolean("create.test.in.the.same.root")) {
if (Messages.showOkCancelDialog( if (Messages.showOkCancelDialog(
project, project,
"Create test in the same source root?", "Create test in the same source root?",
"No Test Roots Found", "No Test Roots Found",
Messages.getQuestionIcon()) != Messages.OK) return Messages.getQuestionIcon()
) != Messages.OK
) return
propertiesComponent.setValue("create.test.in.the.same.root", true) propertiesComponent.setValue("create.test.in.the.same.root", true)
} }
val srcClass = CreateTestAction.getContainingClass(element) ?: return val srcClass = getContainingClass(element) ?: return
val srcDir = element.containingFile.containingDirectory val srcDir = element.containingFile.containingDirectory
val srcPackage = JavaDirectoryService.getInstance().getPackage(srcDir) val srcPackage = JavaDirectoryService.getInstance().getPackage(srcDir)
@@ -137,12 +139,12 @@ class KotlinCreateTestIntention : SelfTargetingRangeIntention<KtNamedDeclaration
if (existingClass != null) { if (existingClass != null) {
// TODO: Override dialog method when it becomes protected // TODO: Override dialog method when it becomes protected
val answer = Messages.showYesNoDialog( val answer = Messages.showYesNoDialog(
project, project,
"Kotlin class '${existingClass.name}' already exists. Do you want to update it?", "Kotlin class '${existingClass.name}' already exists. Do you want to update it?",
CommonBundle.getErrorTitle(), CommonBundle.getErrorTitle(),
"Rewrite", "Rewrite",
"Cancel", "Cancel",
Messages.getErrorIcon() Messages.getErrorIcon()
) )
if (answer == Messages.NO) return if (answer == Messages.NO) return
} }
@@ -163,7 +165,7 @@ class KotlinCreateTestIntention : SelfTargetingRangeIntention<KtNamedDeclaration
if (generatedClass.language == JavaLanguage.INSTANCE) { if (generatedClass.language == JavaLanguage.INSTANCE) {
project.executeCommand("Convert class '${generatedClass.name}' to Kotlin", this) { project.executeCommand("Convert class '${generatedClass.name}' to Kotlin", this) {
runWriteAction { runWriteAction {
generatedClass.methods.forEach { it.throwsList.referenceElements.forEach { it.delete() } } generatedClass.methods.forEach { it.throwsList.referenceElements.forEach { referenceElement -> referenceElement.delete() } }
} }
if (existingClass != null) { if (existingClass != null) {
@@ -172,16 +174,15 @@ class KotlinCreateTestIntention : SelfTargetingRangeIntention<KtNamedDeclaration
.declarations .declarations
.asSequence() .asSequence()
.filterIsInstance<KtNamedFunction>() .filterIsInstance<KtNamedFunction>()
.mapTo(HashSet()) { it.name } .mapTo(HashSet()) { it.name }
generatedClass generatedClass
.methods .methods
.filter { it.name !in existingMethodNames } .filter { it.name !in existingMethodNames }
.forEach { it.j2k()?.let { existingClass.addDeclaration(it) } } .forEach { it.j2k()?.let { declaration -> existingClass.addDeclaration(declaration) } }
generatedClass.delete() generatedClass.delete()
} }
NavigationUtil.activateFileWithPsiElement(existingClass) NavigationUtil.activateFileWithPsiElement(existingClass)
} } else {
else {
with(PsiDocumentManager.getInstance(project)) { with(PsiDocumentManager.getInstance(project)) {
getDocument(generatedFile)?.let { doPostponedOperationsAndUnblockDocument(it) } getDocument(generatedFile)?.let { doPostponedOperationsAndUnblockDocument(it) }
} }
@@ -20,7 +20,6 @@ import com.intellij.openapi.fileTypes.StdFileTypes
import com.intellij.util.indexing.DataIndexer import com.intellij.util.indexing.DataIndexer
import com.intellij.util.indexing.FileBasedIndex import com.intellij.util.indexing.FileBasedIndex
import com.intellij.util.indexing.FileContent import com.intellij.util.indexing.FileContent
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.* import org.jetbrains.kotlin.load.java.JvmAnnotationNames.*
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmMetadataVersion
@@ -76,7 +75,7 @@ object KotlinJvmMetadataVersionIndex : KotlinMetadataVersionIndexBase<KotlinJvmM
kind = KotlinClassHeader.Kind.getById(value) kind = KotlinClassHeader.Kind.getById(value)
} }
METADATA_EXTRA_INT_FIELD_NAME -> if (value is Int) { METADATA_EXTRA_INT_FIELD_NAME -> if (value is Int) {
isStrictSemantics = (value and JvmAnnotationNames.METADATA_STRICT_VERSION_SEMANTICS_FLAG) != 0 isStrictSemantics = (value and METADATA_STRICT_VERSION_SEMANTICS_FLAG) != 0
} }
} }
} }