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