Misc: Cleanup "org.jetbrains.kotlin.idea.intentions" package

This commit is contained in:
Alexey Sedunov
2015-12-17 19:33:02 +03:00
parent 3fca8f765c
commit 2fb3c727a7
89 changed files with 927 additions and 980 deletions
@@ -21,47 +21,47 @@ import com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
public class AddBracesIntention : SelfTargetingIntention<KtExpression>(javaClass(), "Add braces") { public class AddBracesIntention : SelfTargetingIntention<KtExpression>(KtExpression::class.java, "Add braces") {
override fun isApplicableTo(element: KtExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtExpression, caretOffset: Int): Boolean {
val expression = element.getTargetExpression(caretOffset) ?: return false val expression = element.getTargetExpression(caretOffset) ?: return false
if (expression is KtBlockExpression) return false if (expression is KtBlockExpression) return false
val description = (expression.getParent() as KtContainerNode).description()!! val description = (expression.parent as KtContainerNode).description()!!
setText("Add braces to '$description' statement") text = "Add braces to '$description' statement"
return true return true
} }
override fun applyTo(element: KtExpression, editor: Editor) { override fun applyTo(element: KtExpression, editor: Editor) {
val expression = element.getTargetExpression(editor.getCaretModel().getOffset())!! val expression = element.getTargetExpression(editor.caretModel.offset)!!
if (element.getNextSibling()?.getText() == ";") { if (element.nextSibling?.text == ";") {
element.getNextSibling()!!.delete() element.nextSibling!!.delete()
} }
val psiFactory = KtPsiFactory(element) val psiFactory = KtPsiFactory(element)
expression.replace(psiFactory.createSingleStatementBlock(expression)) expression.replace(psiFactory.createSingleStatementBlock(expression))
if (element is KtDoWhileExpression) { // remove new line between '}' and while if (element is KtDoWhileExpression) { // remove new line between '}' and while
(element.getBody()!!.getParent().getNextSibling() as? PsiWhiteSpace)?.delete() (element.body!!.parent.nextSibling as? PsiWhiteSpace)?.delete()
} }
} }
private fun KtExpression.getTargetExpression(caretLocation: Int): KtExpression? { private fun KtExpression.getTargetExpression(caretLocation: Int): KtExpression? {
when (this) { when (this) {
is KtIfExpression -> { is KtIfExpression -> {
val thenExpr = getThen() ?: return null val thenExpr = then ?: return null
val elseExpr = getElse() val elseExpr = `else`
if (elseExpr != null && caretLocation >= getElseKeyword()!!.startOffset) { if (elseExpr != null && caretLocation >= elseKeyword!!.startOffset) {
return elseExpr return elseExpr
} }
return thenExpr return thenExpr
} }
is KtWhileExpression -> return getBody() is KtWhileExpression -> return body
is KtDoWhileExpression -> return getBody() is KtDoWhileExpression -> return body
is KtForExpression -> return getBody() is KtForExpression -> return body
else -> return null else -> return null
} }
@@ -33,7 +33,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
public class AddForLoopIndicesIntention : SelfTargetingRangeIntention<KtForExpression>(javaClass(), "Add indices to 'for' loop"), LowPriorityAction { public class AddForLoopIndicesIntention : SelfTargetingRangeIntention<KtForExpression>(KtForExpression::class.java, "Add indices to 'for' loop"), LowPriorityAction {
private val WITH_INDEX_NAME = "withIndex" private val WITH_INDEX_NAME = "withIndex"
private val WITH_INDEX_FQ_NAMES = listOf("collections", "sequences", "text", "ranges").map { "kotlin.$it.$WITH_INDEX_NAME" }.toSet() private val WITH_INDEX_FQ_NAMES = listOf("collections", "sequences", "text", "ranges").map { "kotlin.$it.$WITH_INDEX_NAME" }.toSet()
@@ -24,7 +24,6 @@ import org.jetbrains.kotlin.idea.conversion.copy.end
import org.jetbrains.kotlin.idea.conversion.copy.start import org.jetbrains.kotlin.idea.conversion.copy.start
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatchStatus import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatchStatus
@@ -32,16 +31,16 @@ import org.jetbrains.kotlin.resolve.calls.model.VarargValueArgument
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
public class AddNameToArgumentIntention public class AddNameToArgumentIntention
: SelfTargetingIntention<KtValueArgument>(javaClass(), "Add name to argument"), LowPriorityAction { : SelfTargetingIntention<KtValueArgument>(KtValueArgument::class.java, "Add name to argument"), LowPriorityAction {
override fun isApplicableTo(element: KtValueArgument, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtValueArgument, caretOffset: Int): Boolean {
val expression = element.getArgumentExpression() ?: return false val expression = element.getArgumentExpression() ?: return false
val name = detectNameToAdd(element) ?: return false val name = detectNameToAdd(element) ?: return false
setText("Add '$name =' to argument") text = "Add '$name =' to argument"
if (expression is KtLambdaExpression) { if (expression is KtLambdaExpression) {
val range = expression.getTextRange() val range = expression.textRange
return caretOffset == range.start || caretOffset == range.end return caretOffset == range.start || caretOffset == range.end
} }
@@ -61,21 +60,21 @@ public class AddNameToArgumentIntention
if (argument.isNamed()) return null if (argument.isNamed()) return null
if (argument is KtLambdaArgument) return null if (argument is KtLambdaArgument) return null
val argumentList = argument.getParent() as? KtValueArgumentList ?: return null val argumentList = argument.parent as? KtValueArgumentList ?: return null
if (argument != argumentList.arguments.last { !it.isNamed() }) return null if (argument != argumentList.arguments.last { !it.isNamed() }) return null
val callExpr = argumentList.getParent() as? KtExpression ?: return null val callExpr = argumentList.parent as? KtExpression ?: return null
val resolvedCall = callExpr.getResolvedCall(callExpr.analyze(BodyResolveMode.PARTIAL)) ?: return null val resolvedCall = callExpr.getResolvedCall(callExpr.analyze(BodyResolveMode.PARTIAL)) ?: return null
val argumentMatch = resolvedCall.getArgumentMapping(argument) as? ArgumentMatch ?: return null val argumentMatch = resolvedCall.getArgumentMapping(argument) as? ArgumentMatch ?: return null
if (argumentMatch.status != ArgumentMatchStatus.SUCCESS) return null if (argumentMatch.status != ArgumentMatchStatus.SUCCESS) return null
if (!resolvedCall.getResultingDescriptor().hasStableParameterNames()) return null if (!resolvedCall.resultingDescriptor.hasStableParameterNames()) return null
if (argumentMatch.valueParameter.varargElementType != null) { if (argumentMatch.valueParameter.varargElementType != null) {
val varargArgument = resolvedCall.getValueArguments()[argumentMatch.valueParameter] as? VarargValueArgument ?: return null val varargArgument = resolvedCall.valueArguments[argumentMatch.valueParameter] as? VarargValueArgument ?: return null
if (varargArgument.getArguments().size() != 1) return null if (varargArgument.arguments.size != 1) return null
} }
return argumentMatch.valueParameter.getName() return argumentMatch.valueParameter.name
} }
} }
@@ -21,14 +21,13 @@ import com.intellij.openapi.util.TextRange
import com.intellij.psi.search.LocalSearchScope import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.searches.ReferencesSearch import com.intellij.psi.search.searches.ReferencesSearch
import org.jetbrains.kotlin.idea.core.replaced import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.inspections.RedundantSamConstructorInspection
import org.jetbrains.kotlin.idea.util.CommentSaver import org.jetbrains.kotlin.idea.util.CommentSaver
import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.psi.psiUtil.contentRange
import org.jetbrains.kotlin.psi.psiUtil.getParentOfTypeAndBranch
import org.jetbrains.kotlin.psi.psiUtil.parents
import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
class AnonymousFunctionToLambdaIntention : SelfTargetingRangeIntention<KtNamedFunction>( class AnonymousFunctionToLambdaIntention : SelfTargetingRangeIntention<KtNamedFunction>(
KtNamedFunction::class.java, KtNamedFunction::class.java,
@@ -32,39 +32,39 @@ import org.jetbrains.kotlin.resolve.BindingContext
public open class ChangeVisibilityModifierIntention protected constructor( public open class ChangeVisibilityModifierIntention protected constructor(
val modifier: KtModifierKeywordToken val modifier: KtModifierKeywordToken
) : SelfTargetingRangeIntention<KtDeclaration>(javaClass(), "Make ${modifier.getValue()}") { ) : SelfTargetingRangeIntention<KtDeclaration>(KtDeclaration::class.java, "Make ${modifier.value}") {
override fun applicabilityRange(element: KtDeclaration): TextRange? { override fun applicabilityRange(element: KtDeclaration): TextRange? {
val modifierList = element.getModifierList() val modifierList = element.modifierList
if (modifierList?.hasModifier(modifier) ?: false) return null if (modifierList?.hasModifier(modifier) ?: false) return null
var descriptor = element.toDescriptor() as? DeclarationDescriptorWithVisibility ?: return null var descriptor = element.toDescriptor() as? DeclarationDescriptorWithVisibility ?: return null
val targetVisibility = modifier.toVisibility() val targetVisibility = modifier.toVisibility()
if (descriptor.getVisibility() == targetVisibility) return null if (descriptor.visibility == targetVisibility) return null
if (modifierList?.hasModifier(KtTokens.OVERRIDE_KEYWORD) ?: false) { if (modifierList?.hasModifier(KtTokens.OVERRIDE_KEYWORD) ?: false) {
val callableDescriptor = descriptor as? CallableDescriptor ?: return null val callableDescriptor = descriptor as? CallableDescriptor ?: return null
// cannot make visibility less than (or non-comparable with) any of the supers // cannot make visibility less than (or non-comparable with) any of the supers
if (callableDescriptor.getOverriddenDescriptors() if (callableDescriptor.overriddenDescriptors
.map { Visibilities.compare(it.getVisibility(), targetVisibility) } .map { Visibilities.compare(it.visibility, targetVisibility) }
.any { it == null || it > 0 }) return null .any { it == null || it > 0 }) return null
} }
setText(defaultText) text = defaultText
val modifierElement = element.visibilityModifier() val modifierElement = element.visibilityModifier()
if (modifierElement != null) { if (modifierElement != null) {
return modifierElement.getTextRange() return modifierElement.textRange
} }
val defaultRange = noModifierYetApplicabilityRange(element) ?: return null val defaultRange = noModifierYetApplicabilityRange(element) ?: return null
if (element is KtPrimaryConstructor && defaultRange.isEmpty()) { if (element is KtPrimaryConstructor && defaultRange.isEmpty) {
setText("Make primary constructor ${modifier.getValue()}") // otherwise it may be confusing text = "Make primary constructor ${modifier.value}" // otherwise it may be confusing
} }
return if (modifierList != null) return if (modifierList != null)
TextRange(modifierList.startOffset, defaultRange.getEndOffset()) //TODO: smaller range? now it includes annotations too TextRange(modifierList.startOffset, defaultRange.endOffset) //TODO: smaller range? now it includes annotations too
else else
defaultRange defaultRange
} }
@@ -73,7 +73,7 @@ public open class ChangeVisibilityModifierIntention protected constructor(
val bindingContext = analyze() val bindingContext = analyze()
// TODO: temporary code // TODO: temporary code
if (this is KtPrimaryConstructor) { if (this is KtPrimaryConstructor) {
return (this.getContainingClassOrObject().resolveToDescriptor() as ClassDescriptor).getUnsubstitutedPrimaryConstructor() return (this.getContainingClassOrObject().resolveToDescriptor() as ClassDescriptor).unsubstitutedPrimaryConstructor
} }
val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, this] val descriptor = bindingContext[BindingContext.DECLARATION_TO_DESCRIPTOR, this]
@@ -100,13 +100,13 @@ public open class ChangeVisibilityModifierIntention protected constructor(
private fun noModifierYetApplicabilityRange(declaration: KtDeclaration): TextRange? { private fun noModifierYetApplicabilityRange(declaration: KtDeclaration): TextRange? {
if (KtPsiUtil.isLocal(declaration)) return null if (KtPsiUtil.isLocal(declaration)) return null
return when (declaration) { return when (declaration) {
is KtNamedFunction -> declaration.getFunKeyword()?.getTextRange() is KtNamedFunction -> declaration.funKeyword?.textRange
is KtProperty -> declaration.getValOrVarKeyword().getTextRange() is KtProperty -> declaration.valOrVarKeyword.textRange
is KtClass -> declaration.getClassOrInterfaceKeyword()?.getTextRange() is KtClass -> declaration.getClassOrInterfaceKeyword()?.textRange
is KtObjectDeclaration -> declaration.getObjectKeyword().getTextRange() is KtObjectDeclaration -> declaration.getObjectKeyword().textRange
is KtPrimaryConstructor -> declaration.getValueParameterList()?.let { TextRange.from(it.startOffset, 0) } //TODO: use constructor keyword if exist is KtPrimaryConstructor -> declaration.valueParameterList?.let { TextRange.from(it.startOffset, 0) } //TODO: use constructor keyword if exist
is KtSecondaryConstructor -> declaration.getConstructorKeyword().getTextRange() is KtSecondaryConstructor -> declaration.getConstructorKeyword().textRange
is KtParameter -> declaration.getValOrVarKeyword()?.getTextRange() is KtParameter -> declaration.valOrVarKeyword?.textRange
else -> null else -> null
} }
} }
@@ -115,11 +115,11 @@ public open class ChangeVisibilityModifierIntention protected constructor(
public class Private : ChangeVisibilityModifierIntention(KtTokens.PRIVATE_KEYWORD), HighPriorityAction { public class Private : ChangeVisibilityModifierIntention(KtTokens.PRIVATE_KEYWORD), HighPriorityAction {
override fun applicabilityRange(element: KtDeclaration): TextRange? { override fun applicabilityRange(element: KtDeclaration): TextRange? {
return if (canBePrivate(element)) super<ChangeVisibilityModifierIntention>.applicabilityRange(element) else null return if (canBePrivate(element)) super.applicabilityRange(element) else null
} }
private fun canBePrivate(declaration: KtDeclaration): Boolean { private fun canBePrivate(declaration: KtDeclaration): Boolean {
if (declaration.getModifierList()?.hasModifier(KtTokens.ABSTRACT_KEYWORD) ?: false) return false if (declaration.modifierList?.hasModifier(KtTokens.ABSTRACT_KEYWORD) ?: false) return false
return true return true
} }
} }
@@ -130,9 +130,9 @@ public open class ChangeVisibilityModifierIntention protected constructor(
} }
private fun canBeProtected(declaration: KtDeclaration): Boolean { private fun canBeProtected(declaration: KtDeclaration): Boolean {
var parent = declaration.getParent() var parent = declaration.parent
if (parent is KtClassBody) { if (parent is KtClassBody) {
parent = parent.getParent() parent = parent.parent
} }
return parent is KtClass return parent is KtClass
} }
@@ -16,18 +16,12 @@
package org.jetbrains.kotlin.idea.intentions package org.jetbrains.kotlin.idea.intentions
import com.intellij.codeInsight.completion.InsertHandler
import com.intellij.codeInsight.completion.InsertionContext
import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.codeInsight.lookup.LookupElementBuilder
import com.intellij.codeInsight.template.Expression import com.intellij.codeInsight.template.Expression
import com.intellij.codeInsight.template.ExpressionContext import com.intellij.codeInsight.template.ExpressionContext
import com.intellij.codeInsight.template.Result
import com.intellij.codeInsight.template.TextResult import com.intellij.codeInsight.template.TextResult
import com.intellij.codeInsight.template.impl.TemplateManagerImpl import com.intellij.codeInsight.template.impl.TemplateManagerImpl
import com.intellij.codeInsight.template.impl.TemplateState
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.TextRange
import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil
//TODO: move it somewhere else and reuse //TODO: move it somewhere else and reuse
@@ -41,21 +35,20 @@ public abstract class ChooseValueExpression<T : Any>(
protected abstract fun getResult(element: T): String protected abstract fun getResult(element: T): String
protected val lookupItems: Array<LookupElement> = lookupItems.map { suggestion -> protected val lookupItems: Array<LookupElement> = lookupItems.map { suggestion ->
LookupElementBuilder.create(suggestion, getLookupString(suggestion)).withInsertHandler(object : InsertHandler<LookupElement> { LookupElementBuilder.create(suggestion, getLookupString(suggestion)).withInsertHandler { context, item ->
override fun handleInsert(context: InsertionContext, item: LookupElement) { val topLevelEditor = InjectedLanguageUtil.getTopLevelEditor(context.editor)
val topLevelEditor = InjectedLanguageUtil.getTopLevelEditor(context.getEditor()) val templateState = TemplateManagerImpl.getTemplateState(topLevelEditor)
val templateState = TemplateManagerImpl.getTemplateState(topLevelEditor) if (templateState != null) {
if (templateState != null) { val range = templateState.currentVariableRange
val range = templateState.getCurrentVariableRange() if (range != null) {
if (range != null) { @Suppress("UNCHECKED_CAST")
topLevelEditor.getDocument().replaceString(range.getStartOffset(), range.getEndOffset(), getResult(item.getObject() as T)) topLevelEditor.document.replaceString(range.startOffset, range.endOffset, getResult(item.`object` as T))
}
} }
} }
}) }
}.toTypedArray() }.toTypedArray()
override fun calculateLookupItems(context: ExpressionContext) = if (lookupItems.size() > 1) lookupItems else null override fun calculateLookupItems(context: ExpressionContext) = if (lookupItems.size > 1) lookupItems else null
override fun calculateQuickResult(context: ExpressionContext) = calculateResult(context) override fun calculateQuickResult(context: ExpressionContext) = calculateResult(context)
@@ -30,24 +30,24 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.utils.addToStdlib.check import org.jetbrains.kotlin.utils.addToStdlib.check
public class ConvertAssertToIfWithThrowIntention : SelfTargetingIntention<KtCallExpression>(javaClass(), "Replace 'assert' with 'if' statement"), LowPriorityAction { public class ConvertAssertToIfWithThrowIntention : SelfTargetingIntention<KtCallExpression>(KtCallExpression::class.java, "Replace 'assert' with 'if' statement"), LowPriorityAction {
override fun isApplicableTo(element: KtCallExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtCallExpression, caretOffset: Int): Boolean {
val callee = element.getCalleeExpression() ?: return false val callee = element.calleeExpression ?: return false
if (!callee.getTextRange().containsOffset(caretOffset)) return false if (!callee.textRange.containsOffset(caretOffset)) return false
val argumentSize = element.getValueArguments().size() val argumentSize = element.valueArguments.size
if (argumentSize !in 1..2) return false if (argumentSize !in 1..2) return false
val functionLiterals = element.getLambdaArguments() val functionLiterals = element.lambdaArguments
if (functionLiterals.size() > 1) return false if (functionLiterals.size > 1) return false
if (functionLiterals.size() == 1 && argumentSize == 1) return false // "assert {...}" is incorrect if (functionLiterals.size == 1 && argumentSize == 1) return false // "assert {...}" is incorrect
val resolvedCall = element.getResolvedCall(element.analyze()) ?: return false val resolvedCall = element.getResolvedCall(element.analyze()) ?: return false
return DescriptorUtils.getFqName(resolvedCall.getResultingDescriptor()).asString() == "kotlin.assert" return DescriptorUtils.getFqName(resolvedCall.resultingDescriptor).asString() == "kotlin.assert"
} }
override fun applyTo(element: KtCallExpression, editor: Editor) { override fun applyTo(element: KtCallExpression, editor: Editor) {
val args = element.getValueArguments() val args = element.valueArguments
val conditionText = args[0]?.getArgumentExpression()?.getText() ?: return val conditionText = args[0]?.getArgumentExpression()?.text ?: return
val functionLiteralArgument = element.lambdaArguments.singleOrNull() val functionLiteralArgument = element.lambdaArguments.singleOrNull()
val bindingContext = element.analyze(BodyResolveMode.PARTIAL) val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
val psiFactory = KtPsiFactory(element) val psiFactory = KtPsiFactory(element)
@@ -66,29 +66,29 @@ public class ConvertAssertToIfWithThrowIntention : SelfTargetingIntention<KtCall
val ifExpression = replaceWithIfThenThrowExpression(element) val ifExpression = replaceWithIfThenThrowExpression(element)
// shorten java.lang.AssertionError // shorten java.lang.AssertionError
ShortenReferences.DEFAULT.process(ifExpression.getThen()!!) ShortenReferences.DEFAULT.process(ifExpression.then!!)
val ifCondition = ifExpression.getCondition() as KtPrefixExpression val ifCondition = ifExpression.condition as KtPrefixExpression
ifCondition.getBaseExpression()!!.replace(psiFactory.createExpression(conditionText)) ifCondition.baseExpression!!.replace(psiFactory.createExpression(conditionText))
val thrownExpression = ((ifExpression.getThen() as KtBlockExpression).getStatements().single() as KtThrowExpression).getThrownExpression() val thrownExpression = ((ifExpression.then as KtBlockExpression).statements.single() as KtThrowExpression).thrownExpression
val assertionErrorCall = if (thrownExpression is KtCallExpression) val assertionErrorCall = if (thrownExpression is KtCallExpression)
thrownExpression thrownExpression
else else
(thrownExpression as KtDotQualifiedExpression).getSelectorExpression() as KtCallExpression (thrownExpression as KtDotQualifiedExpression).selectorExpression as KtCallExpression
val message = psiFactory.createExpression( val message = psiFactory.createExpression(
if (messageIsFunction && messageExpr is KtCallableReferenceExpression) { if (messageIsFunction && messageExpr is KtCallableReferenceExpression) {
messageExpr.getCallableReference().getText() + "()" messageExpr.callableReference.text + "()"
} }
else if (messageIsFunction) { else if (messageIsFunction) {
messageExpr.getText() + "()" messageExpr.text + "()"
} }
else { else {
messageExpr.getText() messageExpr.text
} }
) )
assertionErrorCall.getValueArguments().single().getArgumentExpression()!!.replace(message) assertionErrorCall.valueArguments.single().getArgumentExpression()!!.replace(message)
simplifyConditionIfPossible(ifExpression) simplifyConditionIfPossible(ifExpression)
} }
@@ -101,12 +101,12 @@ public class ConvertAssertToIfWithThrowIntention : SelfTargetingIntention<KtCall
private fun messageIsFunction(callExpr: KtCallExpression, bindingContext: BindingContext): Boolean { private fun messageIsFunction(callExpr: KtCallExpression, bindingContext: BindingContext): Boolean {
val resolvedCall = callExpr.getResolvedCall(bindingContext) ?: return false val resolvedCall = callExpr.getResolvedCall(bindingContext) ?: return false
val valParameters = resolvedCall.getResultingDescriptor().getValueParameters() val valParameters = resolvedCall.resultingDescriptor.valueParameters
return valParameters.size() > 1 && !KotlinBuiltIns.isAny(valParameters[1].type) return valParameters.size > 1 && !KotlinBuiltIns.isAny(valParameters[1].type)
} }
private fun simplifyConditionIfPossible(ifExpression: KtIfExpression) { private fun simplifyConditionIfPossible(ifExpression: KtIfExpression) {
val condition = ifExpression.getCondition() as KtPrefixExpression val condition = ifExpression.condition as KtPrefixExpression
val simplifier = SimplifyNegatedBinaryExpressionIntention() val simplifier = SimplifyNegatedBinaryExpressionIntention()
if (simplifier.isApplicableTo(condition)) { if (simplifier.isApplicableTo(condition)) {
simplifier.applyTo(condition) simplifier.applyTo(condition)
@@ -115,7 +115,7 @@ public class ConvertAssertToIfWithThrowIntention : SelfTargetingIntention<KtCall
private fun replaceWithIfThenThrowExpression(original: KtCallExpression): KtIfExpression { private fun replaceWithIfThenThrowExpression(original: KtCallExpression): KtIfExpression {
val replacement = KtPsiFactory(original).createExpression("if (!true) { throw java.lang.AssertionError(\"\") }") as KtIfExpression val replacement = KtPsiFactory(original).createExpression("if (!true) { throw java.lang.AssertionError(\"\") }") as KtIfExpression
val parent = original.getParent() val parent = original.parent
return if (parent is KtDotQualifiedExpression) return if (parent is KtDotQualifiedExpression)
parent.replaced(replacement) parent.replaced(replacement)
else else
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver
public class ConvertForEachToForLoopIntention : SelfTargetingOffsetIndependentIntention<KtSimpleNameExpression>(javaClass(), "Replace with a 'for' loop") { public class ConvertForEachToForLoopIntention : SelfTargetingOffsetIndependentIntention<KtSimpleNameExpression>(KtSimpleNameExpression::class.java, "Replace with a 'for' loop") {
private val FOR_EACH_NAME = "forEach" private val FOR_EACH_NAME = "forEach"
private val FOR_EACH_FQ_NAMES = listOf("collections", "sequences", "text", "ranges").map { "kotlin.$it.$FOR_EACH_NAME" }.toSet() private val FOR_EACH_FQ_NAMES = listOf("collections", "sequences", "text", "ranges").map { "kotlin.$it.$FOR_EACH_NAME" }.toSet()
@@ -33,8 +33,8 @@ public class ConvertForEachToForLoopIntention : SelfTargetingOffsetIndependentIn
if (element.getReferencedName() != FOR_EACH_NAME) return false if (element.getReferencedName() != FOR_EACH_NAME) return false
val data = extractData(element) ?: return false val data = extractData(element) ?: return false
if (data.functionLiteral.getValueParameters().size() > 1) return false if (data.functionLiteral.valueParameters.size > 1) return false
if (data.functionLiteral.getBodyExpression() == null) return false if (data.functionLiteral.bodyExpression == null) return false
return true return true
} }
@@ -57,18 +57,18 @@ public class ConvertForEachToForLoopIntention : SelfTargetingOffsetIndependentIn
) )
private fun extractData(nameExpr: KtSimpleNameExpression): Data? { private fun extractData(nameExpr: KtSimpleNameExpression): Data? {
val parent = nameExpr.getParent() val parent = nameExpr.parent
val expression = (when (parent) { val expression = (when (parent) {
is KtCallExpression -> parent.getParent() as? KtDotQualifiedExpression is KtCallExpression -> parent.parent as? KtDotQualifiedExpression
is KtBinaryExpression -> parent is KtBinaryExpression -> parent
else -> null else -> null
} ?: return null) as KtExpression //TODO: submit bug } ?: return null) as KtExpression //TODO: submit bug
val resolvedCall = expression.getResolvedCall(expression.analyze()) ?: return null val resolvedCall = expression.getResolvedCall(expression.analyze()) ?: return null
if (DescriptorUtils.getFqName(resolvedCall.getResultingDescriptor()).toString() !in FOR_EACH_FQ_NAMES) return null if (DescriptorUtils.getFqName(resolvedCall.resultingDescriptor).toString() !in FOR_EACH_FQ_NAMES) return null
val receiver = resolvedCall.getCall().getExplicitReceiver() as? ExpressionReceiver ?: return null val receiver = resolvedCall.call.explicitReceiver as? ExpressionReceiver ?: return null
val argument = resolvedCall.getCall().getValueArguments().singleOrNull() ?: return null val argument = resolvedCall.call.valueArguments.singleOrNull() ?: return null
val functionLiteral = argument.getArgumentExpression() as? KtLambdaExpression ?: return null val functionLiteral = argument.getArgumentExpression() as? KtLambdaExpression ?: return null
return Data(expression, receiver.expression, functionLiteral) return Data(expression, receiver.expression, functionLiteral)
} }
@@ -76,8 +76,8 @@ public class ConvertForEachToForLoopIntention : SelfTargetingOffsetIndependentIn
private fun generateLoop(functionLiteral: KtLambdaExpression, receiver: KtExpression): KtExpression { private fun generateLoop(functionLiteral: KtLambdaExpression, receiver: KtExpression): KtExpression {
val factory = KtPsiFactory(functionLiteral) val factory = KtPsiFactory(functionLiteral)
val loopRange = KtPsiUtil.safeDeparenthesize(receiver) val loopRange = KtPsiUtil.safeDeparenthesize(receiver)
val body = functionLiteral.getBodyExpression()!! val body = functionLiteral.bodyExpression!!
val parameter = functionLiteral.getValueParameters().singleOrNull() val parameter = functionLiteral.valueParameters.singleOrNull()
return factory.createExpressionByPattern("for($0 in $1){ $2 }", parameter ?: "it", loopRange, body) return factory.createExpressionByPattern("for($0 in $1){ $2 }", parameter ?: "it", loopRange, body)
} }
} }
@@ -56,13 +56,13 @@ import org.jetbrains.kotlin.types.expressions.OperatorConventions
import org.jetbrains.kotlin.types.typeUtil.supertypes import org.jetbrains.kotlin.types.typeUtil.supertypes
import java.util.* import java.util.*
public class ConvertFunctionToPropertyIntention : SelfTargetingIntention<KtNamedFunction>(javaClass(), "Convert function to property"), LowPriorityAction { public class ConvertFunctionToPropertyIntention : SelfTargetingIntention<KtNamedFunction>(KtNamedFunction::class.java, "Convert function to property"), LowPriorityAction {
private var KtNamedFunction.typeFqNameToAdd: String? by UserDataProperty(Key.create("TYPE_FQ_NAME_TO_ADD")) private var KtNamedFunction.typeFqNameToAdd: String? by UserDataProperty(Key.create("TYPE_FQ_NAME_TO_ADD"))
private inner class Converter( private inner class Converter(
project: Project, project: Project,
descriptor: FunctionDescriptor descriptor: FunctionDescriptor
): CallableRefactoring<FunctionDescriptor>(project, descriptor, getText()) { ): CallableRefactoring<FunctionDescriptor>(project, descriptor, text) {
private val elementsToShorten = ArrayList<KtElement>() private val elementsToShorten = ArrayList<KtElement>()
private val newName: String by lazy { private val newName: String by lazy {
@@ -75,31 +75,31 @@ public class ConvertFunctionToPropertyIntention : SelfTargetingIntention<KtNamed
val propertySample = psiFactory.createProperty("val foo: Int get() = 1") val propertySample = psiFactory.createProperty("val foo: Int get() = 1")
val needsExplicitType = function.getTypeReference() == null val needsExplicitType = function.typeReference == null
if (needsExplicitType) { if (needsExplicitType) {
originalFunction.typeFqNameToAdd?.let { function.setTypeReference(psiFactory.createType(it)) } originalFunction.typeFqNameToAdd?.let { function.setTypeReference(psiFactory.createType(it)) }
} }
function.getFunKeyword()!!.replace(propertySample.getValOrVarKeyword()) function.funKeyword!!.replace(propertySample.valOrVarKeyword)
function.getValueParameterList()?.delete() function.valueParameterList?.delete()
val insertAfter = (function.getEqualsToken() ?: function.getBodyExpression()) val insertAfter = (function.equalsToken ?: function.bodyExpression)
?.siblings(forward = false, withItself = false) ?.siblings(forward = false, withItself = false)
?.firstOrNull { it !is PsiWhiteSpace } ?.firstOrNull { it !is PsiWhiteSpace }
if (insertAfter != null) { if (insertAfter != null) {
function.addAfter(psiFactory.createParameterList("()"), insertAfter) function.addAfter(psiFactory.createParameterList("()"), insertAfter)
function.addAfter(propertySample.getGetter()!!.getNamePlaceholder(), insertAfter) function.addAfter(propertySample.getter!!.namePlaceholder, insertAfter)
} }
function.setName(newName) function.setName(newName)
val property = originalFunction.replace(psiFactory.createProperty(function.getText())) as KtProperty val property = originalFunction.replace(psiFactory.createProperty(function.text)) as KtProperty
if (needsExplicitType) { if (needsExplicitType) {
elementsToShorten.add(property.getTypeReference()!!) elementsToShorten.add(property.typeReference!!)
} }
} }
override fun performRefactoring(descriptorsForChange: Collection<CallableDescriptor>) { override fun performRefactoring(descriptorsForChange: Collection<CallableDescriptor>) {
val conflicts = MultiMap<PsiElement, String>() val conflicts = MultiMap<PsiElement, String>()
val getterName = JvmAbi.getterName(callableDescriptor.getName().asString()) val getterName = JvmAbi.getterName(callableDescriptor.name.asString())
val callables = getAffectedCallables(project, descriptorsForChange) val callables = getAffectedCallables(project, descriptorsForChange)
val kotlinCalls = ArrayList<KtCallElement>() val kotlinCalls = ArrayList<KtCallElement>()
val kotlinRefsToRename = ArrayList<PsiReference>() val kotlinRefsToRename = ArrayList<PsiReference>()
@@ -112,13 +112,13 @@ public class ConvertFunctionToPropertyIntention : SelfTargetingIntention<KtNamed
} }
if (callable is KtNamedFunction) { if (callable is KtNamedFunction) {
if (callable.getTypeReference() == null) { if (callable.typeReference == null) {
val functionDescriptor = callable.resolveToDescriptor() as FunctionDescriptor val functionDescriptor = callable.resolveToDescriptor() as FunctionDescriptor
val type = functionDescriptor.getReturnType() val type = functionDescriptor.returnType
val typeToInsert = when { val typeToInsert = when {
type == null || type.isError() -> null type == null || type.isError -> null
type.getConstructor().isDenotable() -> type type.constructor.isDenotable -> type
else -> type.supertypes().firstOrNull { it.getConstructor().isDenotable() } else -> type.supertypes().firstOrNull { it.constructor.isDenotable }
} ?: functionDescriptor.builtIns.nullableAnyType } ?: functionDescriptor.builtIns.nullableAnyType
callable.typeFqNameToAdd = IdeDescriptorRenderers.SOURCE_CODE.renderType(typeToInsert) callable.typeFqNameToAdd = IdeDescriptorRenderers.SOURCE_CODE.renderType(typeToInsert)
} }
@@ -130,10 +130,10 @@ public class ConvertFunctionToPropertyIntention : SelfTargetingIntention<KtNamed
} }
if (callable is PsiMethod) { if (callable is PsiMethod) {
callable.getContainingClass() callable.containingClass
?.findMethodsByName(getterName, true) ?.findMethodsByName(getterName, true)
// as is necessary here: see KT-10386 // as is necessary here: see KT-10386
?.firstOrNull { it.getParameterList().getParametersCount() == 0 && it.namedUnwrappedElement as PsiElement? !in callables } ?.firstOrNull { it.parameterList.parametersCount == 0 && !callables.contains(it.namedUnwrappedElement as PsiElement?) }
?.let { reportDeclarationConflict(conflicts, it) { "$it already exists" } } ?.let { reportDeclarationConflict(conflicts, it) { "$it already exists" } }
} }
@@ -141,19 +141,19 @@ public class ConvertFunctionToPropertyIntention : SelfTargetingIntention<KtNamed
for (usage in usages) { for (usage in usages) {
if (usage is KtSimpleNameReference) { if (usage is KtSimpleNameReference) {
val expression = usage.expression val expression = usage.expression
val callElement = expression.getParentOfTypeAndBranch<KtCallElement> { getCalleeExpression() } val callElement = expression.getParentOfTypeAndBranch<KtCallElement> { calleeExpression }
if (callElement != null && expression.getStrictParentOfType<KtCallableReferenceExpression>() == null) { if (callElement != null && expression.getStrictParentOfType<KtCallableReferenceExpression>() == null) {
if (callElement.getTypeArguments().isNotEmpty()) { if (callElement.typeArguments.isNotEmpty()) {
conflicts.putValue( conflicts.putValue(
callElement, callElement,
"Type arguments will be lost after conversion: ${StringUtil.htmlEmphasize(callElement.getText())}" "Type arguments will be lost after conversion: ${StringUtil.htmlEmphasize(callElement.text)}"
) )
} }
if (callElement.getValueArguments().isNotEmpty()) { if (callElement.valueArguments.isNotEmpty()) {
conflicts.putValue( conflicts.putValue(
callElement, callElement,
"Call with arguments will be skipped: ${StringUtil.htmlEmphasize(callElement.getText())}" "Call with arguments will be skipped: ${StringUtil.htmlEmphasize(callElement.text)}"
) )
continue continue
} }
@@ -171,7 +171,7 @@ public class ConvertFunctionToPropertyIntention : SelfTargetingIntention<KtNamed
} }
project.checkConflictsInteractively(conflicts) { project.checkConflictsInteractively(conflicts) {
project.executeWriteCommand(getText()) { project.executeWriteCommand(text) {
val psiFactory = KtPsiFactory(project) val psiFactory = KtPsiFactory(project)
val newGetterName = JvmAbi.getterName(newName) val newGetterName = JvmAbi.getterName(newName)
val newRefExpr = psiFactory.createExpression(newName) val newRefExpr = psiFactory.createExpression(newName)
@@ -195,25 +195,25 @@ public class ConvertFunctionToPropertyIntention : SelfTargetingIntention<KtNamed
override fun startInWriteAction(): Boolean = false override fun startInWriteAction(): Boolean = false
override fun isApplicableTo(element: KtNamedFunction, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtNamedFunction, caretOffset: Int): Boolean {
val identifier = element.getNameIdentifier() ?: return false val identifier = element.nameIdentifier ?: return false
if (!identifier.getTextRange().containsOffset(caretOffset)) return false if (!identifier.textRange.containsOffset(caretOffset)) return false
if (element.getValueParameters().isNotEmpty() || element.isLocal()) return false if (element.valueParameters.isNotEmpty() || element.isLocal) return false
val name = element.getName()!! val name = element.name!!
if (name == "invoke" || name == "iterator" || Name.identifier(name) in OperatorConventions.UNARY_OPERATION_NAMES.inverse().keySet()) { if (name == "invoke" || name == "iterator" || Name.identifier(name) in OperatorConventions.UNARY_OPERATION_NAMES.inverse().keys) {
return false return false
} }
val descriptor = element.analyze(BodyResolveMode.PARTIAL)[BindingContext.DECLARATION_TO_DESCRIPTOR, element] as? FunctionDescriptor val descriptor = element.analyze(BodyResolveMode.PARTIAL)[BindingContext.DECLARATION_TO_DESCRIPTOR, element] as? FunctionDescriptor
?: return false ?: return false
val returnType = descriptor.getReturnType() ?: return false val returnType = descriptor.returnType ?: return false
return !KotlinBuiltIns.isUnit(returnType) && !KotlinBuiltIns.isNothing(returnType) return !KotlinBuiltIns.isUnit(returnType) && !KotlinBuiltIns.isNothing(returnType)
} }
override fun applyTo(element: KtNamedFunction, editor: Editor) { override fun applyTo(element: KtNamedFunction, editor: Editor) {
val context = element.analyze(BodyResolveMode.PARTIAL) val context = element.analyze(BodyResolveMode.PARTIAL)
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, element] as FunctionDescriptor val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, element] as FunctionDescriptor
Converter(element.getProject(), descriptor).run() Converter(element.project, descriptor).run()
} }
} }
@@ -17,48 +17,46 @@
package org.jetbrains.kotlin.idea.intentions package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.unwrapBlockOrParenthesis
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isNullExpression
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.idea.core.copied
import org.jetbrains.kotlin.idea.core.replaced import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isNullExpression
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.unwrapBlockOrParenthesis
import org.jetbrains.kotlin.idea.util.ShortenReferences
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
public class ConvertIfWithThrowToAssertIntention : SelfTargetingOffsetIndependentIntention<KtIfExpression>(javaClass(), "Replace 'if' with 'assert' statement") { public class ConvertIfWithThrowToAssertIntention : SelfTargetingOffsetIndependentIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' with 'assert' statement") {
override fun isApplicableTo(element: KtIfExpression): Boolean { override fun isApplicableTo(element: KtIfExpression): Boolean {
if (element.getElse() != null) return false if (element.`else` != null) return false
val throwExpr = element.getThen()?.unwrapBlockOrParenthesis() as? KtThrowExpression val throwExpr = element.then?.unwrapBlockOrParenthesis() as? KtThrowExpression
val thrownExpr = getSelector(throwExpr?.getThrownExpression()) val thrownExpr = getSelector(throwExpr?.thrownExpression)
if (thrownExpr !is KtCallExpression) return false if (thrownExpr !is KtCallExpression) return false
if (thrownExpr.getValueArguments().size() > 1) return false if (thrownExpr.valueArguments.size > 1) return false
val resolvedCall = thrownExpr.getResolvedCall(thrownExpr.analyze()) ?: return false val resolvedCall = thrownExpr.getResolvedCall(thrownExpr.analyze()) ?: return false
return DescriptorUtils.getFqName(resolvedCall.getResultingDescriptor()).toString() == "java.lang.AssertionError.<init>" return DescriptorUtils.getFqName(resolvedCall.resultingDescriptor).toString() == "java.lang.AssertionError.<init>"
} }
override fun applyTo(element: KtIfExpression, editor: Editor) { override fun applyTo(element: KtIfExpression, editor: Editor) {
val condition = element.getCondition() ?: return val condition = element.condition ?: return
val thenExpr = element.getThen()?.unwrapBlockOrParenthesis() as KtThrowExpression val thenExpr = element.then?.unwrapBlockOrParenthesis() as KtThrowExpression
val thrownExpr = getSelector(thenExpr.getThrownExpression()) as KtCallExpression val thrownExpr = getSelector(thenExpr.thrownExpression) as KtCallExpression
val psiFactory = KtPsiFactory(element) val psiFactory = KtPsiFactory(element)
condition.replace(psiFactory.createExpressionByPattern("!$0", condition)) condition.replace(psiFactory.createExpressionByPattern("!$0", condition))
var newCondition = element.getCondition()!! var newCondition = element.condition!!
val simplifier = SimplifyNegatedBinaryExpressionIntention() val simplifier = SimplifyNegatedBinaryExpressionIntention()
if (simplifier.isApplicableTo(newCondition as KtPrefixExpression)) { if (simplifier.isApplicableTo(newCondition as KtPrefixExpression)) {
simplifier.applyTo(newCondition, editor) simplifier.applyTo(newCondition, editor)
newCondition = element.getCondition()!! newCondition = element.condition!!
} }
val arg = thrownExpr.getValueArguments().singleOrNull()?.getArgumentExpression() val arg = thrownExpr.valueArguments.singleOrNull()?.getArgumentExpression()
val assertExpr = if (arg != null && !arg.isNullExpression()) val assertExpr = if (arg != null && !arg.isNullExpression())
psiFactory.createExpressionByPattern("kotlin.assert($0) {$1}", newCondition, arg) psiFactory.createExpressionByPattern("kotlin.assert($0) {$1}", newCondition, arg)
else else
@@ -70,7 +68,7 @@ public class ConvertIfWithThrowToAssertIntention : SelfTargetingOffsetIndependen
private fun getSelector(element: KtExpression?): KtExpression? { private fun getSelector(element: KtExpression?): KtExpression? {
if (element is KtDotQualifiedExpression) { if (element is KtDotQualifiedExpression) {
return element.getSelectorExpression() return element.selectorExpression
} }
return element return element
} }
@@ -17,32 +17,30 @@
package org.jetbrains.kotlin.idea.intentions package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import java.util.LinkedList import java.util.*
public class ConvertNegatedBooleanSequenceIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>( public class ConvertNegatedBooleanSequenceIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>(
javaClass(), "Replace negated sequence with DeMorgan equivalent") { KtBinaryExpression::class.java, "Replace negated sequence with DeMorgan equivalent"
) {
override fun isApplicableTo(element: KtBinaryExpression): Boolean { override fun isApplicableTo(element: KtBinaryExpression): Boolean {
if (element.getParent() is KtBinaryExpression) return false // operate only on the longest sequence if (element.parent is KtBinaryExpression) return false // operate only on the longest sequence
val opToken = element.getOperationToken() val opToken = element.operationToken
if (opToken != KtTokens.ANDAND && opToken != KtTokens.OROR) return false if (opToken != KtTokens.ANDAND && opToken != KtTokens.OROR) return false
return splitBooleanSequence(element) != null return splitBooleanSequence(element) != null
} }
override fun applyTo(element: KtBinaryExpression, editor: Editor) { override fun applyTo(element: KtBinaryExpression, editor: Editor) {
val operatorText = when(element.getOperationToken()) { val operatorText = when(element.operationToken) {
KtTokens.ANDAND -> KtTokens.OROR.getValue() KtTokens.ANDAND -> KtTokens.OROR.value
KtTokens.OROR -> KtTokens.ANDAND.getValue() KtTokens.OROR -> KtTokens.ANDAND.value
else -> throw IllegalArgumentException() // checked in isApplicableTo else -> throw IllegalArgumentException() // checked in isApplicableTo
} }
val elements = splitBooleanSequence(element)!! val elements = splitBooleanSequence(element)!!
val bareExpressions = elements.map { prefixExpression -> prefixExpression.getBaseExpression()!!.getText() } val bareExpressions = elements.map { prefixExpression -> prefixExpression.baseExpression!!.text }
val negatedExpression = bareExpressions.subList(0, bareExpressions.lastIndex).foldRight( val negatedExpression = bareExpressions.subList(0, bareExpressions.lastIndex).foldRight(
"!(${bareExpressions.last()}", { negated, expression -> "$expression $operatorText $negated" } "!(${bareExpressions.last()}", { negated, expression -> "$expression $operatorText $negated" }
) )
@@ -50,7 +48,7 @@ public class ConvertNegatedBooleanSequenceIntention : SelfTargetingOffsetIndepen
val newExpression = KtPsiFactory(element).createExpression("$negatedExpression)") val newExpression = KtPsiFactory(element).createExpression("$negatedExpression)")
val insertedElement = element.replace(newExpression) val insertedElement = element.replace(newExpression)
val insertedElementParent = insertedElement.getParent() as? KtParenthesizedExpression ?: return val insertedElementParent = insertedElement.parent as? KtParenthesizedExpression ?: return
if (KtPsiUtil.areParenthesesUseless(insertedElementParent)) { if (KtPsiUtil.areParenthesesUseless(insertedElementParent)) {
insertedElementParent.replace(insertedElement) insertedElementParent.replace(insertedElement)
@@ -59,16 +57,16 @@ public class ConvertNegatedBooleanSequenceIntention : SelfTargetingOffsetIndepen
private fun splitBooleanSequence(expression: KtBinaryExpression): List<KtPrefixExpression>? { private fun splitBooleanSequence(expression: KtBinaryExpression): List<KtPrefixExpression>? {
val itemList = LinkedList<KtPrefixExpression>() val itemList = LinkedList<KtPrefixExpression>()
val firstOperator = expression.getOperationToken() val firstOperator = expression.operationToken
var currentItem: KtBinaryExpression? = expression var currentItem: KtBinaryExpression? = expression
while (currentItem != null) { while (currentItem != null) {
if (currentItem.getOperationToken() != firstOperator) return null //Boolean sequence must be homogeneous if (currentItem.operationToken != firstOperator) return null //Boolean sequence must be homogeneous
val rightChild = currentItem.getRight() as? KtPrefixExpression ?: return null val rightChild = currentItem.right as? KtPrefixExpression ?: return null
itemList.add(rightChild) itemList.add(rightChild)
val leftChild = currentItem.getLeft() val leftChild = currentItem.left
when (leftChild) { when (leftChild) {
is KtPrefixExpression -> itemList.add(leftChild) is KtPrefixExpression -> itemList.add(leftChild)
!is KtBinaryExpression -> return null !is KtBinaryExpression -> return null
@@ -21,18 +21,17 @@ import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import java.util.* import java.util.*
public class ConvertNegatedExpressionWithDemorgansLawIntention : SelfTargetingOffsetIndependentIntention<KtPrefixExpression>(javaClass(), "DeMorgan Law") { public class ConvertNegatedExpressionWithDemorgansLawIntention : SelfTargetingOffsetIndependentIntention<KtPrefixExpression>(KtPrefixExpression::class.java, "DeMorgan Law") {
override fun isApplicableTo(element: KtPrefixExpression): Boolean { override fun isApplicableTo(element: KtPrefixExpression): Boolean {
val prefixOperator = element.getOperationReference().getReferencedNameElementType() val prefixOperator = element.operationReference.getReferencedNameElementType()
if (prefixOperator != KtTokens.EXCL) return false if (prefixOperator != KtTokens.EXCL) return false
val parenthesizedExpression = element.getBaseExpression() as? KtParenthesizedExpression val parenthesizedExpression = element.baseExpression as? KtParenthesizedExpression
val baseExpression = parenthesizedExpression?.getExpression() as? KtBinaryExpression ?: return false val baseExpression = parenthesizedExpression?.expression as? KtBinaryExpression ?: return false
when (baseExpression.getOperationToken()) { when (baseExpression.operationToken) {
KtTokens.ANDAND -> setText("Replace '&&' with '||'") KtTokens.ANDAND -> text = "Replace '&&' with '||'"
KtTokens.OROR -> setText("Replace '||' with '&&'") KtTokens.OROR -> text = "Replace '||' with '&&'"
else -> return false else -> return false
} }
@@ -44,12 +43,12 @@ public class ConvertNegatedExpressionWithDemorgansLawIntention : SelfTargetingOf
} }
fun applyTo(element: KtPrefixExpression) { fun applyTo(element: KtPrefixExpression) {
val parenthesizedExpression = element.getBaseExpression() as KtParenthesizedExpression val parenthesizedExpression = element.baseExpression as KtParenthesizedExpression
val baseExpression = parenthesizedExpression.getExpression() as KtBinaryExpression val baseExpression = parenthesizedExpression.expression as KtBinaryExpression
val operatorText = when (baseExpression.getOperationToken()) { val operatorText = when (baseExpression.operationToken) {
KtTokens.ANDAND -> KtTokens.OROR.getValue() KtTokens.ANDAND -> KtTokens.OROR.value
KtTokens.OROR -> KtTokens.ANDAND.getValue() KtTokens.OROR -> KtTokens.ANDAND.value
else -> throw IllegalArgumentException() else -> throw IllegalArgumentException()
} }
@@ -64,19 +63,19 @@ public class ConvertNegatedExpressionWithDemorgansLawIntention : SelfTargetingOf
private fun splitBooleanSequence(expression: KtBinaryExpression): List<KtExpression>? { private fun splitBooleanSequence(expression: KtBinaryExpression): List<KtExpression>? {
val result = ArrayList<KtExpression>() val result = ArrayList<KtExpression>()
val firstOperator = expression.getOperationToken() val firstOperator = expression.operationToken
var remainingExpression: KtExpression = expression var remainingExpression: KtExpression = expression
while (true) { while (true) {
if (remainingExpression !is KtBinaryExpression) break if (remainingExpression !is KtBinaryExpression) break
val operation = remainingExpression.getOperationToken() val operation = remainingExpression.operationToken
if (operation != KtTokens.ANDAND && operation != KtTokens.OROR) break if (operation != KtTokens.ANDAND && operation != KtTokens.OROR) break
if (operation != firstOperator) return null //Boolean sequence must be homogenous if (operation != firstOperator) return null //Boolean sequence must be homogenous
result.add(remainingExpression.getRight() ?: return null) result.add(remainingExpression.right ?: return null)
remainingExpression = remainingExpression.getLeft() ?: return null remainingExpression = remainingExpression.left ?: return null
} }
result.add(remainingExpression) result.add(remainingExpression)
@@ -29,19 +29,19 @@ import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
public class ConvertParameterToReceiverIntention : SelfTargetingIntention<KtParameter>(javaClass(), "Convert parameter to receiver") { public class ConvertParameterToReceiverIntention : SelfTargetingIntention<KtParameter>(KtParameter::class.java, "Convert parameter to receiver") {
override fun isApplicableTo(element: KtParameter, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtParameter, caretOffset: Int): Boolean {
val identifier = element.getNameIdentifier() ?: return false val identifier = element.nameIdentifier ?: return false
if (!identifier.getTextRange().containsOffset(caretOffset)) return false if (!identifier.textRange.containsOffset(caretOffset)) return false
if (element.isVarArg()) return false if (element.isVarArg) return false
val function = element.getStrictParentOfType<KtNamedFunction>() ?: return false val function = element.getStrictParentOfType<KtNamedFunction>() ?: return false
return function.getValueParameterList() == element.getParent() && function.getReceiverTypeReference() == null return function.valueParameterList == element.parent && function.receiverTypeReference == null
} }
private fun configureChangeSignature(parameterIndex: Int): KotlinChangeSignatureConfiguration { private fun configureChangeSignature(parameterIndex: Int): KotlinChangeSignatureConfiguration {
return object : KotlinChangeSignatureConfiguration { return object : KotlinChangeSignatureConfiguration {
override fun configure(originalDescriptor: KotlinMethodDescriptor): KotlinMethodDescriptor { override fun configure(originalDescriptor: KotlinMethodDescriptor): KotlinMethodDescriptor {
return originalDescriptor.modify { it.receiver = originalDescriptor.getParameters()[parameterIndex] } return originalDescriptor.modify { it.receiver = originalDescriptor.parameters[parameterIndex] }
} }
override fun performSilently(affectedFunctions: Collection<PsiElement>) = true override fun performSilently(affectedFunctions: Collection<PsiElement>) = true
@@ -52,9 +52,9 @@ public class ConvertParameterToReceiverIntention : SelfTargetingIntention<KtPara
override fun applyTo(element: KtParameter, editor: Editor) { override fun applyTo(element: KtParameter, editor: Editor) {
val function = element.getStrictParentOfType<KtNamedFunction>() ?: return val function = element.getStrictParentOfType<KtNamedFunction>() ?: return
val parameterIndex = function.getValueParameters().indexOf(element) val parameterIndex = function.valueParameters.indexOf(element)
val context = function.analyze() val context = function.analyze()
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, function] as? FunctionDescriptor ?: return val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, function] as? FunctionDescriptor ?: return
runChangeSignature(element.project, descriptor, configureChangeSignature(parameterIndex), element, getText()) runChangeSignature(element.project, descriptor, configureChangeSignature(parameterIndex), element, text)
} }
} }
@@ -17,16 +17,11 @@
package org.jetbrains.kotlin.idea.intentions package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration
import org.jetbrains.kotlin.resolve.BindingContext
class ConvertPropertyInitializerToGetterIntention : SelfTargetingIntention<KtProperty>(javaClass(), "Convert property initializer to getter") { class ConvertPropertyInitializerToGetterIntention : SelfTargetingIntention<KtProperty>(KtProperty::class.java, "Convert property initializer to getter") {
override fun isApplicableTo(element: KtProperty, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtProperty, caretOffset: Int): Boolean {
return element.initializer != null return element.initializer != null
&& element.initializer?.textRange?.containsOffset(caretOffset) == true && element.initializer?.textRange?.containsOffset(caretOffset) == true
@@ -35,8 +30,8 @@ class ConvertPropertyInitializerToGetterIntention : SelfTargetingIntention<KtPro
&& !element.isLocal && !element.isLocal
} }
override fun applyTo(property: KtProperty, editor: Editor) { override fun applyTo(element: KtProperty, editor: Editor) {
convertPropertyInitializerToGetter(property, editor) convertPropertyInitializerToGetter(element, editor)
} }
companion object { companion object {
@@ -50,44 +50,44 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.utils.findFunction import org.jetbrains.kotlin.resolve.scopes.utils.findFunction
import java.util.* import java.util.*
public class ConvertPropertyToFunctionIntention : SelfTargetingIntention<KtProperty>(javaClass(), "Convert property to function"), LowPriorityAction { public class ConvertPropertyToFunctionIntention : SelfTargetingIntention<KtProperty>(KtProperty::class.java, "Convert property to function"), LowPriorityAction {
private inner class Converter( private inner class Converter(
project: Project, project: Project,
descriptor: CallableDescriptor descriptor: CallableDescriptor
): CallableRefactoring<CallableDescriptor>(project, descriptor, getText()) { ): CallableRefactoring<CallableDescriptor>(project, descriptor, text) {
private val newName: String = JvmAbi.getterName(callableDescriptor.name.asString()) private val newName: String = JvmAbi.getterName(callableDescriptor.name.asString())
private fun convertProperty(originalProperty: KtProperty, psiFactory: KtPsiFactory) { private fun convertProperty(originalProperty: KtProperty, psiFactory: KtPsiFactory) {
val property = originalProperty.copy() as KtProperty; val property = originalProperty.copy() as KtProperty;
val getter = property.getGetter(); val getter = property.getter;
val sampleFunction = psiFactory.createFunction("fun foo() {\n\n}"); val sampleFunction = psiFactory.createFunction("fun foo() {\n\n}");
property.getValOrVarKeyword().replace(sampleFunction.getFunKeyword()!!); property.valOrVarKeyword.replace(sampleFunction.funKeyword!!);
property.addAfter(psiFactory.createParameterList("()"), property.getNameIdentifier()); property.addAfter(psiFactory.createParameterList("()"), property.nameIdentifier);
if (property.getInitializer() == null) { if (property.initializer == null) {
if (getter != null) { if (getter != null) {
val dropGetterTo = (getter.getEqualsToken() ?: getter.getBodyExpression()) val dropGetterTo = (getter.equalsToken ?: getter.bodyExpression)
?.siblings(forward = false, withItself = false) ?.siblings(forward = false, withItself = false)
?.firstOrNull { it !is PsiWhiteSpace } ?.firstOrNull { it !is PsiWhiteSpace }
getter.deleteChildRange(getter.getFirstChild(), dropGetterTo) getter.deleteChildRange(getter.firstChild, dropGetterTo)
val dropPropertyFrom = getter val dropPropertyFrom = getter
.siblings(forward = false, withItself = false) .siblings(forward = false, withItself = false)
.first { it !is PsiWhiteSpace } .first { it !is PsiWhiteSpace }
.getNextSibling() .nextSibling
property.deleteChildRange(dropPropertyFrom, getter.getPrevSibling()) property.deleteChildRange(dropPropertyFrom, getter.prevSibling)
} }
} }
property.setName(newName) property.setName(newName)
originalProperty.replace(psiFactory.createFunction(property.getText())) originalProperty.replace(psiFactory.createFunction(property.text))
} }
override fun performRefactoring(descriptorsForChange: Collection<CallableDescriptor>) { override fun performRefactoring(descriptorsForChange: Collection<CallableDescriptor>) {
val propertyName = callableDescriptor.getName().asString() val propertyName = callableDescriptor.name.asString()
val nameChanged = propertyName != newName val nameChanged = propertyName != newName
val getterName = JvmAbi.getterName(callableDescriptor.getName().asString()) val getterName = JvmAbi.getterName(callableDescriptor.name.asString())
val conflicts = MultiMap<PsiElement, String>() val conflicts = MultiMap<PsiElement, String>()
val callables = getAffectedCallables(project, descriptorsForChange) val callables = getAffectedCallables(project, descriptorsForChange)
val kotlinRefsToReplaceWithCall = ArrayList<KtSimpleNameExpression>() val kotlinRefsToReplaceWithCall = ArrayList<KtSimpleNameExpression>()
@@ -108,10 +108,10 @@ public class ConvertPropertyToFunctionIntention : SelfTargetingIntention<KtPrope
?.let { reportDeclarationConflict(conflicts, it) { "$it already exists" } } ?.let { reportDeclarationConflict(conflicts, it) { "$it already exists" } }
} }
else if (callable is PsiMethod) { else if (callable is PsiMethod) {
callable.getContainingClass() callable.containingClass
?.findMethodsByName(propertyName, true) ?.findMethodsByName(propertyName, true)
// as is necessary here: see KT-10386 // as is necessary here: see KT-10386
?.firstOrNull { it.getParameterList().getParametersCount() == 0 && it.namedUnwrappedElement as PsiElement? !in callables } ?.firstOrNull { it.parameterList.parametersCount == 0 && !callables.contains(it.namedUnwrappedElement as PsiElement?) }
?.let { reportDeclarationConflict(conflicts, it) { "$it already exists" } } ?.let { reportDeclarationConflict(conflicts, it) { "$it already exists" } }
} }
@@ -129,18 +129,18 @@ public class ConvertPropertyToFunctionIntention : SelfTargetingIntention<KtPrope
} }
} }
else { else {
val refElement = usage.getElement() val refElement = usage.element
conflicts.putValue( conflicts.putValue(
refElement, refElement,
"Unrecognized reference will be skipped: " + StringUtil.htmlEmphasize(refElement.getText()) "Unrecognized reference will be skipped: " + StringUtil.htmlEmphasize(refElement.text)
) )
} }
continue continue
} }
val refElement = usage.getElement() val refElement = usage.element
if (refElement.getText().endsWith(getterName)) continue if (refElement.text.endsWith(getterName)) continue
if (usage is PsiJavaReference) { if (usage is PsiJavaReference) {
if (usage.resolve() is PsiField && usage is PsiReferenceExpression) { if (usage.resolve() is PsiField && usage is PsiReferenceExpression) {
@@ -151,13 +151,13 @@ public class ConvertPropertyToFunctionIntention : SelfTargetingIntention<KtPrope
conflicts.putValue( conflicts.putValue(
refElement, refElement,
"Can't replace foreign reference with call expression: " + StringUtil.htmlEmphasize(refElement.getText()) "Can't replace foreign reference with call expression: " + StringUtil.htmlEmphasize(refElement.text)
) )
} }
} }
project.checkConflictsInteractively(conflicts) { project.checkConflictsInteractively(conflicts) {
project.executeWriteCommand(getText()) { project.executeWriteCommand(text) {
val kotlinPsiFactory = KtPsiFactory(project) val kotlinPsiFactory = KtPsiFactory(project)
val javaPsiFactory = PsiElementFactory.SERVICE.getInstance(project) val javaPsiFactory = PsiElementFactory.SERVICE.getInstance(project)
val newKotlinCallExpr = kotlinPsiFactory.createExpression("$newName()") val newKotlinCallExpr = kotlinPsiFactory.createExpression("$newName()")
@@ -182,14 +182,14 @@ public class ConvertPropertyToFunctionIntention : SelfTargetingIntention<KtPrope
override fun startInWriteAction(): Boolean = false override fun startInWriteAction(): Boolean = false
override fun isApplicableTo(element: KtProperty, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtProperty, caretOffset: Int): Boolean {
val identifier = element.getNameIdentifier() ?: return false val identifier = element.nameIdentifier ?: return false
if (!identifier.getTextRange().containsOffset(caretOffset)) return false if (!identifier.textRange.containsOffset(caretOffset)) return false
return element.getDelegate() == null && !element.isVar() && !element.isLocal() return element.delegate == null && !element.isVar && !element.isLocal
} }
override fun applyTo(element: KtProperty, editor: Editor) { override fun applyTo(element: KtProperty, editor: Editor) {
val context = element.analyze() val context = element.analyze()
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, element] as? CallableDescriptor ?: return val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, element] as? CallableDescriptor ?: return
Converter(element.getProject(), descriptor).run() Converter(element.project, descriptor).run()
} }
} }
@@ -28,9 +28,9 @@ import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtTypeReference import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
public class ConvertReceiverToParameterIntention : SelfTargetingOffsetIndependentIntention<KtTypeReference>(javaClass(), "Convert receiver to parameter"), LowPriorityAction { public class ConvertReceiverToParameterIntention : SelfTargetingOffsetIndependentIntention<KtTypeReference>(KtTypeReference::class.java, "Convert receiver to parameter"), LowPriorityAction {
override fun isApplicableTo(element: KtTypeReference): Boolean { override fun isApplicableTo(element: KtTypeReference): Boolean {
return (element.getParent() as? KtNamedFunction)?.getReceiverTypeReference() == element return (element.parent as? KtNamedFunction)?.receiverTypeReference == element
} }
private fun configureChangeSignature(): KotlinChangeSignatureConfiguration { private fun configureChangeSignature(): KotlinChangeSignatureConfiguration {
@@ -44,9 +44,9 @@ public class ConvertReceiverToParameterIntention : SelfTargetingOffsetIndependen
override fun startInWriteAction() = false override fun startInWriteAction() = false
override fun applyTo(element: KtTypeReference, editor: Editor) { override fun applyTo(element: KtTypeReference, editor: Editor) {
val function = element.getParent() as? KtNamedFunction ?: return val function = element.parent as? KtNamedFunction ?: return
val context = function.analyze() val context = function.analyze()
val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, function] as? FunctionDescriptor ?: return val descriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, function] as? FunctionDescriptor ?: return
runChangeSignature(element.project, descriptor, configureChangeSignature(), element, getText()) runChangeSignature(element.project, descriptor, configureChangeSignature(), element, text)
} }
} }
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
public class ConvertToBlockBodyIntention : SelfTargetingIntention<KtDeclarationWithBody>( public class ConvertToBlockBodyIntention : SelfTargetingIntention<KtDeclarationWithBody>(
javaClass(), "Convert to block body" KtDeclarationWithBody::class.java, "Convert to block body"
), LowPriorityAction { ), LowPriorityAction {
override fun isApplicableTo(element: KtDeclarationWithBody, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtDeclarationWithBody, caretOffset: Int): Boolean {
if (element is KtFunctionLiteral || element.hasBlockBody() || !element.hasBody()) return false if (element is KtFunctionLiteral || element.hasBlockBody() || !element.hasBody()) return false
@@ -35,7 +35,7 @@ public class ConvertToBlockBodyIntention : SelfTargetingIntention<KtDeclarationW
when (element) { when (element) {
is KtNamedFunction -> { is KtNamedFunction -> {
val returnType = element.returnType() ?: return false val returnType = element.returnType() ?: return false
if (!element.hasDeclaredReturnType() && returnType.isError()) return false// do not convert when type is implicit and unknown if (!element.hasDeclaredReturnType() && returnType.isError) return false// do not convert when type is implicit and unknown
return true return true
} }
@@ -53,7 +53,7 @@ public class ConvertToBlockBodyIntention : SelfTargetingIntention<KtDeclarationW
companion object { companion object {
public fun convert(declaration: KtDeclarationWithBody): KtDeclarationWithBody { public fun convert(declaration: KtDeclarationWithBody): KtDeclarationWithBody {
val body = declaration.getBodyExpression()!! val body = declaration.bodyExpression!!
fun generateBody(returnsValue: Boolean): KtExpression { fun generateBody(returnsValue: Boolean): KtExpression {
val bodyType = body.analyze().getType(body) val bodyType = body.analyze().getType(body)
@@ -74,19 +74,19 @@ public class ConvertToBlockBodyIntention : SelfTargetingIntention<KtDeclarationW
generateBody(!KotlinBuiltIns.isUnit(returnType) && !KotlinBuiltIns.isNothing(returnType)) generateBody(!KotlinBuiltIns.isUnit(returnType) && !KotlinBuiltIns.isNothing(returnType))
} }
is KtPropertyAccessor -> generateBody(declaration.isGetter()) is KtPropertyAccessor -> generateBody(declaration.isGetter)
else -> throw RuntimeException("Unknown declaration type: $declaration") else -> throw RuntimeException("Unknown declaration type: $declaration")
} }
declaration.getEqualsToken()!!.delete() declaration.equalsToken!!.delete()
body.replace(newBody) body.replace(newBody)
return declaration return declaration
} }
private fun KtNamedFunction.returnType(): KotlinType? { private fun KtNamedFunction.returnType(): KotlinType? {
val descriptor = analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, this] ?: return null val descriptor = analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, this] ?: return null
return (descriptor as FunctionDescriptor).getReturnType() return (descriptor as FunctionDescriptor).returnType
} }
} }
} }
@@ -22,21 +22,20 @@ import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContextUtils
public class ConvertToConcatenatedStringIntention : SelfTargetingOffsetIndependentIntention<KtStringTemplateExpression>(javaClass(), "Convert template to concatenated string"), LowPriorityAction { public class ConvertToConcatenatedStringIntention : SelfTargetingOffsetIndependentIntention<KtStringTemplateExpression>(KtStringTemplateExpression::class.java, "Convert template to concatenated string"), LowPriorityAction {
override fun isApplicableTo(element: KtStringTemplateExpression): Boolean { override fun isApplicableTo(element: KtStringTemplateExpression): Boolean {
if (element.getLastChild().getNode().getElementType() != KtTokens.CLOSING_QUOTE) return false // not available for unclosed literal if (element.lastChild.node.elementType != KtTokens.CLOSING_QUOTE) return false // not available for unclosed literal
return element.getEntries().any { it is KtStringTemplateEntryWithExpression } return element.entries.any { it is KtStringTemplateEntryWithExpression }
} }
override fun applyTo(element: KtStringTemplateExpression, editor: Editor) { override fun applyTo(element: KtStringTemplateExpression, editor: Editor) {
val tripleQuoted = isTripleQuoted(element.getText()!!) val tripleQuoted = isTripleQuoted(element.text!!)
val quote = if (tripleQuoted) "\"\"\"" else "\"" val quote = if (tripleQuoted) "\"\"\"" else "\""
val entries = element.getEntries() val entries = element.entries
val text = entries val text = entries
.filterNot { it is KtStringTemplateEntryWithExpression && it.getExpression() == null } .filterNot { it is KtStringTemplateEntryWithExpression && it.expression == null }
.mapIndexed { index, entry -> .mapIndexed { index, entry ->
entry.toSeparateString(quote, convertExplicitly = (index == 0), isFinalEntry = (index == entries.lastIndex)) entry.toSeparateString(quote, convertExplicitly = (index == 0), isFinalEntry = (index == entries.lastIndex))
} }
@@ -51,15 +50,15 @@ public class ConvertToConcatenatedStringIntention : SelfTargetingOffsetIndepende
private fun KtStringTemplateEntry.toSeparateString(quote: String, convertExplicitly: Boolean, isFinalEntry: Boolean): String { private fun KtStringTemplateEntry.toSeparateString(quote: String, convertExplicitly: Boolean, isFinalEntry: Boolean): String {
if (this !is KtStringTemplateEntryWithExpression) { if (this !is KtStringTemplateEntryWithExpression) {
return getText().quote(quote) return text.quote(quote)
} }
val expression = getExpression()!! // checked before val expression = expression!! // checked before
val text = if (needsParenthesis(expression, isFinalEntry)) val text = if (needsParenthesis(expression, isFinalEntry))
"(" + expression.getText() + ")" "(" + expression.text + ")"
else else
expression.getText() expression.text
return if (convertExplicitly && !expression.isStringExpression()) return if (convertExplicitly && !expression.isStringExpression())
text + ".toString()" text + ".toString()"
@@ -70,7 +69,7 @@ public class ConvertToConcatenatedStringIntention : SelfTargetingOffsetIndepende
private fun needsParenthesis(expression: KtExpression, isFinalEntry: Boolean): Boolean { private fun needsParenthesis(expression: KtExpression, isFinalEntry: Boolean): Boolean {
return when (expression) { return when (expression) {
is KtBinaryExpression -> true is KtBinaryExpression -> true
is KtIfExpression -> expression.getElse() !is KtBlockExpression && !isFinalEntry is KtIfExpression -> expression.`else` !is KtBlockExpression && !isFinalEntry
else -> false else -> false
} }
} }
@@ -31,7 +31,7 @@ import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.utils.addToStdlib.check import org.jetbrains.kotlin.utils.addToStdlib.check
public class ConvertToExpressionBodyIntention : SelfTargetingOffsetIndependentIntention<KtDeclarationWithBody>( public class ConvertToExpressionBodyIntention : SelfTargetingOffsetIndependentIntention<KtDeclarationWithBody>(
javaClass(), "Convert to expression body" KtDeclarationWithBody::class.java, "Convert to expression body"
) { ) {
override fun isApplicableTo(element: KtDeclarationWithBody): Boolean { override fun isApplicableTo(element: KtDeclarationWithBody): Boolean {
val value = calcValue(element) ?: return false val value = calcValue(element) ?: return false
@@ -53,7 +53,7 @@ public class ConvertToExpressionBodyIntention : SelfTargetingOffsetIndependentIn
public fun applyTo(declaration: KtDeclarationWithBody, canDeleteTypeRef: Boolean) { public fun applyTo(declaration: KtDeclarationWithBody, canDeleteTypeRef: Boolean) {
val deleteTypeHandler: (KtCallableDeclaration) -> Unit = { val deleteTypeHandler: (KtCallableDeclaration) -> Unit = {
it.deleteChildRange(it.getColon()!!, it.getTypeReference()!!) it.deleteChildRange(it.colon!!, it.typeReference!!)
} }
applyTo(declaration, deleteTypeHandler.check { canDeleteTypeRef }) applyTo(declaration, deleteTypeHandler.check { canDeleteTypeRef })
} }
@@ -68,7 +68,7 @@ public class ConvertToExpressionBodyIntention : SelfTargetingOffsetIndependentIn
} }
} }
val body = declaration.getBodyExpression()!! val body = declaration.bodyExpression!!
val commentSaver = CommentSaver(body) val commentSaver = CommentSaver(body)
@@ -86,13 +86,13 @@ public class ConvertToExpressionBodyIntention : SelfTargetingOffsetIndependentIn
private fun calcValue(declaration: KtDeclarationWithBody): KtExpression? { private fun calcValue(declaration: KtDeclarationWithBody): KtExpression? {
if (declaration is KtFunctionLiteral) return null if (declaration is KtFunctionLiteral) return null
val body = declaration.getBodyExpression() val body = declaration.bodyExpression
if (!declaration.hasBlockBody() || body !is KtBlockExpression) return null if (!declaration.hasBlockBody() || body !is KtBlockExpression) return null
val statement = body.getStatements().singleOrNull() ?: return null val statement = body.statements.singleOrNull() ?: return null
when(statement) { when(statement) {
is KtReturnExpression -> { is KtReturnExpression -> {
return statement.getReturnedExpression() return statement.returnedExpression
} }
//TODO: IMO this is not good code, there should be a way to detect that JetExpression does not have value //TODO: IMO this is not good code, there should be a way to detect that JetExpression does not have value
@@ -25,23 +25,23 @@ import org.jetbrains.kotlin.psi.createExpressionByPattern
import org.jetbrains.kotlin.psi.psiUtil.contentRange import org.jetbrains.kotlin.psi.psiUtil.contentRange
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
public class ConvertToForEachFunctionCallIntention : SelfTargetingIntention<KtForExpression>(javaClass(), "Replace with a 'forEach' function call") { public class ConvertToForEachFunctionCallIntention : SelfTargetingIntention<KtForExpression>(KtForExpression::class.java, "Replace with a 'forEach' function call") {
override fun isApplicableTo(element: KtForExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtForExpression, caretOffset: Int): Boolean {
val rParen = element.getRightParenthesis() ?: return false val rParen = element.rightParenthesis ?: return false
if (caretOffset > rParen.endOffset) return false // available only on the loop header, not in the body if (caretOffset > rParen.endOffset) return false // available only on the loop header, not in the body
return element.getLoopRange() != null && element.getLoopParameter() != null && element.getBody() != null return element.loopRange != null && element.loopParameter != null && element.body != null
} }
override fun applyTo(element: KtForExpression, editor: Editor) { override fun applyTo(element: KtForExpression, editor: Editor) {
val commentSaver = CommentSaver(element) val commentSaver = CommentSaver(element)
val body = element.getBody()!! val body = element.body!!
val loopParameter = element.getLoopParameter()!! val loopParameter = element.loopParameter!!
val functionBodyArgument: Any = if (body is KtBlockExpression) body.contentRange() else body val functionBodyArgument: Any = if (body is KtBlockExpression) body.contentRange() else body
val foreachExpression = KtPsiFactory(element).createExpressionByPattern( val foreachExpression = KtPsiFactory(element).createExpressionByPattern(
"$0.forEach{$1->$2}", element.getLoopRange()!!, loopParameter, functionBodyArgument) "$0.forEach{$1->$2}", element.loopRange!!, loopParameter, functionBodyArgument)
val result = element.replace(foreachExpression) val result = element.replace(foreachExpression)
commentSaver.restore(result) commentSaver.restore(result)
@@ -32,11 +32,11 @@ public class ConvertToStringTemplateInspection : IntentionBasedInspection<KtBina
{ ConvertToStringTemplateIntention().shouldSuggestToConvert(it) } { ConvertToStringTemplateIntention().shouldSuggestToConvert(it) }
) )
public class ConvertToStringTemplateIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>(javaClass(), "Convert concatenation to template") { public class ConvertToStringTemplateIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Convert concatenation to template") {
override fun isApplicableTo(element: KtBinaryExpression): Boolean { override fun isApplicableTo(element: KtBinaryExpression): Boolean {
if (!isApplicableToNoParentCheck(element)) return false if (!isApplicableToNoParentCheck(element)) return false
val parent = element.getParent() val parent = element.parent
if (parent is KtBinaryExpression && isApplicableToNoParentCheck(parent)) return false if (parent is KtBinaryExpression && isApplicableToNoParentCheck(parent)) return false
return true return true
@@ -58,25 +58,25 @@ public class ConvertToStringTemplateIntention : SelfTargetingOffsetIndependentIn
} }
private fun isApplicableToNoParentCheck(expression: KtBinaryExpression): Boolean { private fun isApplicableToNoParentCheck(expression: KtBinaryExpression): Boolean {
if (expression.getOperationToken() != KtTokens.PLUS) return false if (expression.operationToken != KtTokens.PLUS) return false
if (!KotlinBuiltIns.isString(expression.analyze().getType(expression))) return false if (!KotlinBuiltIns.isString(expression.analyze().getType(expression))) return false
val left = expression.getLeft() ?: return false val left = expression.left ?: return false
val right = expression.getRight() ?: return false val right = expression.right ?: return false
return !PsiUtilCore.hasErrorElementChild(left) && !PsiUtilCore.hasErrorElementChild(right) return !PsiUtilCore.hasErrorElementChild(left) && !PsiUtilCore.hasErrorElementChild(right)
} }
private fun buildReplacement(expression: KtBinaryExpression): KtStringTemplateExpression { private fun buildReplacement(expression: KtBinaryExpression): KtStringTemplateExpression {
val rightText = buildText(expression.getRight(), false) val rightText = buildText(expression.right, false)
return fold(expression.getLeft(), rightText, KtPsiFactory(expression)) return fold(expression.left, rightText, KtPsiFactory(expression))
} }
private fun fold(left: KtExpression?, right: String, factory: KtPsiFactory): KtStringTemplateExpression { private fun fold(left: KtExpression?, right: String, factory: KtPsiFactory): KtStringTemplateExpression {
val forceBraces = !right.isEmpty() && right.first() != '$' && right.first().isJavaIdentifierPart() val forceBraces = !right.isEmpty() && right.first() != '$' && right.first().isJavaIdentifierPart()
if (left is KtBinaryExpression && isApplicableToNoParentCheck(left)) { if (left is KtBinaryExpression && isApplicableToNoParentCheck(left)) {
val leftRight = buildText(left.getRight(), forceBraces) val leftRight = buildText(left.right, forceBraces)
return fold(left.getLeft(), leftRight + right, factory) return fold(left.left, leftRight + right, factory)
} }
else { else {
val leftText = buildText(left, forceBraces) val leftText = buildText(left, forceBraces)
@@ -87,7 +87,7 @@ public class ConvertToStringTemplateIntention : SelfTargetingOffsetIndependentIn
private fun buildText(expr: KtExpression?, forceBraces: Boolean): String { private fun buildText(expr: KtExpression?, forceBraces: Boolean): String {
if (expr == null) return "" if (expr == null) return ""
val expression = KtPsiUtil.safeDeparenthesize(expr) val expression = KtPsiUtil.safeDeparenthesize(expr)
val expressionText = expression.getText() val expressionText = expression.text
return when (expression) { return when (expression) {
is KtConstantExpression -> { is KtConstantExpression -> {
val bindingContext = expression.analyze() val bindingContext = expression.analyze()
@@ -97,7 +97,7 @@ public class ConvertToStringTemplateIntention : SelfTargetingOffsetIndependentIn
is KtStringTemplateExpression -> { is KtStringTemplateExpression -> {
val base = if (expressionText.startsWith("\"\"\"") && expressionText.endsWith("\"\"\"")) { val base = if (expressionText.startsWith("\"\"\"") && expressionText.endsWith("\"\"\"")) {
val unquoted = expressionText.substring(3, expressionText.length() - 3) val unquoted = expressionText.substring(3, expressionText.length - 3)
StringUtil.escapeStringCharacters(unquoted) StringUtil.escapeStringCharacters(unquoted)
} }
else { else {
@@ -114,8 +114,6 @@ public class ConvertToStringTemplateIntention : SelfTargetingOffsetIndependentIn
is KtNameReferenceExpression -> is KtNameReferenceExpression ->
"$" + (if (forceBraces) "{$expressionText}" else expressionText) "$" + (if (forceBraces) "{$expressionText}" else expressionText)
null -> ""
else -> "\${" + expressionText.replace("\n+".toRegex(), " ") + "}" else -> "\${" + expressionText.replace("\n+".toRegex(), " ") + "}"
} }
} }
@@ -45,14 +45,14 @@ import java.util.*
public class DeprecatedCallableAddReplaceWithInspection : IntentionBasedInspection<KtCallableDeclaration>(DeprecatedCallableAddReplaceWithIntention()) public class DeprecatedCallableAddReplaceWithInspection : IntentionBasedInspection<KtCallableDeclaration>(DeprecatedCallableAddReplaceWithIntention())
public class DeprecatedCallableAddReplaceWithIntention : SelfTargetingRangeIntention<KtCallableDeclaration>( public class DeprecatedCallableAddReplaceWithIntention : SelfTargetingRangeIntention<KtCallableDeclaration>(
javaClass(), "Add 'replaceWith' argument to specify replacement pattern", "Add 'replaceWith' argument to 'Deprecated' annotation" KtCallableDeclaration::class.java, "Add 'replaceWith' argument to specify replacement pattern", "Add 'replaceWith' argument to 'Deprecated' annotation"
) { ) {
private class ReplaceWith(val expression: String, vararg val imports: String) private class ReplaceWith(val expression: String, vararg val imports: String)
override fun applicabilityRange(element: KtCallableDeclaration): TextRange? { override fun applicabilityRange(element: KtCallableDeclaration): TextRange? {
val annotationEntry = element.deprecatedAnnotationWithNoReplaceWith() ?: return null val annotationEntry = element.deprecatedAnnotationWithNoReplaceWith() ?: return null
if (element.suggestReplaceWith() == null) return null if (element.suggestReplaceWith() == null) return null
return annotationEntry.getTextRange() return annotationEntry.textRange
} }
override fun applyTo(element: KtCallableDeclaration, editor: Editor) { override fun applyTo(element: KtCallableDeclaration, editor: Editor) {
@@ -69,9 +69,9 @@ public class DeprecatedCallableAddReplaceWithIntention : SelfTargetingRangeInten
// escape '$' if it's followed by a letter or '{' // escape '$' if it's followed by a letter or '{'
if (escapedText.contains('$')) { if (escapedText.contains('$')) {
escapedText = StringBuilder { escapedText = StringBuilder().apply {
var i = 0 var i = 0
val length = escapedText.length() val length = escapedText.length
while (i < length) { while (i < length) {
val c = escapedText[i++] val c = escapedText[i++]
if (c == '$' && i < length) { if (c == '$' && i < length) {
@@ -85,7 +85,7 @@ public class DeprecatedCallableAddReplaceWithIntention : SelfTargetingRangeInten
}.toString() }.toString()
} }
val argumentText = StringBuilder { val argumentText = StringBuilder().apply {
append("kotlin.ReplaceWith(\"") append("kotlin.ReplaceWith(\"")
append(escapedText) append(escapedText)
append("\"") append("\"")
@@ -95,30 +95,30 @@ public class DeprecatedCallableAddReplaceWithIntention : SelfTargetingRangeInten
}.toString() }.toString()
var argument = psiFactory.createArgument(psiFactory.createExpression(argumentText)) var argument = psiFactory.createArgument(psiFactory.createExpression(argumentText))
argument = annotationEntry.getValueArgumentList()!!.addArgument(argument) argument = annotationEntry.valueArgumentList!!.addArgument(argument)
argument = ShortenReferences.DEFAULT.process(argument) as KtValueArgument argument = ShortenReferences.DEFAULT.process(argument) as KtValueArgument
PsiDocumentManager.getInstance(argument.getProject()).doPostponedOperationsAndUnblockDocument(editor.getDocument()) PsiDocumentManager.getInstance(argument.project).doPostponedOperationsAndUnblockDocument(editor.document)
editor.moveCaret(argument.getTextOffset()) editor.moveCaret(argument.textOffset)
} }
private fun KtCallableDeclaration.deprecatedAnnotationWithNoReplaceWith(): KtAnnotationEntry? { private fun KtCallableDeclaration.deprecatedAnnotationWithNoReplaceWith(): KtAnnotationEntry? {
val bindingContext = this.analyze() val bindingContext = this.analyze()
// val deprecatedConstructor = KotlinBuiltIns.getInstance().getDeprecatedAnnotation().getUnsubstitutedPrimaryConstructor() // val deprecatedConstructor = KotlinBuiltIns.getInstance().getDeprecatedAnnotation().getUnsubstitutedPrimaryConstructor()
for (entry in getAnnotationEntries()) { for (entry in annotationEntries) {
entry.analyze() entry.analyze()
val resolvedCall = entry.getCalleeExpression().getResolvedCall(bindingContext) ?: continue val resolvedCall = entry.calleeExpression.getResolvedCall(bindingContext) ?: continue
if (!resolvedCall.isReallySuccess()) continue if (!resolvedCall.isReallySuccess()) continue
// if (resolvedCall.getResultingDescriptor() != deprecatedConstructor) continue // if (resolvedCall.getResultingDescriptor() != deprecatedConstructor) continue
//TODO //TODO
val descriptor = resolvedCall.getResultingDescriptor().getContainingDeclaration() val descriptor = resolvedCall.resultingDescriptor.containingDeclaration
val descriptorFqName = DescriptorUtils.getFqName(descriptor).toSafe() val descriptorFqName = DescriptorUtils.getFqName(descriptor).toSafe()
if (descriptorFqName != KotlinBuiltIns.FQ_NAMES.deprecated) continue if (descriptorFqName != KotlinBuiltIns.FQ_NAMES.deprecated) continue
val replaceWithArguments = resolvedCall.getValueArguments().entrySet() val replaceWithArguments = resolvedCall.valueArguments.entries
.single { it.key.getName().asString() == "replaceWith"/*TODO: kotlin.deprecated::replaceWith.name*/ }.value .single { it.key.name.asString() == "replaceWith"/*TODO: kotlin.deprecated::replaceWith.name*/ }.value
return if (replaceWithArguments.getArguments().isEmpty()) entry else null return if (replaceWithArguments.arguments.isEmpty()) entry else null
} }
return null return null
} }
@@ -128,8 +128,8 @@ public class DeprecatedCallableAddReplaceWithIntention : SelfTargetingRangeInten
is KtNamedFunction -> replacementExpressionFromBody() is KtNamedFunction -> replacementExpressionFromBody()
is KtProperty -> { is KtProperty -> {
if (isVar()) return null //TODO if (isVar) return null //TODO
getGetter()?.replacementExpressionFromBody() getter?.replacementExpressionFromBody()
} }
else -> null else -> null
@@ -146,7 +146,7 @@ public class DeprecatedCallableAddReplaceWithIntention : SelfTargetingRangeInten
} }
override fun visitBlockExpression(expression: KtBlockExpression) { override fun visitBlockExpression(expression: KtBlockExpression) {
if (expression.getStatements().size() > 1) { if (expression.statements.size > 1) {
isGood = false isGood = false
return return
} }
@@ -155,7 +155,7 @@ public class DeprecatedCallableAddReplaceWithIntention : SelfTargetingRangeInten
override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) { override fun visitSimpleNameExpression(expression: KtSimpleNameExpression) {
val target = expression.analyze()[BindingContext.REFERENCE_TARGET, expression] as? DeclarationDescriptorWithVisibility ?: return val target = expression.analyze()[BindingContext.REFERENCE_TARGET, expression] as? DeclarationDescriptorWithVisibility ?: return
if (Visibilities.isPrivate((target.getVisibility()))) { if (Visibilities.isPrivate((target.visibility))) {
isGood = false isGood = false
} }
} }
@@ -168,34 +168,34 @@ public class DeprecatedCallableAddReplaceWithIntention : SelfTargetingRangeInten
//TODO: check that no receivers that cannot be referenced from outside involved //TODO: check that no receivers that cannot be referenced from outside involved
val text = replacementExpression.getText() val text = replacementExpression.text
var expression = try { var expression = try {
KtPsiFactory(this).createExpression(text.replace('\n', ' ')) KtPsiFactory(this).createExpression(text.replace('\n', ' '))
} }
catch(e: Throwable) { // does not parse in one line catch(e: Throwable) { // does not parse in one line
return null return null
} }
expression = CodeStyleManager.getInstance(getProject()).reformat(expression, true) as KtExpression expression = CodeStyleManager.getInstance(project).reformat(expression, true) as KtExpression
return ReplaceWith(expression.getText(), *extractImports(replacementExpression).toTypedArray()) return ReplaceWith(expression.text, *extractImports(replacementExpression).toTypedArray())
} }
private fun KtDeclarationWithBody.replacementExpressionFromBody(): KtExpression? { private fun KtDeclarationWithBody.replacementExpressionFromBody(): KtExpression? {
val body = getBodyExpression() ?: return null val body = bodyExpression ?: return null
if (!hasBlockBody()) return body if (!hasBlockBody()) return body
val block = body as? KtBlockExpression ?: return null val block = body as? KtBlockExpression ?: return null
val statement = block.getStatements().singleOrNull() as? KtExpression ?: return null val statement = block.statements.singleOrNull() as? KtExpression ?: return null
val returnsUnit = (analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, this] as? FunctionDescriptor)?.getReturnType()?.isUnit() ?: return null val returnsUnit = (analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, this] as? FunctionDescriptor)?.returnType?.isUnit() ?: return null
return when (statement) { return when (statement) {
is KtReturnExpression -> statement.getReturnedExpression() is KtReturnExpression -> statement.returnedExpression
else -> if (returnsUnit) statement else null else -> if (returnsUnit) statement else null
} }
} }
private fun extractImports(expression: KtExpression): Collection<String> { private fun extractImports(expression: KtExpression): Collection<String> {
val file = expression.getContainingKtFile() val file = expression.getContainingKtFile()
val currentPackageFqName = file.getPackageFqName() val currentPackageFqName = file.packageFqName
val importHelper = ImportInsertHelper.getInstance(expression.getProject()) val importHelper = ImportInsertHelper.getInstance(expression.project)
val result = ArrayList<String>() val result = ArrayList<String>()
expression.accept(object : KtVisitorVoid(){ expression.accept(object : KtVisitorVoid(){
@@ -207,7 +207,7 @@ public class DeprecatedCallableAddReplaceWithIntention : SelfTargetingRangeInten
if (target.isExtension || expression.getReceiverExpression() == null) { if (target.isExtension || expression.getReceiverExpression() == null) {
val fqName = target.importableFqName ?: return val fqName = target.importableFqName ?: return
if (!importHelper.isImportedWithDefault(ImportPath(fqName, false), file) if (!importHelper.isImportedWithDefault(ImportPath(fqName, false), file)
&& (target.getContainingDeclaration() as? PackageFragmentDescriptor)?.fqName != currentPackageFqName) { && (target.containingDeclaration as? PackageFragmentDescriptor)?.fqName != currentPackageFqName) {
result.add(fqName.asString()) result.add(fqName.asString())
} }
} }
@@ -36,27 +36,27 @@ import java.util.*
public class IfNullToElvisInspection : IntentionBasedInspection<KtIfExpression>(IfNullToElvisIntention()) public class IfNullToElvisInspection : IntentionBasedInspection<KtIfExpression>(IfNullToElvisIntention())
public class IfNullToElvisIntention : SelfTargetingRangeIntention<KtIfExpression>(javaClass(), "Replace 'if' with elvis operator"){ public class IfNullToElvisIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' with elvis operator"){
override fun applicabilityRange(element: KtIfExpression): TextRange? { override fun applicabilityRange(element: KtIfExpression): TextRange? {
val data = calcData(element) ?: return null val data = calcData(element) ?: return null
val type = data.ifNullExpression.analyze().getType(data.ifNullExpression) ?: return null val type = data.ifNullExpression.analyze().getType(data.ifNullExpression) ?: return null
if (!type.isNothing()) return null if (!type.isNothing()) return null
val rParen = element.getRightParenthesis() ?: return null val rParen = element.rightParenthesis ?: return null
return TextRange(element.startOffset, rParen.endOffset) return TextRange(element.startOffset, rParen.endOffset)
} }
override fun applyTo(element: KtIfExpression, editor: Editor) { override fun applyTo(element: KtIfExpression, editor: Editor) {
val newElvis = applyTo(element) val newElvis = applyTo(element)
editor.getCaretModel().moveToOffset(newElvis.getRight()!!.getTextOffset()) editor.caretModel.moveToOffset(newElvis.right!!.textOffset)
} }
public fun applyTo(element: KtIfExpression): KtBinaryExpression { public fun applyTo(element: KtIfExpression): KtBinaryExpression {
val (initializer, declaration, ifNullExpr) = calcData(element)!! val (initializer, declaration, ifNullExpr) = calcData(element)!!
val factory = KtPsiFactory(element) val factory = KtPsiFactory(element)
val explicitTypeToAdd = if (declaration.isVar() && declaration.getTypeReference() == null) val explicitTypeToAdd = if (declaration.isVar && declaration.typeReference == null)
initializer.analyze().getType(initializer) initializer.analyze().getType(initializer)
else else
null null
@@ -73,7 +73,7 @@ public class IfNullToElvisIntention : SelfTargetingRangeIntention<KtIfExpression
val newElvis = initializer.replaced(elvis) val newElvis = initializer.replaced(elvis)
element.delete() element.delete()
if (explicitTypeToAdd != null && !explicitTypeToAdd.isError()) { if (explicitTypeToAdd != null && !explicitTypeToAdd.isError) {
declaration.setType(explicitTypeToAdd) declaration.setType(explicitTypeToAdd)
} }
@@ -87,22 +87,22 @@ public class IfNullToElvisIntention : SelfTargetingRangeIntention<KtIfExpression
) )
private fun calcData(ifExpression: KtIfExpression): Data? { private fun calcData(ifExpression: KtIfExpression): Data? {
if (ifExpression.getElse() != null) return null if (ifExpression.`else` != null) return null
val binaryExpression = ifExpression.getCondition() as? KtBinaryExpression ?: return null val binaryExpression = ifExpression.condition as? KtBinaryExpression ?: return null
if (binaryExpression.getOperationToken() != KtTokens.EQEQ) return null if (binaryExpression.operationToken != KtTokens.EQEQ) return null
val value = binaryExpression.expressionComparedToNull() as? KtNameReferenceExpression ?: return null val value = binaryExpression.expressionComparedToNull() as? KtNameReferenceExpression ?: return null
if (ifExpression.getParent() !is KtBlockExpression) return null if (ifExpression.parent !is KtBlockExpression) return null
val prevStatement = ifExpression.siblings(forward = false, withItself = false) val prevStatement = ifExpression.siblings(forward = false, withItself = false)
.firstIsInstanceOrNull<KtExpression>() ?: return null .firstIsInstanceOrNull<KtExpression>() ?: return null
if (prevStatement !is KtVariableDeclaration) return null if (prevStatement !is KtVariableDeclaration) return null
if (prevStatement.getNameAsName() != value.getReferencedNameAsName()) return null if (prevStatement.nameAsName != value.getReferencedNameAsName()) return null
val initializer = prevStatement.getInitializer() ?: return null val initializer = prevStatement.initializer ?: return null
val then = ifExpression.getThen() ?: return null val then = ifExpression.then ?: return null
if (then is KtBlockExpression) { if (then is KtBlockExpression) {
val statement = then.getStatements().singleOrNull() ?: return null val statement = then.statements.singleOrNull() ?: return null
return Data(initializer, prevStatement, statement) return Data(initializer, prevStatement, statement)
} }
else { else {
@@ -20,10 +20,10 @@ import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
public class InfixCallToOrdinaryIntention : SelfTargetingIntention<KtBinaryExpression>(javaClass(), "Replace infix call with ordinary call") { public class InfixCallToOrdinaryIntention : SelfTargetingIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Replace infix call with ordinary call") {
override fun isApplicableTo(element: KtBinaryExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtBinaryExpression, caretOffset: Int): Boolean {
if (element.getOperationToken() != KtTokens.IDENTIFIER || element.getLeft() == null || element.getRight() == null) return false if (element.operationToken != KtTokens.IDENTIFIER || element.left == null || element.right == null) return false
return element.getOperationReference().getTextRange().containsOffset(caretOffset) return element.operationReference.textRange.containsOffset(caretOffset)
} }
override fun applyTo(element: KtBinaryExpression, editor: Editor) { override fun applyTo(element: KtBinaryExpression, editor: Editor) {
@@ -32,12 +32,12 @@ public class InfixCallToOrdinaryIntention : SelfTargetingIntention<KtBinaryExpre
companion object { companion object {
public fun convert(element: KtBinaryExpression): KtExpression { public fun convert(element: KtBinaryExpression): KtExpression {
val argument = KtPsiUtil.safeDeparenthesize(element.getRight()!!) val argument = KtPsiUtil.safeDeparenthesize(element.right!!)
val pattern = "$0.$1" + when (argument) { val pattern = "$0.$1" + when (argument) {
is KtLambdaExpression -> " $2:'{}'" is KtLambdaExpression -> " $2:'{}'"
else -> "($2)" else -> "($2)"
} }
val replacement = KtPsiFactory(element).createExpressionByPattern(pattern, element.getLeft()!!, element.getOperationReference().getText(), argument) val replacement = KtPsiFactory(element).createExpressionByPattern(pattern, element.left!!, element.operationReference.text, argument)
return element.replace(replacement) as KtExpression return element.replace(replacement) as KtExpression
} }
} }
@@ -22,12 +22,12 @@ import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtSimpleNameStringTemplateEntry import org.jetbrains.kotlin.psi.KtSimpleNameStringTemplateEntry
public class InsertCurlyBracesToTemplateIntention : SelfTargetingOffsetIndependentIntention<KtSimpleNameStringTemplateEntry> ( public class InsertCurlyBracesToTemplateIntention : SelfTargetingOffsetIndependentIntention<KtSimpleNameStringTemplateEntry> (
javaClass(), "Insert curly braces around variable"), LowPriorityAction { KtSimpleNameStringTemplateEntry::class.java, "Insert curly braces around variable"), LowPriorityAction {
override fun isApplicableTo(element: KtSimpleNameStringTemplateEntry): Boolean = true override fun isApplicableTo(element: KtSimpleNameStringTemplateEntry): Boolean = true
override fun applyTo(element: KtSimpleNameStringTemplateEntry, editor: Editor) { override fun applyTo(element: KtSimpleNameStringTemplateEntry, editor: Editor) {
val expression = element.getExpression() ?: return val expression = element.expression ?: return
element.replace(KtPsiFactory(element).createBlockStringTemplateEntry(expression)) element.replace(KtPsiFactory(element).createBlockStringTemplateEntry(expression))
} }
} }
@@ -29,15 +29,15 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.ErrorUtils
public class InsertExplicitTypeArgumentsIntention : SelfTargetingRangeIntention<KtCallExpression>(javaClass(), "Add explicit type arguments"), LowPriorityAction { public class InsertExplicitTypeArgumentsIntention : SelfTargetingRangeIntention<KtCallExpression>(KtCallExpression::class.java, "Add explicit type arguments"), LowPriorityAction {
override fun applicabilityRange(element: KtCallExpression): TextRange? { override fun applicabilityRange(element: KtCallExpression): TextRange? {
return if (isApplicableTo(element, element.analyze())) element.getCalleeExpression()!!.getTextRange() else null return if (isApplicableTo(element, element.analyze())) element.calleeExpression!!.textRange else null
} }
override fun applyTo(element: KtCallExpression, editor: Editor) { override fun applyTo(element: KtCallExpression, editor: Editor) {
val argumentList = createTypeArguments(element, element.analyze())!! val argumentList = createTypeArguments(element, element.analyze())!!
val callee = element.getCalleeExpression()!! val callee = element.calleeExpression!!
val newArgumentList = element.addAfter(argumentList, callee) as KtTypeArgumentList val newArgumentList = element.addAfter(argumentList, callee) as KtTypeArgumentList
ShortenReferences.DEFAULT.process(newArgumentList) ShortenReferences.DEFAULT.process(newArgumentList)
@@ -45,19 +45,19 @@ public class InsertExplicitTypeArgumentsIntention : SelfTargetingRangeIntention<
companion object { companion object {
public fun isApplicableTo(element: KtCallExpression, bindingContext: BindingContext): Boolean { public fun isApplicableTo(element: KtCallExpression, bindingContext: BindingContext): Boolean {
if (!element.getTypeArguments().isEmpty()) return false if (!element.typeArguments.isEmpty()) return false
if (element.getCalleeExpression() == null) return false if (element.calleeExpression == null) return false
val resolvedCall = element.getResolvedCall(bindingContext) ?: return false val resolvedCall = element.getResolvedCall(bindingContext) ?: return false
val typeArgs = resolvedCall.getTypeArguments() val typeArgs = resolvedCall.typeArguments
return typeArgs.isNotEmpty() && typeArgs.values().none { ErrorUtils.containsErrorType(it) } return typeArgs.isNotEmpty() && typeArgs.values.none { ErrorUtils.containsErrorType(it) }
} }
public fun createTypeArguments(element: KtCallExpression, bindingContext: BindingContext): KtTypeArgumentList? { public fun createTypeArguments(element: KtCallExpression, bindingContext: BindingContext): KtTypeArgumentList? {
val resolvedCall = element.getResolvedCall(bindingContext) ?: return null val resolvedCall = element.getResolvedCall(bindingContext) ?: return null
val args = resolvedCall.getTypeArguments() val args = resolvedCall.typeArguments
val types = resolvedCall.getCandidateDescriptor().getTypeParameters() val types = resolvedCall.candidateDescriptor.typeParameters
val text = types.map { IdeDescriptorRenderers.SOURCE_CODE.renderType(args[it]!!) }.joinToString(", ", "<", ">") val text = types.map { IdeDescriptorRenderers.SOURCE_CODE.renderType(args[it]!!) }.joinToString(", ", "<", ">")
@@ -16,24 +16,17 @@
package org.jetbrains.kotlin.idea.intentions package org.jetbrains.kotlin.idea.intentions
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.Project
import com.intellij.psi.search.LocalSearchScope
import com.intellij.psi.search.searches.ReferencesSearch
import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor import org.jetbrains.kotlin.descriptors.impl.SyntheticFieldDescriptor
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.quickfix.KotlinQuickFixAction
import org.jetbrains.kotlin.idea.quickfix.KotlinSingleIntentionActionFactory
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
class IntroduceBackingPropertyIntention(): SelfTargetingIntention<KtProperty>(javaClass(), "Introduce backing property") { class IntroduceBackingPropertyIntention(): SelfTargetingIntention<KtProperty>(KtProperty::class.java, "Introduce backing property") {
override fun isApplicableTo(element: KtProperty, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtProperty, caretOffset: Int): Boolean {
if (!canIntroduceBackingProperty(element)) return false if (!canIntroduceBackingProperty(element)) return false
return element.nameIdentifier?.textRange?.containsOffset(caretOffset) == true return element.nameIdentifier?.textRange?.containsOffset(caretOffset) == true
@@ -97,7 +90,7 @@ class IntroduceBackingPropertyIntention(): SelfTargetingIntention<KtProperty>(ja
} }
private fun KtProperty.addAccessor(newAccessor: KtPropertyAccessor) { private fun KtProperty.addAccessor(newAccessor: KtPropertyAccessor) {
val semicolon = getNode().findChildByType(KtTokens.SEMICOLON) val semicolon = node.findChildByType(KtTokens.SEMICOLON)
addBefore(newAccessor, semicolon?.psi) addBefore(newAccessor, semicolon?.psi)
} }
@@ -136,24 +129,3 @@ class IntroduceBackingPropertyIntention(): SelfTargetingIntention<KtProperty>(ja
} }
} }
} }
class IntroduceBackingPropertyFix(prop: KtProperty): KotlinQuickFixAction<KtProperty>(prop) {
override fun getText(): String = "Introduce backing property"
override fun getFamilyName(): String = getText()
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
IntroduceBackingPropertyIntention.introduceBackingProperty(element)
}
companion object : KotlinSingleIntentionActionFactory() {
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
val resolveResult = diagnostic.psiElement.reference?.resolve()
if (resolveResult is KtProperty &&
IntroduceBackingPropertyIntention.canIntroduceBackingProperty(resolveResult)) {
return IntroduceBackingPropertyFix(resolveResult)
}
return null
}
}
}
@@ -29,14 +29,14 @@ import org.jetbrains.kotlin.types.typeUtil.isUnit
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
import org.jetbrains.kotlin.utils.addToStdlib.lastIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.lastIsInstanceOrNull
public class InvertIfConditionIntention : SelfTargetingIntention<KtIfExpression>(javaClass(), "Invert 'if' condition") { public class InvertIfConditionIntention : SelfTargetingIntention<KtIfExpression>(KtIfExpression::class.java, "Invert 'if' condition") {
override fun isApplicableTo(element: KtIfExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtIfExpression, caretOffset: Int): Boolean {
if (!element.getIfKeyword().getTextRange().containsOffset(caretOffset)) return false if (!element.ifKeyword.textRange.containsOffset(caretOffset)) return false
return element.getCondition() != null && element.getThen() != null return element.condition != null && element.then != null
} }
override fun applyTo(element: KtIfExpression, editor: Editor) { override fun applyTo(element: KtIfExpression, editor: Editor) {
val newCondition = element.getCondition()!!.negate() val newCondition = element.condition!!.negate()
val newIf = handleSpecialCases(element, newCondition) val newIf = handleSpecialCases(element, newCondition)
?: handleStandardCase(element, newCondition) ?: handleStandardCase(element, newCondition)
@@ -47,22 +47,22 @@ public class InvertIfConditionIntention : SelfTargetingIntention<KtIfExpression>
simplifyIntention.applyTo(newIfCondition) simplifyIntention.applyTo(newIfCondition)
} }
PsiDocumentManager.getInstance(newIf.getProject()).doPostponedOperationsAndUnblockDocument(editor.getDocument()) PsiDocumentManager.getInstance(newIf.project).doPostponedOperationsAndUnblockDocument(editor.document)
editor.moveCaret(newIf.getTextOffset()) editor.moveCaret(newIf.textOffset)
} }
private fun handleStandardCase(ifExpression: KtIfExpression, newCondition: KtExpression): KtIfExpression { private fun handleStandardCase(ifExpression: KtIfExpression, newCondition: KtExpression): KtIfExpression {
val psiFactory = KtPsiFactory(ifExpression) val psiFactory = KtPsiFactory(ifExpression)
val thenBranch = ifExpression.getThen()!! val thenBranch = ifExpression.then!!
val elseBranch = ifExpression.getElse() ?: psiFactory.createEmptyBody() val elseBranch = ifExpression.`else` ?: psiFactory.createEmptyBody()
val newThen = if (elseBranch is KtIfExpression) val newThen = if (elseBranch is KtIfExpression)
psiFactory.createSingleStatementBlock(elseBranch) psiFactory.createSingleStatementBlock(elseBranch)
else else
elseBranch elseBranch
val newElse = if (thenBranch is KtBlockExpression && thenBranch.getStatements().isEmpty()) val newElse = if (thenBranch is KtBlockExpression && thenBranch.statements.isEmpty())
null null
else else
thenBranch thenBranch
@@ -71,17 +71,17 @@ public class InvertIfConditionIntention : SelfTargetingIntention<KtIfExpression>
} }
private fun handleSpecialCases(ifExpression: KtIfExpression, newCondition: KtExpression): KtIfExpression? { private fun handleSpecialCases(ifExpression: KtIfExpression, newCondition: KtExpression): KtIfExpression? {
val elseBranch = ifExpression.getElse() val elseBranch = ifExpression.`else`
if (elseBranch != null) return null if (elseBranch != null) return null
val factory = KtPsiFactory(ifExpression) val factory = KtPsiFactory(ifExpression)
val thenBranch = ifExpression.getThen()!! val thenBranch = ifExpression.then!!
val lastThenStatement = thenBranch.lastBlockStatementOrThis() val lastThenStatement = thenBranch.lastBlockStatementOrThis()
if (lastThenStatement.isExitStatement()) { if (lastThenStatement.isExitStatement()) {
val block = ifExpression.getParent() as? KtBlockExpression val block = ifExpression.parent as? KtBlockExpression
if (block != null) { if (block != null) {
val rBrace = block.getRBrace() val rBrace = block.rBrace
val afterIfInBlock = ifExpression.siblings(withItself = false) val afterIfInBlock = ifExpression.siblings(withItself = false)
.takeWhile { it != rBrace } .takeWhile { it != rBrace }
.toList() .toList()
@@ -95,12 +95,12 @@ public class InvertIfConditionIntention : SelfTargetingIntention<KtIfExpression>
val first = afterIfInBlock.first() val first = afterIfInBlock.first()
val last = afterIfInBlock.last() val last = afterIfInBlock.last()
// build new then branch text from statements after if (we will add exit statement if necessary later) // build new then branch text from statements after if (we will add exit statement if necessary later)
var newIfBodyText = ifExpression.getContainingFile().getText().substring(first.startOffset, last.endOffset).trim() var newIfBodyText = ifExpression.containingFile.text.substring(first.startOffset, last.endOffset).trim()
// remove statements after if as they are moving under if // remove statements after if as they are moving under if
block.deleteChildRange(first, last) block.deleteChildRange(first, last)
if (lastThenStatement is KtReturnExpression && lastThenStatement.getReturnedExpression() == null) { if (lastThenStatement is KtReturnExpression && lastThenStatement.returnedExpression == null) {
lastThenStatement.delete() lastThenStatement.delete()
} }
val updatedIf = copyThenBranchAfter(ifExpression) val updatedIf = copyThenBranchAfter(ifExpression)
@@ -110,7 +110,7 @@ public class InvertIfConditionIntention : SelfTargetingIntention<KtIfExpression>
// don't insert the exit statement, if the new if statement placement has the same exit statement executed after it // don't insert the exit statement, if the new if statement placement has the same exit statement executed after it
val exitAfterNewIf = exitStatementExecutedAfter(updatedIf) val exitAfterNewIf = exitStatementExecutedAfter(updatedIf)
if (exitAfterNewIf == null || !exitAfterNewIf.matches(exitStatementAfterIf)) { if (exitAfterNewIf == null || !exitAfterNewIf.matches(exitStatementAfterIf)) {
newIfBodyText += "\n" + exitStatementAfterIf.getText() newIfBodyText += "\n" + exitStatementAfterIf.text
} }
} }
@@ -132,15 +132,15 @@ public class InvertIfConditionIntention : SelfTargetingIntention<KtIfExpression>
private fun copyThenBranchAfter(ifExpression: KtIfExpression): KtIfExpression { private fun copyThenBranchAfter(ifExpression: KtIfExpression): KtIfExpression {
val factory = KtPsiFactory(ifExpression) val factory = KtPsiFactory(ifExpression)
val thenBranch = ifExpression.getThen() ?: return ifExpression val thenBranch = ifExpression.then ?: return ifExpression
val parent = ifExpression.getParent() val parent = ifExpression.parent
if (parent !is KtBlockExpression) { if (parent !is KtBlockExpression) {
assert(parent is KtContainerNode) assert(parent is KtContainerNode)
val block = factory.createEmptyBody() val block = factory.createEmptyBody()
block.addAfter(ifExpression, block.getLBrace()) block.addAfter(ifExpression, block.lBrace)
val newBlock = ifExpression.replaced(block) val newBlock = ifExpression.replaced(block)
val newIf = newBlock.getStatements().single() as KtIfExpression val newIf = newBlock.statements.single() as KtIfExpression
return copyThenBranchAfter(newIf) return copyThenBranchAfter(newIf)
} }
@@ -159,9 +159,9 @@ public class InvertIfConditionIntention : SelfTargetingIntention<KtIfExpression>
} }
private fun exitStatementExecutedAfter(expression: KtExpression): KtExpression? { private fun exitStatementExecutedAfter(expression: KtExpression): KtExpression? {
val parent = expression.getParent() val parent = expression.parent
if (parent is KtBlockExpression) { if (parent is KtBlockExpression) {
val lastStatement = parent.getStatements().last() val lastStatement = parent.statements.last()
if (expression == lastStatement) { if (expression == lastStatement) {
return exitStatementExecutedAfter(parent) return exitStatementExecutedAfter(parent)
} }
@@ -175,25 +175,25 @@ public class InvertIfConditionIntention : SelfTargetingIntention<KtIfExpression>
when (parent) { when (parent) {
is KtNamedFunction -> { is KtNamedFunction -> {
if (parent.getBodyExpression() == expression) { if (parent.bodyExpression == expression) {
if (!parent.hasBlockBody()) return null if (!parent.hasBlockBody()) return null
val returnType = (parent.resolveToDescriptor() as FunctionDescriptor).getReturnType() val returnType = (parent.resolveToDescriptor() as FunctionDescriptor).returnType
if (returnType == null || !returnType.isUnit()) return null if (returnType == null || !returnType.isUnit()) return null
return KtPsiFactory(expression).createExpression("return") return KtPsiFactory(expression).createExpression("return")
} }
} }
is KtContainerNode -> { is KtContainerNode -> {
val pparent = parent.getParent() val pparent = parent.parent
when (pparent) { when (pparent) {
is KtLoopExpression -> { is KtLoopExpression -> {
if (expression == pparent.getBody()) { if (expression == pparent.body) {
return KtPsiFactory(expression).createExpression("continue") return KtPsiFactory(expression).createExpression("continue")
} }
} }
is KtIfExpression -> { is KtIfExpression -> {
if (expression == pparent.getThen() || expression == pparent.getElse()) { if (expression == pparent.then || expression == pparent.`else`) {
return exitStatementExecutedAfter(pparent) return exitStatementExecutedAfter(pparent)
} }
} }
@@ -32,13 +32,13 @@ import org.jetbrains.kotlin.psi.psiUtil.siblings
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
public class IterateExpressionIntention : SelfTargetingIntention<KtExpression>(javaClass(), "Iterate over collection"), HighPriorityAction { public class IterateExpressionIntention : SelfTargetingIntention<KtExpression>(KtExpression::class.java, "Iterate over collection"), HighPriorityAction {
override fun isApplicableTo(element: KtExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtExpression, caretOffset: Int): Boolean {
if (element.getParent() !is KtBlockExpression) return false if (element.parent !is KtBlockExpression) return false
val range = element.getTextRange() val range = element.textRange
if (caretOffset != range.getStartOffset() && caretOffset != range.getEndOffset()) return false if (caretOffset != range.startOffset && caretOffset != range.endOffset) return false
val data = data(element) ?: return false val data = data(element) ?: return false
setText("Iterate over '${IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(data.collectionType)}'") text = "Iterate over '${IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(data.collectionType)}'"
return true return true
} }
@@ -65,12 +65,12 @@ public class IterateExpressionIntention : SelfTargetingIntention<KtExpression>(j
var forExpression = KtPsiFactory(element).createExpressionByPattern("for($0 in $1) {\nx\n}", names.first(), element) as KtForExpression var forExpression = KtPsiFactory(element).createExpressionByPattern("for($0 in $1) {\nx\n}", names.first(), element) as KtForExpression
forExpression = element.replaced(forExpression) forExpression = element.replaced(forExpression)
PsiDocumentManager.getInstance(forExpression.getProject()).doPostponedOperationsAndUnblockDocument(editor.getDocument()) PsiDocumentManager.getInstance(forExpression.project).doPostponedOperationsAndUnblockDocument(editor.document)
val bodyPlaceholder = (forExpression.getBody() as KtBlockExpression).getStatements().single() val bodyPlaceholder = (forExpression.body as KtBlockExpression).statements.single()
val templateBuilder = TemplateBuilderImpl(forExpression) val templateBuilder = TemplateBuilderImpl(forExpression)
templateBuilder.replaceElement(forExpression.getLoopParameter()!!, ChooseStringExpression(names)) templateBuilder.replaceElement(forExpression.loopParameter!!, ChooseStringExpression(names))
templateBuilder.replaceElement(bodyPlaceholder, ConstantNode(""), false) templateBuilder.replaceElement(bodyPlaceholder, ConstantNode(""), false)
templateBuilder.setEndVariableAfter(bodyPlaceholder) templateBuilder.setEndVariableAfter(bodyPlaceholder)
@@ -30,7 +30,7 @@ import org.jetbrains.kotlin.psi.psiUtil.*
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
public class MoveAssignmentToInitializerIntention : public class MoveAssignmentToInitializerIntention :
SelfTargetingIntention<KtBinaryExpression>(javaClass(), "Move assignment to initializer") { SelfTargetingIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Move assignment to initializer") {
override fun isApplicableTo(element: KtBinaryExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtBinaryExpression, caretOffset: Int): Boolean {
if (element.operationToken != KtTokens.EQ) { if (element.operationToken != KtTokens.EQ) {
@@ -19,15 +19,14 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.codeInsight.intention.LowPriorityAction import com.intellij.codeInsight.intention.LowPriorityAction
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
import org.jetbrains.kotlin.idea.core.moveInsideParentheses import org.jetbrains.kotlin.idea.core.moveInsideParentheses
import org.jetbrains.kotlin.psi.KtLambdaArgument import org.jetbrains.kotlin.psi.KtLambdaArgument
import org.jetbrains.kotlin.psi.psiUtil.containsInside import org.jetbrains.kotlin.psi.psiUtil.containsInside
public class MoveLambdaInsideParenthesesIntention : SelfTargetingIntention<KtLambdaArgument>(javaClass(), "Move lambda argument into parentheses"), LowPriorityAction { public class MoveLambdaInsideParenthesesIntention : SelfTargetingIntention<KtLambdaArgument>(KtLambdaArgument::class.java, "Move lambda argument into parentheses"), LowPriorityAction {
override fun isApplicableTo(element: KtLambdaArgument, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtLambdaArgument, caretOffset: Int): Boolean {
val body = element.getLambdaExpression().getBodyExpression() ?: return true val body = element.getLambdaExpression().bodyExpression ?: return true
return !body.getTextRange().containsInside(caretOffset) return !body.textRange.containsInside(caretOffset)
} }
override fun applyTo(element: KtLambdaArgument, editor: Editor) { override fun applyTo(element: KtLambdaArgument, editor: Editor) {
@@ -29,14 +29,14 @@ import org.jetbrains.kotlin.psi.unpackFunctionLiteral
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
public class MoveLambdaOutsideParenthesesIntention : SelfTargetingIntention<KtCallExpression>(javaClass(), "Move lambda argument out of parentheses") { public class MoveLambdaOutsideParenthesesIntention : SelfTargetingIntention<KtCallExpression>(KtCallExpression::class.java, "Move lambda argument out of parentheses") {
override fun isApplicableTo(element: KtCallExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtCallExpression, caretOffset: Int): Boolean {
if (element.getLambdaArguments().isNotEmpty()) return false if (element.lambdaArguments.isNotEmpty()) return false
val argument = element.getValueArguments().lastOrNull() ?: return false val argument = element.valueArguments.lastOrNull() ?: return false
val expression = argument.getArgumentExpression() ?: return false val expression = argument.getArgumentExpression() ?: return false
val functionLiteral = expression.unpackFunctionLiteral() ?: return false val functionLiteral = expression.unpackFunctionLiteral() ?: return false
val callee = element.getCalleeExpression() val callee = element.calleeExpression
if (callee is KtNameReferenceExpression) { if (callee is KtNameReferenceExpression) {
val bindingContext = element.analyze(BodyResolveMode.PARTIAL) val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
val targets = bindingContext[BindingContext.REFERENCE_TARGET, callee]?.let { listOf(it) } val targets = bindingContext[BindingContext.REFERENCE_TARGET, callee]?.let { listOf(it) }
@@ -45,15 +45,15 @@ public class MoveLambdaOutsideParenthesesIntention : SelfTargetingIntention<KtCa
val candidates = targets.filterIsInstance<FunctionDescriptor>() val candidates = targets.filterIsInstance<FunctionDescriptor>()
// if there are functions among candidates but none of them have last function parameter then not show the intention // if there are functions among candidates but none of them have last function parameter then not show the intention
if (candidates.isNotEmpty() && candidates.none { if (candidates.isNotEmpty() && candidates.none {
val lastParameter = it.getValueParameters().lastOrNull() val lastParameter = it.valueParameters.lastOrNull()
lastParameter != null && KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(lastParameter.getType()) lastParameter != null && KotlinBuiltIns.isExactFunctionOrExtensionFunctionType(lastParameter.type)
}) { }) {
return false return false
} }
} }
if (caretOffset < argument.asElement().startOffset) return false if (caretOffset < argument.asElement().startOffset) return false
val bodyRange = functionLiteral.getBodyExpression()?.getTextRange() ?: return true val bodyRange = functionLiteral.bodyExpression?.textRange ?: return true
return !bodyRange.containsInside(caretOffset) return !bodyRange.containsInside(caretOffset)
} }
@@ -27,26 +27,26 @@ import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
public class ReconstructTypeInCastOrIsIntention : SelfTargetingOffsetIndependentIntention<KtTypeReference>(javaClass(), "Replace by reconstructed type"), LowPriorityAction { public class ReconstructTypeInCastOrIsIntention : SelfTargetingOffsetIndependentIntention<KtTypeReference>(KtTypeReference::class.java, "Replace by reconstructed type"), LowPriorityAction {
override fun isApplicableTo(element: KtTypeReference): Boolean { override fun isApplicableTo(element: KtTypeReference): Boolean {
// Only user types (like Foo) are interesting // Only user types (like Foo) are interesting
val typeElement = element.typeElement as? KtUserType ?: return false val typeElement = element.typeElement as? KtUserType ?: return false
// If there are generic arguments already, there's nothing to reconstruct // If there are generic arguments already, there's nothing to reconstruct
if (typeElement.getTypeArguments().isNotEmpty()) return false if (typeElement.typeArguments.isNotEmpty()) return false
// We must be on the RHS of as/as?/is/!is or inside an is/!is-condition in when() // We must be on the RHS of as/as?/is/!is or inside an is/!is-condition in when()
val expression = element.getParentOfType<KtExpression>(true) val expression = element.getParentOfType<KtExpression>(true)
if (expression !is KtBinaryExpressionWithTypeRHS && element.getParentOfType<KtWhenConditionIsPattern>(true) == null) return false if (expression !is KtBinaryExpressionWithTypeRHS && element.getParentOfType<KtWhenConditionIsPattern>(true) == null) return false
val type = getReconstructedType(element) val type = getReconstructedType(element)
if (type == null || type.isError()) return false if (type == null || type.isError) return false
// No type parameters expected => nothing to reconstruct // No type parameters expected => nothing to reconstruct
if (type.getConstructor().getParameters().isEmpty()) return false if (type.constructor.parameters.isEmpty()) return false
val typePresentation = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type) val typePresentation = IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.renderType(type)
setText("Replace by '$typePresentation'") text = "Replace by '$typePresentation'"
return true return true
} }
@@ -29,16 +29,16 @@ import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
public class RemoveArgumentNameIntention public class RemoveArgumentNameIntention
: SelfTargetingRangeIntention<KtValueArgument>(javaClass(), "Remove argument name") { : SelfTargetingRangeIntention<KtValueArgument>(KtValueArgument::class.java, "Remove argument name") {
override fun applicabilityRange(element: KtValueArgument): TextRange? { override fun applicabilityRange(element: KtValueArgument): TextRange? {
if (!element.isNamed()) return null if (!element.isNamed()) return null
val argumentList = element.getParent() as? KtValueArgumentList ?: return null val argumentList = element.parent as? KtValueArgumentList ?: return null
val arguments = argumentList.getArguments() val arguments = argumentList.arguments
if (arguments.takeWhile { it != element }.any { it.isNamed() }) return null if (arguments.takeWhile { it != element }.any { it.isNamed() }) return null
val callExpr = argumentList.getParent() as? KtExpression ?: return null val callExpr = argumentList.parent as? KtExpression ?: return null
val resolvedCall = callExpr.getResolvedCall(callExpr.analyze(BodyResolveMode.PARTIAL)) ?: return null val resolvedCall = callExpr.getResolvedCall(callExpr.analyze(BodyResolveMode.PARTIAL)) ?: return null
val argumentMatch = resolvedCall.getArgumentMapping(element) as? ArgumentMatch ?: return null val argumentMatch = resolvedCall.getArgumentMapping(element) as? ArgumentMatch ?: return null
if (argumentMatch.valueParameter.index != arguments.indexOf(element)) return null if (argumentMatch.valueParameter.index != arguments.indexOf(element)) return null
@@ -20,51 +20,50 @@ import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiComment import com.intellij.psi.PsiComment
import com.intellij.psi.PsiWhiteSpace import com.intellij.psi.PsiWhiteSpace
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getParentOfType
public class RemoveBracesIntention : SelfTargetingIntention<KtBlockExpression>(javaClass(), "Remove braces") { public class RemoveBracesIntention : SelfTargetingIntention<KtBlockExpression>(KtBlockExpression::class.java, "Remove braces") {
override fun isApplicableTo(element: KtBlockExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtBlockExpression, caretOffset: Int): Boolean {
if (element.getStatements().size() != 1) return false if (element.statements.size != 1) return false
val containerNode = element.getParent() as? KtContainerNode ?: return false val containerNode = element.parent as? KtContainerNode ?: return false
val lBrace = element.getLBrace() ?: return false val lBrace = element.lBrace ?: return false
val rBrace = element.getRBrace() ?: return false val rBrace = element.rBrace ?: return false
if (!lBrace.getTextRange().containsOffset(caretOffset) && !rBrace.getTextRange().containsOffset(caretOffset)) return false if (!lBrace.textRange.containsOffset(caretOffset) && !rBrace.textRange.containsOffset(caretOffset)) return false
val description = containerNode.description() ?: return false val description = containerNode.description() ?: return false
setText("Remove braces from '$description' statement") text = "Remove braces from '$description' statement"
return true return true
} }
override fun applyTo(element: KtBlockExpression, editor: Editor) { override fun applyTo(element: KtBlockExpression, editor: Editor) {
val statement = element.getStatements().single() val statement = element.statements.single()
val containerNode = element.getParent() as KtContainerNode val containerNode = element.parent as KtContainerNode
val construct = containerNode.getParent() as KtExpression val construct = containerNode.parent as KtExpression
handleComments(construct, element) handleComments(construct, element)
val newElement = element.replace(statement.copy()) val newElement = element.replace(statement.copy())
if (construct is KtDoWhileExpression) { if (construct is KtDoWhileExpression) {
newElement.getParent()!!.addAfter(KtPsiFactory(element).createNewLine(), newElement) newElement.parent!!.addAfter(KtPsiFactory(element).createNewLine(), newElement)
} }
} }
private fun handleComments(construct: KtExpression, block: KtBlockExpression) { private fun handleComments(construct: KtExpression, block: KtBlockExpression) {
var sibling = block.getFirstChild()?.getNextSibling() var sibling = block.firstChild?.nextSibling
while (sibling != null) { while (sibling != null) {
if (sibling is PsiComment) { if (sibling is PsiComment) {
//cleans up extra whitespace //cleans up extra whitespace
val psiFactory = KtPsiFactory(construct) val psiFactory = KtPsiFactory(construct)
if (construct.getPrevSibling() is PsiWhiteSpace) { if (construct.prevSibling is PsiWhiteSpace) {
construct.getPrevSibling()!!.replace(psiFactory.createNewLine()) construct.prevSibling!!.replace(psiFactory.createNewLine())
} }
val commentElement = construct.getParent()!!.addBefore(sibling, construct.getPrevSibling()) val commentElement = construct.parent!!.addBefore(sibling, construct.prevSibling)
construct.getParent()!!.addBefore(psiFactory.createNewLine(), commentElement) construct.parent!!.addBefore(psiFactory.createNewLine(), commentElement)
} }
sibling = sibling.getNextSibling() sibling = sibling.nextSibling
} }
} }
} }
@@ -27,9 +27,9 @@ import org.jetbrains.kotlin.psi.psiUtil.canPlaceAfterSimpleNameEntry
public class RemoveCurlyBracesFromTemplateInspection : IntentionBasedInspection<KtBlockStringTemplateEntry>(RemoveCurlyBracesFromTemplateIntention()) public class RemoveCurlyBracesFromTemplateInspection : IntentionBasedInspection<KtBlockStringTemplateEntry>(RemoveCurlyBracesFromTemplateIntention())
public class RemoveCurlyBracesFromTemplateIntention : SelfTargetingOffsetIndependentIntention<KtBlockStringTemplateEntry>(javaClass(), "Remove curly braces") { public class RemoveCurlyBracesFromTemplateIntention : SelfTargetingOffsetIndependentIntention<KtBlockStringTemplateEntry>(KtBlockStringTemplateEntry::class.java, "Remove curly braces") {
override fun isApplicableTo(element: KtBlockStringTemplateEntry): Boolean { override fun isApplicableTo(element: KtBlockStringTemplateEntry): Boolean {
if (element.getExpression() !is KtNameReferenceExpression) return false if (element.expression !is KtNameReferenceExpression) return false
return canPlaceAfterSimpleNameEntry(element.nextSibling) return canPlaceAfterSimpleNameEntry(element.nextSibling)
} }
@@ -38,7 +38,7 @@ public class RemoveCurlyBracesFromTemplateIntention : SelfTargetingOffsetIndepen
} }
public fun applyTo(element: KtBlockStringTemplateEntry): KtStringTemplateEntryWithExpression { public fun applyTo(element: KtBlockStringTemplateEntry): KtStringTemplateEntryWithExpression {
val name = (element.getExpression() as KtNameReferenceExpression).getReferencedName() val name = (element.expression as KtNameReferenceExpression).getReferencedName()
val newEntry = KtPsiFactory(element).createSimpleNameStringTemplateEntry(name) val newEntry = KtPsiFactory(element).createSimpleNameStringTemplateEntry(name)
return element.replaced(newEntry) return element.replaced(newEntry)
} }
@@ -19,20 +19,19 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.psi.KtLambdaExpression import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
public class RemoveExplicitLambdaParameterTypesIntention : SelfTargetingIntention<KtLambdaExpression>(javaClass(), "Remove explicit lambda parameter types (may break code)") { public class RemoveExplicitLambdaParameterTypesIntention : SelfTargetingIntention<KtLambdaExpression>(KtLambdaExpression::class.java, "Remove explicit lambda parameter types (may break code)") {
override fun isApplicableTo(element: KtLambdaExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtLambdaExpression, caretOffset: Int): Boolean {
if (element.getValueParameters().none { it.getTypeReference() != null }) return false if (element.valueParameters.none { it.typeReference != null }) return false
val arrow = element.getFunctionLiteral().getArrow() ?: return false val arrow = element.functionLiteral.arrow ?: return false
return caretOffset <= arrow.endOffset return caretOffset <= arrow.endOffset
} }
override fun applyTo(element: KtLambdaExpression, editor: Editor) { override fun applyTo(element: KtLambdaExpression, editor: Editor) {
val oldParameterList = element.getFunctionLiteral().getValueParameterList()!! val oldParameterList = element.functionLiteral.valueParameterList!!
val parameterString = oldParameterList.getParameters().map { it.getName() }.joinToString(", ") val parameterString = oldParameterList.parameters.map { it.name }.joinToString(", ")
val newParameterList = KtPsiFactory(element).createFunctionLiteralParameterList(parameterString) val newParameterList = KtPsiFactory(element).createFunctionLiteralParameterList(parameterString)
oldParameterList.replace(newParameterList) oldParameterList.replace(newParameterList)
} }
@@ -44,7 +44,7 @@ public class RemoveExplicitSuperQualifierInspection : IntentionBasedInspection<K
get() = ProblemHighlightType.LIKE_UNUSED_SYMBOL get() = ProblemHighlightType.LIKE_UNUSED_SYMBOL
} }
public class RemoveExplicitSuperQualifierIntention : SelfTargetingRangeIntention<KtSuperExpression>(javaClass(), "Remove explicit supertype qualification") { public class RemoveExplicitSuperQualifierIntention : SelfTargetingRangeIntention<KtSuperExpression>(KtSuperExpression::class.java, "Remove explicit supertype qualification") {
override fun applicabilityRange(element: KtSuperExpression): TextRange? { override fun applicabilityRange(element: KtSuperExpression): TextRange? {
if (element.superTypeQualifier == null) return null if (element.superTypeQualifier == null) return null
@@ -39,27 +39,27 @@ public class RemoveExplicitTypeArgumentsInspection : IntentionBasedInspection<Kt
get() = ProblemHighlightType.LIKE_UNUSED_SYMBOL get() = ProblemHighlightType.LIKE_UNUSED_SYMBOL
} }
public class RemoveExplicitTypeArgumentsIntention : SelfTargetingOffsetIndependentIntention<KtTypeArgumentList>(javaClass(), "Remove explicit type arguments") { public class RemoveExplicitTypeArgumentsIntention : SelfTargetingOffsetIndependentIntention<KtTypeArgumentList>(KtTypeArgumentList::class.java, "Remove explicit type arguments") {
companion object { companion object {
public fun isApplicableTo(element: KtTypeArgumentList, approximateFlexible: Boolean): Boolean { public fun isApplicableTo(element: KtTypeArgumentList, approximateFlexible: Boolean): Boolean {
val callExpression = element.getParent() as? KtCallExpression ?: return false val callExpression = element.parent as? KtCallExpression ?: return false
if (callExpression.getTypeArguments().isEmpty()) return false if (callExpression.typeArguments.isEmpty()) return false
val resolutionFacade = callExpression.getResolutionFacade() val resolutionFacade = callExpression.getResolutionFacade()
val context = resolutionFacade.analyze(callExpression, BodyResolveMode.PARTIAL) val context = resolutionFacade.analyze(callExpression, BodyResolveMode.PARTIAL)
val calleeExpression = callExpression.getCalleeExpression() ?: return false val calleeExpression = callExpression.calleeExpression ?: return false
val scope = calleeExpression.getResolutionScope(context, resolutionFacade) val scope = calleeExpression.getResolutionScope(context, resolutionFacade)
val originalCall = callExpression.getResolvedCall(context) ?: return false val originalCall = callExpression.getResolvedCall(context) ?: return false
val untypedCall = CallWithoutTypeArgs(originalCall.getCall()) val untypedCall = CallWithoutTypeArgs(originalCall.call)
// todo Check with expected type for other expressions // todo Check with expected type for other expressions
// If always use expected type from trace there is a problem with nested calls: // If always use expected type from trace there is a problem with nested calls:
// the expression type for them can depend on their explicit type arguments (via outer call), // the expression type for them can depend on their explicit type arguments (via outer call),
// therefore we should resolve outer call with erased type arguments for inner call // therefore we should resolve outer call with erased type arguments for inner call
val parent = callExpression.getParent() val parent = callExpression.parent
val expectedTypeIsExplicitInCode = when (parent) { val expectedTypeIsExplicitInCode = when (parent) {
is KtProperty -> parent.getInitializer() == callExpression && parent.getTypeReference() != null is KtProperty -> parent.initializer == callExpression && parent.typeReference != null
is KtDeclarationWithBody -> parent.getBodyExpression() == callExpression is KtDeclarationWithBody -> parent.bodyExpression == callExpression
is KtReturnExpression -> true is KtReturnExpression -> true
else -> false else -> false
} }
@@ -73,12 +73,12 @@ public class RemoveExplicitTypeArgumentsIntention : SelfTargetingOffsetIndepende
val callResolver = resolutionFacade.frontendService<CallResolver>() val callResolver = resolutionFacade.frontendService<CallResolver>()
val resolutionResults = callResolver.resolveFunctionCall( val resolutionResults = callResolver.resolveFunctionCall(
BindingTraceContext(), scope, untypedCall, expectedType, dataFlow, false) BindingTraceContext(), scope, untypedCall, expectedType, dataFlow, false)
if (!resolutionResults.isSingleResult()) { if (!resolutionResults.isSingleResult) {
return false return false
} }
val args = originalCall.getTypeArguments() val args = originalCall.typeArguments
val newArgs = resolutionResults.getResultingCall().getTypeArguments() val newArgs = resolutionResults.resultingCall.typeArguments
fun equalTypes(type1: KotlinType, type2: KotlinType): Boolean { fun equalTypes(type1: KotlinType, type2: KotlinType): Boolean {
return if (approximateFlexible) { return if (approximateFlexible) {
@@ -89,7 +89,7 @@ public class RemoveExplicitTypeArgumentsIntention : SelfTargetingOffsetIndepende
} }
} }
return args.size() == newArgs.size() && args.values().zip(newArgs.values()).all { pair -> equalTypes(pair.first, pair.second) } return args.size == newArgs.size && args.values.zip(newArgs.values).all { pair -> equalTypes(pair.first, pair.second) }
} }
} }
@@ -19,18 +19,18 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
public class RemoveExplicitTypeIntention : SelfTargetingIntention<KtCallableDeclaration>(javaClass(), "Remove explicit type specification") { public class RemoveExplicitTypeIntention : SelfTargetingIntention<KtCallableDeclaration>(KtCallableDeclaration::class.java, "Remove explicit type specification") {
override fun isApplicableTo(element: KtCallableDeclaration, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtCallableDeclaration, caretOffset: Int): Boolean {
if (element.getContainingFile() is KtCodeFragment) return false if (element.containingFile is KtCodeFragment) return false
if (element.getTypeReference() == null) return false if (element.typeReference == null) return false
val initializer = (element as? KtWithExpressionInitializer)?.getInitializer() val initializer = (element as? KtWithExpressionInitializer)?.initializer
if (initializer != null && initializer.getTextRange().containsOffset(caretOffset)) return false if (initializer != null && initializer.textRange.containsOffset(caretOffset)) return false
return when (element) { return when (element) {
is KtProperty -> initializer != null is KtProperty -> initializer != null
is KtNamedFunction -> !element.hasBlockBody() && initializer != null is KtNamedFunction -> !element.hasBlockBody() && initializer != null
is KtParameter -> element.isLoopParameter() is KtParameter -> element.isLoopParameter
else -> false else -> false
} }
} }
@@ -34,20 +34,20 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
public class RemoveForLoopIndicesInspection : IntentionBasedInspection<KtForExpression>( public class RemoveForLoopIndicesInspection : IntentionBasedInspection<KtForExpression>(
listOf(IntentionBasedInspection.IntentionData(RemoveForLoopIndicesIntention())), listOf(IntentionBasedInspection.IntentionData(RemoveForLoopIndicesIntention())),
"Index is not used in the loop body", "Index is not used in the loop body",
javaClass() KtForExpression::class.java
) { ) {
override val problemHighlightType: ProblemHighlightType override val problemHighlightType: ProblemHighlightType
get() = ProblemHighlightType.LIKE_UNUSED_SYMBOL get() = ProblemHighlightType.LIKE_UNUSED_SYMBOL
} }
public class RemoveForLoopIndicesIntention : SelfTargetingRangeIntention<KtForExpression>(javaClass(), "Remove indices in 'for' loop") { public class RemoveForLoopIndicesIntention : SelfTargetingRangeIntention<KtForExpression>(KtForExpression::class.java, "Remove indices in 'for' loop") {
private val WITH_INDEX_NAME = "withIndex" private val WITH_INDEX_NAME = "withIndex"
private val WITH_INDEX_FQ_NAMES = listOf("collections", "sequences", "text", "ranges").map { "kotlin.$it.$WITH_INDEX_NAME" }.toSet() private val WITH_INDEX_FQ_NAMES = listOf("collections", "sequences", "text", "ranges").map { "kotlin.$it.$WITH_INDEX_NAME" }.toSet()
override fun applicabilityRange(element: KtForExpression): TextRange? { override fun applicabilityRange(element: KtForExpression): TextRange? {
val loopRange = element.loopRange as? KtDotQualifiedExpression ?: return null val loopRange = element.loopRange as? KtDotQualifiedExpression ?: return null
val multiParameter = element.destructuringParameter ?: return null val multiParameter = element.destructuringParameter ?: return null
if (multiParameter.entries.size() != 2) return null if (multiParameter.entries.size != 2) return null
val bindingContext = element.analyze(BodyResolveMode.PARTIAL) val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
@@ -20,13 +20,12 @@ import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.psi.KtParenthesizedExpression import org.jetbrains.kotlin.psi.KtParenthesizedExpression
import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.psiUtil.containsInside
public class RemoveUnnecessaryParenthesesIntention : SelfTargetingRangeIntention<KtParenthesizedExpression>(KtParenthesizedExpression::class.java, "Remove unnecessary parentheses") { public class RemoveUnnecessaryParenthesesIntention : SelfTargetingRangeIntention<KtParenthesizedExpression>(KtParenthesizedExpression::class.java, "Remove unnecessary parentheses") {
override fun applicabilityRange(element: KtParenthesizedExpression): TextRange? { override fun applicabilityRange(element: KtParenthesizedExpression): TextRange? {
element.getExpression() ?: return null element.expression ?: return null
if (!KtPsiUtil.areParenthesesUseless(element)) return null if (!KtPsiUtil.areParenthesesUseless(element)) return null
return element.getTextRange() return element.textRange
} }
override fun applyTo(element: KtParenthesizedExpression, editor: Editor) { override fun applyTo(element: KtParenthesizedExpression, editor: Editor) {
@@ -34,6 +33,6 @@ public class RemoveUnnecessaryParenthesesIntention : SelfTargetingRangeIntention
} }
fun applyTo(element: KtParenthesizedExpression) { fun applyTo(element: KtParenthesizedExpression) {
element.replace(element.getExpression()!!) element.replace(element.expression!!)
} }
} }
@@ -39,19 +39,19 @@ public class ReplaceExplicitFunctionLiteralParamWithItIntention() : PsiElementBa
override fun getFamilyName() = "Replace explicit lambda parameter with 'it'" override fun getFamilyName() = "Replace explicit lambda parameter with 'it'"
override fun isAvailable(project: Project, editor: Editor, element: PsiElement): Boolean { override fun isAvailable(project: Project, editor: Editor, element: PsiElement): Boolean {
val functionLiteral = targetFunctionLiteral(element, editor.getCaretModel().getOffset()) ?: return false val functionLiteral = targetFunctionLiteral(element, editor.caretModel.offset) ?: return false
val parameter = functionLiteral.getValueParameters().singleOrNull() ?: return false val parameter = functionLiteral.valueParameters.singleOrNull() ?: return false
if (parameter.getTypeReference() != null) return false if (parameter.typeReference != null) return false
setText("Replace explicit parameter '${parameter.getName()}' with 'it'") text = "Replace explicit parameter '${parameter.name}' with 'it'"
return true return true
} }
override fun invoke(project: Project, editor: Editor, element: PsiElement) { override fun invoke(project: Project, editor: Editor, element: PsiElement) {
val caretOffset = editor.getCaretModel().getOffset() val caretOffset = editor.caretModel.offset
val functionLiteral = targetFunctionLiteral(element, editor.getCaretModel().getOffset())!! val functionLiteral = targetFunctionLiteral(element, editor.caretModel.offset)!!
val cursorInParameterList = functionLiteral.getValueParameterList()!!.getTextRange().containsOffset(caretOffset) val cursorInParameterList = functionLiteral.valueParameterList!!.textRange.containsOffset(caretOffset)
ParamRenamingProcessor(editor, functionLiteral, cursorInParameterList).run() ParamRenamingProcessor(editor, functionLiteral, cursorInParameterList).run()
} }
@@ -60,12 +60,12 @@ public class ReplaceExplicitFunctionLiteralParamWithItIntention() : PsiElementBa
if (expression != null) { if (expression != null) {
val target = expression.mainReference.resolveToDescriptors(expression.analyze(BodyResolveMode.PARTIAL)) val target = expression.mainReference.resolveToDescriptors(expression.analyze(BodyResolveMode.PARTIAL))
.singleOrNull() as? ParameterDescriptor ?: return null .singleOrNull() as? ParameterDescriptor ?: return null
val functionDescriptor = target.getContainingDeclaration() as? AnonymousFunctionDescriptor ?: return null val functionDescriptor = target.containingDeclaration as? AnonymousFunctionDescriptor ?: return null
return DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor) as? KtFunctionLiteral return DescriptorToSourceUtils.descriptorToDeclaration(functionDescriptor) as? KtFunctionLiteral
} }
val functionLiteral = element.getParentOfType<KtFunctionLiteral>(true) ?: return null val functionLiteral = element.getParentOfType<KtFunctionLiteral>(true) ?: return null
val arrow = functionLiteral.getArrow() ?: return null val arrow = functionLiteral.arrow ?: return null
if (caretOffset > arrow.endOffset) return null if (caretOffset > arrow.endOffset) return null
return functionLiteral return functionLiteral
} }
@@ -74,8 +74,8 @@ public class ReplaceExplicitFunctionLiteralParamWithItIntention() : PsiElementBa
val editor: Editor, val editor: Editor,
val functionLiteral: KtFunctionLiteral, val functionLiteral: KtFunctionLiteral,
val cursorWasInParameterList: Boolean val cursorWasInParameterList: Boolean
) : RenameProcessor(editor.getProject(), ) : RenameProcessor(editor.project,
functionLiteral.getValueParameters().single(), functionLiteral.valueParameters.single(),
"it", "it",
false, false,
false false
@@ -83,15 +83,15 @@ public class ReplaceExplicitFunctionLiteralParamWithItIntention() : PsiElementBa
public override fun performRefactoring(usages: Array<out UsageInfo>) { public override fun performRefactoring(usages: Array<out UsageInfo>) {
super.performRefactoring(usages) super.performRefactoring(usages)
functionLiteral.deleteChildRange(functionLiteral.getValueParameterList(), functionLiteral.getArrow()!!) functionLiteral.deleteChildRange(functionLiteral.valueParameterList, functionLiteral.arrow!!)
if (cursorWasInParameterList) { if (cursorWasInParameterList) {
editor.getCaretModel().moveToOffset(functionLiteral.getBodyExpression()!!.getTextOffset()) editor.caretModel.moveToOffset(functionLiteral.bodyExpression!!.textOffset)
} }
val project = functionLiteral.getProject() val project = functionLiteral.project
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()) PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
CodeStyleManager.getInstance(project).adjustLineIndent(functionLiteral.getContainingFile(), functionLiteral.getTextRange()) CodeStyleManager.getInstance(project).adjustLineIndent(functionLiteral.containingFile, functionLiteral.textRange)
} }
} }
@@ -21,13 +21,15 @@ import com.intellij.openapi.editor.Editor
import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiDocumentManager
import com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler import com.intellij.refactoring.rename.inplace.VariableInplaceRenameHandler
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.references.mainReference
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.KtFunctionLiteral
import org.jetbrains.kotlin.psi.KtLambdaExpression
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
public class ReplaceItWithExplicitFunctionLiteralParamIntention() : SelfTargetingOffsetIndependentIntention<KtNameReferenceExpression> ( public class ReplaceItWithExplicitFunctionLiteralParamIntention() : SelfTargetingOffsetIndependentIntention<KtNameReferenceExpression> (
javaClass(), "Replace 'it' with explicit parameter" KtNameReferenceExpression::class.java, "Replace 'it' with explicit parameter"
), LowPriorityAction { ), LowPriorityAction {
override fun isApplicableTo(element: KtNameReferenceExpression) override fun isApplicableTo(element: KtNameReferenceExpression)
= isAutoCreatedItUsage(element) = isAutoCreatedItUsage(element)
@@ -35,17 +37,17 @@ public class ReplaceItWithExplicitFunctionLiteralParamIntention() : SelfTargetin
override fun applyTo(element: KtNameReferenceExpression, editor: Editor) { override fun applyTo(element: KtNameReferenceExpression, editor: Editor) {
val target = element.mainReference.resolveToDescriptors(element.analyze()).single() val target = element.mainReference.resolveToDescriptors(element.analyze()).single()
val functionLiteral = DescriptorToSourceUtils.descriptorToDeclaration(target.getContainingDeclaration()!!) as KtFunctionLiteral val functionLiteral = DescriptorToSourceUtils.descriptorToDeclaration(target.containingDeclaration!!) as KtFunctionLiteral
val newExpr = KtPsiFactory(element).createExpression("{ it -> }") as KtLambdaExpression val newExpr = KtPsiFactory(element).createExpression("{ it -> }") as KtLambdaExpression
functionLiteral.addRangeAfter( functionLiteral.addRangeAfter(
newExpr.getFunctionLiteral().getValueParameterList(), newExpr.functionLiteral.valueParameterList,
newExpr.getFunctionLiteral().getArrow()!!, newExpr.functionLiteral.arrow!!,
functionLiteral.getLBrace()) functionLiteral.lBrace)
PsiDocumentManager.getInstance(element.getProject()).doPostponedOperationsAndUnblockDocument(editor.getDocument()) PsiDocumentManager.getInstance(element.project).doPostponedOperationsAndUnblockDocument(editor.document)
val paramToRename = functionLiteral.getValueParameters().single() val paramToRename = functionLiteral.valueParameters.single()
editor.getCaretModel().moveToOffset(element.getTextOffset()) editor.caretModel.moveToOffset(element.textOffset)
VariableInplaceRenameHandler().doRename(paramToRename, editor, null) VariableInplaceRenameHandler().doRename(paramToRename, editor, null)
} }
} }
@@ -31,27 +31,26 @@ import org.jetbrains.kotlin.resolve.BindingContext
public class ReplaceWithOperatorAssignmentInspection : IntentionBasedInspection<KtBinaryExpression>(ReplaceWithOperatorAssignmentIntention()) public class ReplaceWithOperatorAssignmentInspection : IntentionBasedInspection<KtBinaryExpression>(ReplaceWithOperatorAssignmentIntention())
public class ReplaceWithOperatorAssignmentIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>(javaClass(), "Replace with operator-assignment") { public class ReplaceWithOperatorAssignmentIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Replace with operator-assignment") {
override fun isApplicableTo(element: KtBinaryExpression): Boolean { override fun isApplicableTo(element: KtBinaryExpression): Boolean {
if (element.getOperationToken() != KtTokens.EQ) return false if (element.operationToken != KtTokens.EQ) return false
val left = element.getLeft() as? KtNameReferenceExpression ?: return false val left = element.left as? KtNameReferenceExpression ?: return false
val right = element.getRight() as? KtBinaryExpression ?: return false val right = element.right as? KtBinaryExpression ?: return false
if (right.getLeft() == null || right.getRight() == null) return false if (right.left == null || right.right == null) return false
return checkExpressionRepeat(left, right) return checkExpressionRepeat(left, right)
} }
private fun checkExpressionRepeat(variableExpression: KtNameReferenceExpression, expression: KtBinaryExpression): Boolean { private fun checkExpressionRepeat(variableExpression: KtNameReferenceExpression, expression: KtBinaryExpression): Boolean {
val context = expression.analyze() val context = expression.analyze()
val descriptor = context[BindingContext.REFERENCE_TARGET, expression.getOperationReference()]?.getContainingDeclaration() val descriptor = context[BindingContext.REFERENCE_TARGET, expression.operationReference]?.containingDeclaration
val isPrimitiveOperation = descriptor is ClassDescriptor && KotlinBuiltIns.isPrimitiveType(descriptor.getDefaultType()) val isPrimitiveOperation = descriptor is ClassDescriptor && KotlinBuiltIns.isPrimitiveType(descriptor.defaultType)
val operationToken = expression.getOperationToken() val operationToken = expression.operationToken
setText("Replace with ${expression.getOperationReference().getText()}= expression") text = "Replace with ${expression.operationReference.text}= expression"
val expressionLeft = expression.getLeft() val expressionLeft = expression.left
val expressionRight = expression.getRight() val expressionRight = expression.right
return when { return when {
variableExpression.matches(expressionLeft) -> { variableExpression.matches(expressionLeft) -> {
isArithmeticOperation(operationToken) isArithmeticOperation(operationToken)
@@ -62,7 +61,7 @@ public class ReplaceWithOperatorAssignmentIntention : SelfTargetingOffsetIndepen
} }
expressionLeft is KtBinaryExpression -> { expressionLeft is KtBinaryExpression -> {
val sameCommutativeOperation = expressionLeft.getOperationToken() == operationToken && isCommutative(operationToken) val sameCommutativeOperation = expressionLeft.operationToken == operationToken && isCommutative(operationToken)
isPrimitiveOperation && sameCommutativeOperation && checkExpressionRepeat(variableExpression, expressionLeft) isPrimitiveOperation && sameCommutativeOperation && checkExpressionRepeat(variableExpression, expressionLeft)
} }
@@ -81,26 +80,26 @@ public class ReplaceWithOperatorAssignmentIntention : SelfTargetingOffsetIndepen
override fun applyTo(element: KtBinaryExpression, editor: Editor) { override fun applyTo(element: KtBinaryExpression, editor: Editor) {
val replacement = buildOperatorAssignmentText( val replacement = buildOperatorAssignmentText(
element.getLeft() as KtNameReferenceExpression, element.left as KtNameReferenceExpression,
element.getRight() as KtBinaryExpression, element.right as KtBinaryExpression,
"" ""
) )
element.replace(KtPsiFactory(element).createExpression(replacement)) element.replace(KtPsiFactory(element).createExpression(replacement))
} }
tailrec private fun buildOperatorAssignmentText(variableExpression: KtNameReferenceExpression, expression: KtBinaryExpression, tail: String): String { tailrec private fun buildOperatorAssignmentText(variableExpression: KtNameReferenceExpression, expression: KtBinaryExpression, tail: String): String {
val operationText = expression.getOperationReference().getText() val operationText = expression.operationReference.text
val variableName = variableExpression.getText() val variableName = variableExpression.text
fun String.appendTail() = if (tail.isEmpty()) this else "$this $tail" fun String.appendTail() = if (tail.isEmpty()) this else "$this $tail"
return when { return when {
variableExpression.matches(expression.getLeft()) -> "$variableName $operationText= ${expression.getRight()!!.getText()}".appendTail() variableExpression.matches(expression.left) -> "$variableName $operationText= ${expression.right!!.text}".appendTail()
variableExpression.matches(expression.getRight()) -> "$variableName $operationText= ${expression.getLeft()!!.getText()}".appendTail() variableExpression.matches(expression.right) -> "$variableName $operationText= ${expression.left!!.text}".appendTail()
expression.getLeft() is KtBinaryExpression -> expression.left is KtBinaryExpression ->
buildOperatorAssignmentText(variableExpression, expression.getLeft() as KtBinaryExpression, "$operationText ${expression.getRight()!!.getText()}".appendTail()) buildOperatorAssignmentText(variableExpression, expression.left as KtBinaryExpression, "$operationText ${expression.right!!.text}".appendTail())
else -> tail else -> tail
} }
@@ -24,22 +24,22 @@ import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.createExpressionByPattern import org.jetbrains.kotlin.psi.createExpressionByPattern
public class ReplaceWithOrdinaryAssignmentIntention : SelfTargetingIntention<KtBinaryExpression>(javaClass(), "Replace with ordinary assignment"), LowPriorityAction { public class ReplaceWithOrdinaryAssignmentIntention : SelfTargetingIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Replace with ordinary assignment"), LowPriorityAction {
override fun isApplicableTo(element: KtBinaryExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtBinaryExpression, caretOffset: Int): Boolean {
if (element.getOperationToken() !in KtTokens.AUGMENTED_ASSIGNMENTS) return false if (element.operationToken !in KtTokens.AUGMENTED_ASSIGNMENTS) return false
if (element.getLeft() !is KtNameReferenceExpression) return false if (element.left !is KtNameReferenceExpression) return false
if (element.getRight() == null) return false if (element.right == null) return false
return element.getOperationReference().getTextRange().containsOffset(caretOffset) return element.operationReference.textRange.containsOffset(caretOffset)
} }
override fun applyTo(element: KtBinaryExpression, editor: Editor) { override fun applyTo(element: KtBinaryExpression, editor: Editor) {
val left = element.getLeft()!! val left = element.left!!
val right = element.getRight()!! val right = element.right!!
val factory = KtPsiFactory(element) val factory = KtPsiFactory(element)
val assignOpText = element.getOperationReference().getText() val assignOpText = element.operationReference.text
assert(assignOpText.endsWith("=")) assert(assignOpText.endsWith("="))
val operationText = assignOpText.substring(0, assignOpText.length() - 1) val operationText = assignOpText.substring(0, assignOpText.length - 1)
element.replace(factory.createExpressionByPattern("$0 = $0 $operationText $1", left, right)) element.replace(factory.createExpressionByPattern("$0 = $0 $operationText $1", left, right))
} }
@@ -30,30 +30,30 @@ import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
public class SimplifyBooleanWithConstantsInspection : IntentionBasedInspection<KtBinaryExpression>(SimplifyBooleanWithConstantsIntention()) public class SimplifyBooleanWithConstantsInspection : IntentionBasedInspection<KtBinaryExpression>(SimplifyBooleanWithConstantsIntention())
public class SimplifyBooleanWithConstantsIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>(javaClass(), "Simplify boolean expression") { public class SimplifyBooleanWithConstantsIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Simplify boolean expression") {
override fun isApplicableTo(element: KtBinaryExpression): Boolean { override fun isApplicableTo(element: KtBinaryExpression): Boolean {
val topBinary = PsiTreeUtil.getTopmostParentOfType(element, javaClass<KtBinaryExpression>()) ?: element val topBinary = PsiTreeUtil.getTopmostParentOfType(element, KtBinaryExpression::class.java) ?: element
return areThereExpressionsToBeSimplified(topBinary) return areThereExpressionsToBeSimplified(topBinary)
} }
private fun areThereExpressionsToBeSimplified(element: KtExpression?) : Boolean { private fun areThereExpressionsToBeSimplified(element: KtExpression?) : Boolean {
if (element == null) return false if (element == null) return false
when (element) { when (element) {
is KtParenthesizedExpression -> return areThereExpressionsToBeSimplified(element.getExpression()) is KtParenthesizedExpression -> return areThereExpressionsToBeSimplified(element.expression)
is KtBinaryExpression -> { is KtBinaryExpression -> {
val op = element.getOperationToken() val op = element.operationToken
if ((op == KtTokens.ANDAND || op == KtTokens.OROR) && if ((op == KtTokens.ANDAND || op == KtTokens.OROR) &&
(areThereExpressionsToBeSimplified(element.getLeft()) || (areThereExpressionsToBeSimplified(element.left) ||
areThereExpressionsToBeSimplified(element.getRight()))) return true areThereExpressionsToBeSimplified(element.right))) return true
} }
} }
return element.canBeReducedToBooleanConstant(null) return element.canBeReducedToBooleanConstant(null)
} }
override fun applyTo(element: KtBinaryExpression, editor: Editor) { override fun applyTo(element: KtBinaryExpression, editor: Editor) {
val topBinary = PsiTreeUtil.getTopmostParentOfType(element, javaClass<KtBinaryExpression>()) ?: element val topBinary = PsiTreeUtil.getTopmostParentOfType(element, KtBinaryExpression::class.java) ?: element
val simplified = toSimplifiedExpression(topBinary) val simplified = toSimplifiedExpression(topBinary)
topBinary.replace(KtPsiUtil.safeDeparenthesize(simplified)) topBinary.replace(KtPsiUtil.safeDeparenthesize(simplified))
} }
@@ -71,7 +71,7 @@ public class SimplifyBooleanWithConstantsIntention : SelfTargetingOffsetIndepend
} }
expression is KtParenthesizedExpression -> { expression is KtParenthesizedExpression -> {
val expr = expression.getExpression() val expr = expression.expression
if (expr != null) { if (expr != null) {
val simplified = toSimplifiedExpression(expr) val simplified = toSimplifiedExpression(expr)
return if (simplified is KtBinaryExpression) { return if (simplified is KtBinaryExpression) {
@@ -86,9 +86,9 @@ public class SimplifyBooleanWithConstantsIntention : SelfTargetingOffsetIndepend
} }
expression is KtBinaryExpression -> { expression is KtBinaryExpression -> {
val left = expression.getLeft() val left = expression.left
val right = expression.getRight() val right = expression.right
val op = expression.getOperationToken() val op = expression.operationToken
if (left != null && right != null && (op == KtTokens.ANDAND || op == KtTokens.OROR)) { if (left != null && right != null && (op == KtTokens.ANDAND || op == KtTokens.OROR)) {
val simpleLeft = simplifyExpression(left) val simpleLeft = simplifyExpression(left)
val simpleRight = simplifyExpression(right) val simpleRight = simplifyExpression(right)
@@ -102,7 +102,7 @@ public class SimplifyBooleanWithConstantsIntention : SelfTargetingOffsetIndepend
simpleRight.canBeReducedToFalse() -> toSimplifiedBooleanBinaryExpressionWithConstantOperand(false, simpleLeft, op) simpleRight.canBeReducedToFalse() -> toSimplifiedBooleanBinaryExpressionWithConstantOperand(false, simpleLeft, op)
else -> { else -> {
val opText = expression.getOperationReference().getText() val opText = expression.operationReference.text
psiFactory.createExpressionByPattern("$0 $opText $1", simpleLeft, simpleRight) psiFactory.createExpressionByPattern("$0 $opText $1", simpleLeft, simpleRight)
} }
} }
@@ -26,7 +26,7 @@ import org.jetbrains.kotlin.psi.*
public class SimplifyNegatedBinaryExpressionInspection : IntentionBasedInspection<KtPrefixExpression>(SimplifyNegatedBinaryExpressionIntention()) public class SimplifyNegatedBinaryExpressionInspection : IntentionBasedInspection<KtPrefixExpression>(SimplifyNegatedBinaryExpressionIntention())
public class SimplifyNegatedBinaryExpressionIntention : SelfTargetingRangeIntention<KtPrefixExpression>(javaClass(), "Simplify negated binary expression") { public class SimplifyNegatedBinaryExpressionIntention : SelfTargetingRangeIntention<KtPrefixExpression>(KtPrefixExpression::class.java, "Simplify negated binary expression") {
private fun IElementType.negate(): KtSingleValueToken? = when (this) { private fun IElementType.negate(): KtSingleValueToken? = when (this) {
KtTokens.IN_KEYWORD -> KtTokens.NOT_IN KtTokens.IN_KEYWORD -> KtTokens.NOT_IN
@@ -48,23 +48,23 @@ public class SimplifyNegatedBinaryExpressionIntention : SelfTargetingRangeIntent
} }
override fun applicabilityRange(element: KtPrefixExpression): TextRange? { override fun applicabilityRange(element: KtPrefixExpression): TextRange? {
return if (isApplicableTo(element)) element.getOperationReference().getTextRange() else null return if (isApplicableTo(element)) element.operationReference.textRange else null
} }
public fun isApplicableTo(element: KtPrefixExpression): Boolean { public fun isApplicableTo(element: KtPrefixExpression): Boolean {
if (element.getOperationToken() != KtTokens.EXCL) return false if (element.operationToken != KtTokens.EXCL) return false
val expression = KtPsiUtil.deparenthesize(element.getBaseExpression()) as? KtOperationExpression ?: return false val expression = KtPsiUtil.deparenthesize(element.baseExpression) as? KtOperationExpression ?: return false
when (expression) { when (expression) {
is KtIsExpression -> { if (expression.getTypeReference() == null) return false } is KtIsExpression -> { if (expression.typeReference == null) return false }
is KtBinaryExpression -> { if (expression.getLeft() == null || expression.getRight() == null) return false } is KtBinaryExpression -> { if (expression.left == null || expression.right == null) return false }
else -> return false else -> return false
} }
val operation = expression.getOperationReference().getReferencedNameElementType() as? KtSingleValueToken ?: return false val operation = expression.operationReference.getReferencedNameElementType() as? KtSingleValueToken ?: return false
val negatedOperation = operation.negate() ?: return false val negatedOperation = operation.negate() ?: return false
setText("Simplify negated '${operation.getValue()}' expression to '${negatedOperation.getValue()}'") text = "Simplify negated '${operation.value}' expression to '${negatedOperation.value}'"
return true return true
} }
@@ -73,13 +73,13 @@ public class SimplifyNegatedBinaryExpressionIntention : SelfTargetingRangeIntent
} }
public fun applyTo(element: KtPrefixExpression) { public fun applyTo(element: KtPrefixExpression) {
val expression = KtPsiUtil.deparenthesize(element.getBaseExpression())!! val expression = KtPsiUtil.deparenthesize(element.baseExpression)!!
val operation = (expression as KtOperationExpression).getOperationReference().getReferencedNameElementType().negate()!!.getValue() val operation = (expression as KtOperationExpression).operationReference.getReferencedNameElementType().negate()!!.value
val psiFactory = KtPsiFactory(expression) val psiFactory = KtPsiFactory(expression)
val newExpression = when (expression) { val newExpression = when (expression) {
is KtIsExpression -> psiFactory.createExpressionByPattern("$0 $1 $2", expression.getLeftHandSide(), operation, expression.getTypeReference()!!) is KtIsExpression -> psiFactory.createExpressionByPattern("$0 $1 $2", expression.leftHandSide, operation, expression.typeReference!!)
is KtBinaryExpression -> psiFactory.createExpressionByPattern("$0 $1 $2", expression.getLeft()!!, operation, expression.getRight()!!) is KtBinaryExpression -> psiFactory.createExpressionByPattern("$0 $1 $2", expression.left!!, operation, expression.right!!)
else -> throw IllegalArgumentException() else -> throw IllegalArgumentException()
} }
element.replace(newExpression) element.replace(newExpression)
@@ -27,40 +27,40 @@ import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
public class SpecifyExplicitLambdaSignatureIntention : SelfTargetingIntention<KtLambdaExpression>(javaClass(), "Specify explicit lambda signature"), LowPriorityAction { public class SpecifyExplicitLambdaSignatureIntention : SelfTargetingIntention<KtLambdaExpression>(KtLambdaExpression::class.java, "Specify explicit lambda signature"), LowPriorityAction {
override fun isApplicableTo(element: KtLambdaExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtLambdaExpression, caretOffset: Int): Boolean {
val arrow = element.getFunctionLiteral().getArrow() val arrow = element.functionLiteral.arrow
if (arrow != null) { if (arrow != null) {
if (caretOffset > arrow.endOffset) return false if (caretOffset > arrow.endOffset) return false
if (element.getValueParameters().all { it.getTypeReference() != null }) return false if (element.valueParameters.all { it.typeReference != null }) return false
} }
else { else {
if (!element.getLeftCurlyBrace().getTextRange().containsOffset(caretOffset)) return false if (!element.leftCurlyBrace.textRange.containsOffset(caretOffset)) return false
} }
val functionDescriptor = element.analyze()[BindingContext.FUNCTION, element.getFunctionLiteral()] ?: return false val functionDescriptor = element.analyze()[BindingContext.FUNCTION, element.functionLiteral] ?: return false
return functionDescriptor.getValueParameters().none { it.getType().isError() } return functionDescriptor.valueParameters.none { it.type.isError }
} }
override fun applyTo(element: KtLambdaExpression, editor: Editor) { override fun applyTo(element: KtLambdaExpression, editor: Editor) {
val psiFactory = KtPsiFactory(element) val psiFactory = KtPsiFactory(element)
val functionLiteral = element.getFunctionLiteral() val functionLiteral = element.functionLiteral
val functionDescriptor = element.analyze()[BindingContext.FUNCTION, functionLiteral]!! val functionDescriptor = element.analyze()[BindingContext.FUNCTION, functionLiteral]!!
val parameterString = functionDescriptor.getValueParameters() val parameterString = functionDescriptor.valueParameters
.map { "${it.getName()}: ${IdeDescriptorRenderers.SOURCE_CODE.renderType(it.getType())}" } .map { "${it.name}: ${IdeDescriptorRenderers.SOURCE_CODE.renderType(it.type)}" }
.joinToString(", ") .joinToString(", ")
val newParameterList = psiFactory.createFunctionLiteralParameterList(parameterString) val newParameterList = psiFactory.createFunctionLiteralParameterList(parameterString)
val oldParameterList = functionLiteral.getValueParameterList() val oldParameterList = functionLiteral.valueParameterList
if (oldParameterList != null) { if (oldParameterList != null) {
oldParameterList.replace(newParameterList) oldParameterList.replace(newParameterList)
} }
else { else {
val openBraceElement = functionLiteral.getLBrace() val openBraceElement = functionLiteral.lBrace
val nextSibling = openBraceElement.getNextSibling() val nextSibling = openBraceElement.nextSibling
val addNewline = nextSibling is PsiWhiteSpace && nextSibling.getText()?.contains("\n") ?: false val addNewline = nextSibling is PsiWhiteSpace && nextSibling.text?.contains("\n") ?: false
val (whitespace, arrow) = psiFactory.createWhitespaceAndArrow() val (whitespace, arrow) = psiFactory.createWhitespaceAndArrow()
functionLiteral.addRangeAfter(whitespace, arrow, openBraceElement) functionLiteral.addRangeAfter(whitespace, arrow, openBraceElement)
functionLiteral.addAfter(newParameterList, openBraceElement) functionLiteral.addAfter(newParameterList, openBraceElement)
@@ -68,6 +68,6 @@ public class SpecifyExplicitLambdaSignatureIntention : SelfTargetingIntention<Kt
functionLiteral.addAfter(psiFactory.createNewLine(), openBraceElement) functionLiteral.addAfter(psiFactory.createNewLine(), openBraceElement)
} }
} }
ShortenReferences.DEFAULT.process(element.getValueParameters()) ShortenReferences.DEFAULT.process(element.valueParameters)
} }
} }
@@ -34,21 +34,21 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import java.util.* import java.util.*
public class SpecifyTypeExplicitlyIntention : SelfTargetingIntention<KtCallableDeclaration>(javaClass(), "Specify type explicitly"), LowPriorityAction { public class SpecifyTypeExplicitlyIntention : SelfTargetingIntention<KtCallableDeclaration>(KtCallableDeclaration::class.java, "Specify type explicitly"), LowPriorityAction {
override fun isApplicableTo(element: KtCallableDeclaration, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtCallableDeclaration, caretOffset: Int): Boolean {
if (element.getContainingFile() is KtCodeFragment) return false if (element.containingFile is KtCodeFragment) return false
if (element is KtFunctionLiteral) return false // TODO: should JetFunctionLiteral be JetCallableDeclaration at all? if (element is KtFunctionLiteral) return false // TODO: should JetFunctionLiteral be JetCallableDeclaration at all?
if (element is KtConstructor<*>) return false if (element is KtConstructor<*>) return false
if (element.getTypeReference() != null) return false if (element.typeReference != null) return false
if (getTypeForDeclaration(element).isError()) return false if (getTypeForDeclaration(element).isError) return false
val initializer = (element as? KtWithExpressionInitializer)?.getInitializer() val initializer = (element as? KtWithExpressionInitializer)?.initializer
if (initializer != null && initializer.getTextRange().containsOffset(caretOffset)) return false if (initializer != null && initializer.textRange.containsOffset(caretOffset)) return false
if (element is KtNamedFunction && element.hasBlockBody()) return false if (element is KtNamedFunction && element.hasBlockBody()) return false
setText(if (element is KtFunction) "Specify return type explicitly" else "Specify type explicitly") text = if (element is KtFunction) "Specify return type explicitly" else "Specify type explicitly"
return true return true
} }
@@ -61,12 +61,12 @@ public class SpecifyTypeExplicitlyIntention : SelfTargetingIntention<KtCallableD
companion object { companion object {
public fun getTypeForDeclaration(declaration: KtCallableDeclaration): KotlinType { public fun getTypeForDeclaration(declaration: KtCallableDeclaration): KotlinType {
val descriptor = declaration.analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration] val descriptor = declaration.analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration]
val type = (descriptor as? CallableDescriptor)?.getReturnType() val type = (descriptor as? CallableDescriptor)?.returnType
return type ?: ErrorUtils.createErrorType("null type") return type ?: ErrorUtils.createErrorType("null type")
} }
public fun createTypeExpressionForTemplate(exprType: KotlinType): Expression { public fun createTypeExpressionForTemplate(exprType: KotlinType): Expression {
val descriptor = exprType.getConstructor().getDeclarationDescriptor() val descriptor = exprType.constructor.declarationDescriptor
val isAnonymous = descriptor != null && DescriptorUtils.isAnonymousObject(descriptor) val isAnonymous = descriptor != null && DescriptorUtils.isAnonymousObject(descriptor)
val allSupertypes = TypeUtils.getAllSupertypes(exprType) val allSupertypes = TypeUtils.getAllSupertypes(exprType)
@@ -91,8 +91,8 @@ public class SpecifyTypeExplicitlyIntention : SelfTargetingIntention<KtCallableD
public fun createTypeReferencePostprocessor(declaration: KtCallableDeclaration): TemplateEditingAdapter { public fun createTypeReferencePostprocessor(declaration: KtCallableDeclaration): TemplateEditingAdapter {
return object : TemplateEditingAdapter() { return object : TemplateEditingAdapter() {
override fun templateFinished(template: Template?, brokenOff: Boolean) { override fun templateFinished(template: Template?, brokenOff: Boolean) {
val typeRef = declaration.getTypeReference() val typeRef = declaration.typeReference
if (typeRef != null && typeRef.isValid()) { if (typeRef != null && typeRef.isValid) {
ShortenReferences.DEFAULT.process(typeRef) ShortenReferences.DEFAULT.process(typeRef)
} }
} }
@@ -100,21 +100,21 @@ public class SpecifyTypeExplicitlyIntention : SelfTargetingIntention<KtCallableD
} }
private fun addTypeAnnotationWithTemplate(editor: Editor, declaration: KtCallableDeclaration, exprType: KotlinType) { private fun addTypeAnnotationWithTemplate(editor: Editor, declaration: KtCallableDeclaration, exprType: KotlinType) {
assert(!exprType.isError()) { "Unexpected error type, should have been checked before: " + declaration.getElementTextWithContext() + ", type = " + exprType } assert(!exprType.isError) { "Unexpected error type, should have been checked before: " + declaration.getElementTextWithContext() + ", type = " + exprType }
val project = declaration.getProject() val project = declaration.project
val expression = createTypeExpressionForTemplate(exprType) val expression = createTypeExpressionForTemplate(exprType)
declaration.setType(KotlinBuiltIns.FQ_NAMES.any.asString()) declaration.setType(KotlinBuiltIns.FQ_NAMES.any.asString())
PsiDocumentManager.getInstance(project).commitAllDocuments() PsiDocumentManager.getInstance(project).commitAllDocuments()
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()) PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
val newTypeRef = declaration.getTypeReference()!! val newTypeRef = declaration.typeReference!!
val builder = TemplateBuilderImpl(newTypeRef) val builder = TemplateBuilderImpl(newTypeRef)
builder.replaceElement(newTypeRef, expression) builder.replaceElement(newTypeRef, expression)
editor.getCaretModel().moveToOffset(newTypeRef.getNode().getStartOffset()) editor.caretModel.moveToOffset(newTypeRef.node.startOffset)
TemplateManager.getInstance(project).startTemplate(editor, builder.buildInlineTemplate(), createTypeReferencePostprocessor(declaration)) TemplateManager.getInstance(project).startTemplate(editor, builder.buildInlineTemplate(), createTypeReferencePostprocessor(declaration))
} }
@@ -29,11 +29,11 @@ import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
public class SplitIfIntention : SelfTargetingIntention<KtExpression>(javaClass(), "Split if into 2 if's") { public class SplitIfIntention : SelfTargetingIntention<KtExpression>(KtExpression::class.java, "Split if into 2 if's") {
override fun isApplicableTo(element: KtExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtExpression, caretOffset: Int): Boolean {
return when (element) { return when (element) {
is KtOperationReferenceExpression -> isOperatorValid(element) is KtOperationReferenceExpression -> isOperatorValid(element)
is KtIfExpression -> getFirstValidOperator(element) != null && element.getIfKeyword().getTextRange().containsOffset(caretOffset) is KtIfExpression -> getFirstValidOperator(element) != null && element.ifKeyword.textRange.containsOffset(caretOffset)
else -> false else -> false
} }
} }
@@ -48,11 +48,11 @@ public class SplitIfIntention : SelfTargetingIntention<KtExpression>(javaClass()
val commentSaver = CommentSaver(ifExpression!!) val commentSaver = CommentSaver(ifExpression!!)
val expression = operator.getParent() as KtBinaryExpression val expression = operator.parent as KtBinaryExpression
val rightExpression = KtPsiUtil.safeDeparenthesize(getRight(expression, ifExpression.getCondition()!!, commentSaver)) val rightExpression = KtPsiUtil.safeDeparenthesize(getRight(expression, ifExpression.condition!!, commentSaver))
val leftExpression = KtPsiUtil.safeDeparenthesize(expression.getLeft()!!) val leftExpression = KtPsiUtil.safeDeparenthesize(expression.left!!)
val thenBranch = ifExpression.getThen()!! val thenBranch = ifExpression.then!!
val elseBranch = ifExpression.getElse() val elseBranch = ifExpression.`else`
val psiFactory = KtPsiFactory(element) val psiFactory = KtPsiFactory(element)
@@ -62,7 +62,7 @@ public class SplitIfIntention : SelfTargetingIntention<KtExpression>(javaClass()
KtTokens.ANDAND -> psiFactory.createIf(leftExpression, psiFactory.createSingleStatementBlock(innerIf), elseBranch) KtTokens.ANDAND -> psiFactory.createIf(leftExpression, psiFactory.createSingleStatementBlock(innerIf), elseBranch)
KtTokens.OROR -> { KtTokens.OROR -> {
val container = ifExpression.getParent() val container = ifExpression.parent
if (container is KtBlockExpression && elseBranch == null && thenBranch.lastBlockStatementOrThis().isExitStatement()) { // special case if (container is KtBlockExpression && elseBranch == null && thenBranch.lastBlockStatementOrThis().isExitStatement()) { // special case
val secondIf = container.addAfter(innerIf, ifExpression) val secondIf = container.addAfter(innerIf, ifExpression)
@@ -86,9 +86,9 @@ public class SplitIfIntention : SelfTargetingIntention<KtExpression>(javaClass()
private fun getRight(element: KtBinaryExpression, condition: KtExpression, commentSaver: CommentSaver): KtExpression { private fun getRight(element: KtBinaryExpression, condition: KtExpression, commentSaver: CommentSaver): KtExpression {
//gets the textOffset of the right side of the JetBinaryExpression in context to condition //gets the textOffset of the right side of the JetBinaryExpression in context to condition
val conditionRange = condition.range val conditionRange = condition.range
val startOffset = element.getRight()!!.startOffset - conditionRange.start val startOffset = element.right!!.startOffset - conditionRange.start
val endOffset = conditionRange.length val endOffset = conditionRange.length
val rightString = condition.getText().substring(startOffset, endOffset) val rightString = condition.text.substring(startOffset, endOffset)
val expression = KtPsiFactory(element).createExpression(rightString) val expression = KtPsiFactory(element).createExpression(rightString)
commentSaver.elementCreatedByText(expression, condition, TextRange(startOffset, endOffset)) commentSaver.elementCreatedByText(expression, condition, TextRange(startOffset, endOffset))
@@ -96,8 +96,8 @@ public class SplitIfIntention : SelfTargetingIntention<KtExpression>(javaClass()
} }
private fun getFirstValidOperator(element: KtIfExpression): KtOperationReferenceExpression? { private fun getFirstValidOperator(element: KtIfExpression): KtOperationReferenceExpression? {
val condition = element.getCondition() ?: return null val condition = element.condition ?: return null
return PsiTreeUtil.findChildrenOfType(condition, javaClass<KtOperationReferenceExpression>()) return PsiTreeUtil.findChildrenOfType(condition, KtOperationReferenceExpression::class.java)
.firstOrNull { isOperatorValid(it) } .firstOrNull { isOperatorValid(it) }
} }
@@ -105,21 +105,21 @@ public class SplitIfIntention : SelfTargetingIntention<KtExpression>(javaClass()
val operator = element.getReferencedNameElementType() val operator = element.getReferencedNameElementType()
if (operator != KtTokens.ANDAND && operator != KtTokens.OROR) return false if (operator != KtTokens.ANDAND && operator != KtTokens.OROR) return false
var expression = element.getParent() as? KtBinaryExpression ?: return false var expression = element.parent as? KtBinaryExpression ?: return false
if (expression.getRight() == null || expression.getLeft() == null) return false if (expression.right == null || expression.left == null) return false
while (true) { while (true) {
expression = expression.getParent() as? KtBinaryExpression ?: break expression = expression.parent as? KtBinaryExpression ?: break
if (expression.getOperationToken() != operator) return false if (expression.operationToken != operator) return false
} }
val ifExpression = expression.getParent()?.getParent() as? KtIfExpression ?: return false val ifExpression = expression.parent?.parent as? KtIfExpression ?: return false
if (ifExpression.getCondition() == null) return false if (ifExpression.condition == null) return false
if (!PsiTreeUtil.isAncestor(ifExpression.getCondition(), element, false)) return false if (!PsiTreeUtil.isAncestor(ifExpression.condition, element, false)) return false
if (ifExpression.getThen() == null) return false if (ifExpression.then == null) return false
return true return true
} }
@@ -27,7 +27,7 @@ import org.jetbrains.kotlin.psi.createExpressionByPattern
import org.jetbrains.kotlin.idea.core.copied import org.jetbrains.kotlin.idea.core.copied
import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.types.expressions.OperatorConventions
public class SwapBinaryExpressionIntention : SelfTargetingIntention<KtBinaryExpression>(javaClass(), "Flip binary expression"), LowPriorityAction { public class SwapBinaryExpressionIntention : SelfTargetingIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Flip binary expression"), LowPriorityAction {
companion object { companion object {
private val SUPPORTED_OPERATIONS = setOf(PLUS, MUL, OROR, ANDAND, EQEQ, EXCLEQ, EQEQEQ, EXCLEQEQEQ, GT, LT, GTEQ, LTEQ) private val SUPPORTED_OPERATIONS = setOf(PLUS, MUL, OROR, ANDAND, EQEQ, EXCLEQ, EQEQEQ, EXCLEQEQEQ, GT, LT, GTEQ, LTEQ)
@@ -36,18 +36,18 @@ public class SwapBinaryExpressionIntention : SelfTargetingIntention<KtBinaryExpr
} }
override fun isApplicableTo(element: KtBinaryExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtBinaryExpression, caretOffset: Int): Boolean {
val opRef = element.getOperationReference() val opRef = element.operationReference
if (!opRef.getTextRange().containsOffset(caretOffset)) return false if (!opRef.textRange.containsOffset(caretOffset)) return false
if (leftSubject(element) == null || rightSubject(element) == null) { if (leftSubject(element) == null || rightSubject(element) == null) {
return false return false
} }
val operationToken = element.getOperationToken() val operationToken = element.operationToken
val operationTokenText = opRef.getText() val operationTokenText = opRef.text
if (operationToken in SUPPORTED_OPERATIONS if (operationToken in SUPPORTED_OPERATIONS
|| operationToken == IDENTIFIER && operationTokenText in SUPPORTED_OPERATION_NAMES) { || operationToken == IDENTIFIER && operationTokenText in SUPPORTED_OPERATION_NAMES) {
setText("Flip '$operationTokenText'") text = "Flip '$operationTokenText'"
return true return true
} }
return false return false
@@ -55,7 +55,7 @@ public class SwapBinaryExpressionIntention : SelfTargetingIntention<KtBinaryExpr
override fun applyTo(element: KtBinaryExpression, editor: Editor) { override fun applyTo(element: KtBinaryExpression, editor: Editor) {
// Have to use text here to preserve names like "plus" // Have to use text here to preserve names like "plus"
val operator = element.getOperationReference().getText()!! val operator = element.operationReference.text!!
val convertedOperator = when (operator) { val convertedOperator = when (operator) {
">" -> "<" ">" -> "<"
"<" -> ">" "<" -> ">"
@@ -69,15 +69,15 @@ public class SwapBinaryExpressionIntention : SelfTargetingIntention<KtBinaryExpr
val leftCopy = left.copied() val leftCopy = left.copied()
left.replace(rightCopy) left.replace(rightCopy)
right.replace(leftCopy) right.replace(leftCopy)
element.replace(KtPsiFactory(element).createExpressionByPattern("$0 $convertedOperator $1" , element.getLeft()!!, element.getRight()!!)) element.replace(KtPsiFactory(element).createExpressionByPattern("$0 $convertedOperator $1", element.left!!, element.right!!))
} }
private fun leftSubject(element: KtBinaryExpression): KtExpression? { private fun leftSubject(element: KtBinaryExpression): KtExpression? {
return firstDescendantOfTighterPrecedence(element.getLeft(), PsiPrecedences.getPrecedence(element), KtBinaryExpression::getRight) return firstDescendantOfTighterPrecedence(element.left, PsiPrecedences.getPrecedence(element), KtBinaryExpression::getRight)
} }
private fun rightSubject(element: KtBinaryExpression): KtExpression? { private fun rightSubject(element: KtBinaryExpression): KtExpression? {
return firstDescendantOfTighterPrecedence(element.getRight(), PsiPrecedences.getPrecedence(element), KtBinaryExpression::getLeft) return firstDescendantOfTighterPrecedence(element.right, PsiPrecedences.getPrecedence(element), KtBinaryExpression::getLeft)
} }
private fun firstDescendantOfTighterPrecedence(expression: KtExpression?, precedence: Int, getChild: KtBinaryExpression.() -> KtExpression?): KtExpression? { private fun firstDescendantOfTighterPrecedence(expression: KtExpression?, precedence: Int, getChild: KtBinaryExpression.() -> KtExpression?): KtExpression? {
@@ -23,16 +23,16 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
public class ToInfixCallIntention : SelfTargetingIntention<KtCallExpression>(javaClass(), "Replace with infix function call") { public class ToInfixCallIntention : SelfTargetingIntention<KtCallExpression>(KtCallExpression::class.java, "Replace with infix function call") {
override fun isApplicableTo(element: KtCallExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtCallExpression, caretOffset: Int): Boolean {
val calleeExpr = element.getCalleeExpression() as? KtNameReferenceExpression ?: return false val calleeExpr = element.calleeExpression as? KtNameReferenceExpression ?: return false
if (!calleeExpr.getTextRange().containsOffset(caretOffset)) return false if (!calleeExpr.textRange.containsOffset(caretOffset)) return false
val dotQualified = element.getParent() as? KtDotQualifiedExpression ?: return false val dotQualified = element.parent as? KtDotQualifiedExpression ?: return false
if (element.getTypeArgumentList() != null) return false if (element.typeArgumentList != null) return false
val argument = element.getValueArguments().singleOrNull() ?: return false val argument = element.valueArguments.singleOrNull() ?: return false
if (argument.isNamed()) return false if (argument.isNamed()) return false
if (argument.getArgumentExpression() == null) return false if (argument.getArgumentExpression() == null) return false
@@ -48,10 +48,10 @@ public class ToInfixCallIntention : SelfTargetingIntention<KtCallExpression>(jav
} }
override fun applyTo(element: KtCallExpression, editor: Editor) { override fun applyTo(element: KtCallExpression, editor: Editor) {
val dotQualified = element.getParent() as KtDotQualifiedExpression val dotQualified = element.parent as KtDotQualifiedExpression
val receiver = dotQualified.getReceiverExpression() val receiver = dotQualified.receiverExpression
val argument = element.getValueArguments().single().getArgumentExpression()!! val argument = element.valueArguments.single().getArgumentExpression()!!
val name = element.getCalleeExpression()!!.getText() val name = element.calleeExpression!!.text
val newCall = KtPsiFactory(element).createExpressionByPattern("$0 $name $1", receiver, argument) val newCall = KtPsiFactory(element).createExpressionByPattern("$0 $name $1", receiver, argument)
dotQualified.replace(newCall) dotQualified.replace(newCall)
@@ -55,7 +55,7 @@ import org.jetbrains.kotlin.types.TypeUtils
class UsePropertyAccessSyntaxInspection : IntentionBasedInspection<KtCallExpression>(UsePropertyAccessSyntaxIntention()), CleanupLocalInspectionTool class UsePropertyAccessSyntaxInspection : IntentionBasedInspection<KtCallExpression>(UsePropertyAccessSyntaxIntention()), CleanupLocalInspectionTool
class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention<KtCallExpression>(javaClass(), "Use property access syntax") { class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention<KtCallExpression>(KtCallExpression::class.java, "Use property access syntax") {
override fun isApplicableTo(element: KtCallExpression): Boolean { override fun isApplicableTo(element: KtCallExpression): Boolean {
return detectPropertyNameToUse(element) != null return detectPropertyNameToUse(element) != null
} }
@@ -65,8 +65,8 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention
} }
public fun applyTo(element: KtCallExpression, propertyName: Name): KtExpression { public fun applyTo(element: KtCallExpression, propertyName: Name): KtExpression {
val arguments = element.getValueArguments() val arguments = element.valueArguments
return when (arguments.size()) { return when (arguments.size) {
0 -> replaceWithPropertyGet(element, propertyName) 0 -> replaceWithPropertyGet(element, propertyName)
1 -> replaceWithPropertySet(element, propertyName, arguments.single()) 1 -> replaceWithPropertySet(element, propertyName, arguments.single())
else -> error("More than one argument in call to accessor") else -> error("More than one argument in call to accessor")
@@ -74,16 +74,16 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention
} }
public fun detectPropertyNameToUse(callExpression: KtCallExpression): Name? { public fun detectPropertyNameToUse(callExpression: KtCallExpression): Name? {
if (callExpression.getQualifiedExpressionForSelector()?.getReceiverExpression() is KtSuperExpression) return null // cannot call extensions on "super" if (callExpression.getQualifiedExpressionForSelector()?.receiverExpression is KtSuperExpression) return null // cannot call extensions on "super"
val callee = callExpression.getCalleeExpression() as? KtNameReferenceExpression ?: return null val callee = callExpression.calleeExpression as? KtNameReferenceExpression ?: return null
val resolutionFacade = callExpression.getResolutionFacade() val resolutionFacade = callExpression.getResolutionFacade()
val bindingContext = resolutionFacade.analyze(callExpression, BodyResolveMode.PARTIAL) val bindingContext = resolutionFacade.analyze(callExpression, BodyResolveMode.PARTIAL)
val resolvedCall = callExpression.getResolvedCall(bindingContext) ?: return null val resolvedCall = callExpression.getResolvedCall(bindingContext) ?: return null
if (!resolvedCall.isReallySuccess()) return null if (!resolvedCall.isReallySuccess()) return null
val function = resolvedCall.getResultingDescriptor() as? FunctionDescriptor ?: return null val function = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return null
val resolutionScope = callExpression.getResolutionScope(bindingContext, resolutionFacade) val resolutionScope = callExpression.getResolutionScope(bindingContext, resolutionFacade)
val property = findSyntheticProperty(function, resolutionScope) ?: return null val property = findSyntheticProperty(function, resolutionScope) ?: return null
@@ -93,7 +93,7 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention
if (!checkWillResolveToProperty(resolvedCall, property, bindingContext, resolutionScope, dataFlowInfo, expectedType, resolutionFacade)) return null if (!checkWillResolveToProperty(resolvedCall, property, bindingContext, resolutionScope, dataFlowInfo, expectedType, resolutionFacade)) return null
val isSetUsage = callExpression.valueArguments.size() == 1 val isSetUsage = callExpression.valueArguments.size == 1
if (isSetUsage && property.type != function.valueParameters.single().type) { if (isSetUsage && property.type != function.valueParameters.single().type) {
val qualifiedExpressionCopy = qualifiedExpression.copied() val qualifiedExpressionCopy = qualifiedExpression.copied()
val callExpressionCopy = ((qualifiedExpressionCopy as? KtQualifiedExpression)?.selectorExpression ?: qualifiedExpressionCopy) as KtCallExpression val callExpressionCopy = ((qualifiedExpressionCopy as? KtQualifiedExpression)?.selectorExpression ?: qualifiedExpressionCopy) as KtCallExpression
@@ -144,7 +144,7 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention
private fun findSyntheticProperty(function: FunctionDescriptor, resolutionScope: LexicalScope): SyntheticJavaPropertyDescriptor? { private fun findSyntheticProperty(function: FunctionDescriptor, resolutionScope: LexicalScope): SyntheticJavaPropertyDescriptor? {
SyntheticJavaPropertyDescriptor.findByGetterOrSetter(function, resolutionScope)?.let { return it } SyntheticJavaPropertyDescriptor.findByGetterOrSetter(function, resolutionScope)?.let { return it }
for (overridden in function.getOverriddenDescriptors()) { for (overridden in function.overriddenDescriptors) {
findSyntheticProperty(overridden, resolutionScope)?.let { return it } findSyntheticProperty(overridden, resolutionScope)?.let { return it }
} }
@@ -167,7 +167,7 @@ class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention
} }
val newExpression = KtPsiFactory(callExpression).createExpressionByPattern( val newExpression = KtPsiFactory(callExpression).createExpressionByPattern(
pattern, pattern,
qualifiedExpression.getReceiverExpression(), qualifiedExpression.receiverExpression,
propertyName, propertyName,
argument.getArgumentExpression()!! argument.getArgumentExpression()!!
) )
@@ -36,7 +36,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.KotlinType import org.jetbrains.kotlin.types.KotlinType
fun KtCallableDeclaration.setType(type: KotlinType, shortenReferences: Boolean = true) { fun KtCallableDeclaration.setType(type: KotlinType, shortenReferences: Boolean = true) {
if (type.isError()) return if (type.isError) return
setType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type), shortenReferences) setType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type), shortenReferences)
} }
@@ -49,18 +49,18 @@ fun KtCallableDeclaration.setType(typeString: String, shortenReferences: Boolean
} }
fun KtCallableDeclaration.setReceiverType(type: KotlinType) { fun KtCallableDeclaration.setReceiverType(type: KotlinType) {
if (type.isError()) return if (type.isError) return
val typeReference = KtPsiFactory(getProject()).createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type)) val typeReference = KtPsiFactory(project).createType(IdeDescriptorRenderers.SOURCE_CODE.renderType(type))
setReceiverTypeReference(typeReference) setReceiverTypeReference(typeReference)
ShortenReferences.DEFAULT.process(getReceiverTypeReference()!!) ShortenReferences.DEFAULT.process(receiverTypeReference!!)
} }
fun KtContainerNode.description(): String? { fun KtContainerNode.description(): String? {
when (getNode().getElementType()) { when (node.elementType) {
KtNodeTypes.THEN -> return "if" KtNodeTypes.THEN -> return "if"
KtNodeTypes.ELSE -> return "else" KtNodeTypes.ELSE -> return "else"
KtNodeTypes.BODY -> { KtNodeTypes.BODY -> {
when (getParent()) { when (parent) {
is KtWhileExpression -> return "while" is KtWhileExpression -> return "while"
is KtDoWhileExpression -> return "do...while" is KtDoWhileExpression -> return "do...while"
is KtForExpression -> return "for" is KtForExpression -> return "for"
@@ -79,14 +79,14 @@ fun isAutoCreatedItUsage(expression: KtNameReferenceExpression): Boolean {
// returns assignment which replaces initializer // returns assignment which replaces initializer
fun splitPropertyDeclaration(property: KtProperty): KtBinaryExpression { fun splitPropertyDeclaration(property: KtProperty): KtBinaryExpression {
val parent = property.getParent()!! val parent = property.parent!!
val initializer = property.getInitializer()!! val initializer = property.initializer!!
val explicitTypeToSet = if (property.getTypeReference() != null) null else initializer.analyze().getType(initializer) val explicitTypeToSet = if (property.typeReference != null) null else initializer.analyze().getType(initializer)
val psiFactory = KtPsiFactory(property) val psiFactory = KtPsiFactory(property)
var assignment = psiFactory.createExpressionByPattern("$0 = $1", property.getNameAsName()!!, initializer) var assignment = psiFactory.createExpressionByPattern("$0 = $1", property.nameAsName!!, initializer)
assignment = parent.addAfter(assignment, property) as KtBinaryExpression assignment = parent.addAfter(assignment, property) as KtBinaryExpression
parent.addAfter(psiFactory.createNewLine(), property) parent.addAfter(psiFactory.createNewLine(), property)
@@ -101,10 +101,10 @@ fun splitPropertyDeclaration(property: KtProperty): KtBinaryExpression {
} }
val KtQualifiedExpression.callExpression: KtCallExpression? val KtQualifiedExpression.callExpression: KtCallExpression?
get() = getSelectorExpression() as? KtCallExpression get() = selectorExpression as? KtCallExpression
val KtQualifiedExpression.calleeName: String? val KtQualifiedExpression.calleeName: String?
get() = (callExpression?.getCalleeExpression() as? KtNameReferenceExpression)?.getText() get() = (callExpression?.calleeExpression as? KtNameReferenceExpression)?.text
fun KtQualifiedExpression.toResolvedCall(bodyResolveMode: BodyResolveMode): ResolvedCall<out CallableDescriptor>? { fun KtQualifiedExpression.toResolvedCall(bodyResolveMode: BodyResolveMode): ResolvedCall<out CallableDescriptor>? {
val callExpression = callExpression ?: return null val callExpression = callExpression ?: return null
@@ -120,7 +120,7 @@ fun KtExpression.isExitStatement(): Boolean {
// returns false for call of super, static method or method from package // returns false for call of super, static method or method from package
fun KtQualifiedExpression.isReceiverExpressionWithValue(): Boolean { fun KtQualifiedExpression.isReceiverExpressionWithValue(): Boolean {
val receiver = getReceiverExpression() val receiver = receiverExpression
if (receiver is KtSuperExpression) return false if (receiver is KtSuperExpression) return false
return analyze().getType(receiver) != null return analyze().getType(receiver) != null
} }
@@ -135,8 +135,8 @@ private fun KtExpression.specialNegation(): KtExpression? {
val factory = KtPsiFactory(this) val factory = KtPsiFactory(this)
when (this) { when (this) {
is KtPrefixExpression -> { is KtPrefixExpression -> {
if (getOperationReference().getReferencedName() == "!") { if (operationReference.getReferencedName() == "!") {
val baseExpression = getBaseExpression() val baseExpression = baseExpression
if (baseExpression != null) { if (baseExpression != null) {
val context = baseExpression.analyzeAndGetResult().bindingContext val context = baseExpression.analyzeAndGetResult().bindingContext
val type = context.getType(baseExpression) val type = context.getType(baseExpression)
@@ -148,15 +148,15 @@ private fun KtExpression.specialNegation(): KtExpression? {
} }
is KtBinaryExpression -> { is KtBinaryExpression -> {
val operator = getOperationToken() val operator = operationToken
if (operator !in NEGATABLE_OPERATORS) return null if (operator !in NEGATABLE_OPERATORS) return null
val left = getLeft() ?: return null val left = left ?: return null
val right = getRight() ?: return null val right = right ?: return null
return factory.createExpressionByPattern("$0 $1 $2", left, getNegatedOperatorText(operator), right) return factory.createExpressionByPattern("$0 $1 $2", left, getNegatedOperatorText(operator), right)
} }
is KtConstantExpression -> { is KtConstantExpression -> {
return when (getText()) { return when (text) {
"true" -> factory.createExpression("false") "true" -> factory.createExpression("false")
"false" -> factory.createExpression("true") "false" -> factory.createExpression("true")
else -> null else -> null
@@ -172,18 +172,18 @@ private val NEGATABLE_OPERATORS = setOf(KtTokens.EQEQ, KtTokens.EXCLEQ, KtTokens
private fun getNegatedOperatorText(token: IElementType): String { private fun getNegatedOperatorText(token: IElementType): String {
return when(token) { return when(token) {
KtTokens.EQEQ -> KtTokens.EXCLEQ.getValue() KtTokens.EQEQ -> KtTokens.EXCLEQ.value
KtTokens.EXCLEQ -> KtTokens.EQEQ.getValue() KtTokens.EXCLEQ -> KtTokens.EQEQ.value
KtTokens.EQEQEQ -> KtTokens.EXCLEQEQEQ.getValue() KtTokens.EQEQEQ -> KtTokens.EXCLEQEQEQ.value
KtTokens.EXCLEQEQEQ -> KtTokens.EQEQEQ.getValue() KtTokens.EXCLEQEQEQ -> KtTokens.EQEQEQ.value
KtTokens.IS_KEYWORD -> KtTokens.NOT_IS.getValue() KtTokens.IS_KEYWORD -> KtTokens.NOT_IS.value
KtTokens.NOT_IS -> KtTokens.IS_KEYWORD.getValue() KtTokens.NOT_IS -> KtTokens.IS_KEYWORD.value
KtTokens.IN_KEYWORD -> KtTokens.NOT_IN.getValue() KtTokens.IN_KEYWORD -> KtTokens.NOT_IN.value
KtTokens.NOT_IN -> KtTokens.IN_KEYWORD.getValue() KtTokens.NOT_IN -> KtTokens.IN_KEYWORD.value
KtTokens.LT -> KtTokens.GTEQ.getValue() KtTokens.LT -> KtTokens.GTEQ.value
KtTokens.LTEQ -> KtTokens.GT.getValue() KtTokens.LTEQ -> KtTokens.GT.value
KtTokens.GT -> KtTokens.LTEQ.getValue() KtTokens.GT -> KtTokens.LTEQ.value
KtTokens.GTEQ -> KtTokens.LT.getValue() KtTokens.GTEQ -> KtTokens.LT.value
else -> throw IllegalArgumentException("The token $token does not have a negated equivalent.") else -> throw IllegalArgumentException("The token $token does not have a negated equivalent.")
} }
} }
@@ -24,14 +24,14 @@ import org.jetbrains.kotlin.utils.addToStdlib.check
object BranchedFoldingUtils { object BranchedFoldingUtils {
public fun getFoldableBranchedAssignment(branch: KtExpression?): KtBinaryExpression? { public fun getFoldableBranchedAssignment(branch: KtExpression?): KtBinaryExpression? {
fun checkAssignment(expression: KtBinaryExpression): Boolean { fun checkAssignment(expression: KtBinaryExpression): Boolean {
if (expression.getOperationToken() !in KtTokens.ALL_ASSIGNMENTS) return false if (expression.operationToken !in KtTokens.ALL_ASSIGNMENTS) return false
val left = expression.getLeft() as? KtNameReferenceExpression ?: return false val left = expression.left as? KtNameReferenceExpression ?: return false
if (expression.getRight() == null) return false if (expression.right == null) return false
val parent = expression.getParent() val parent = expression.parent
if (parent is KtBlockExpression) { if (parent is KtBlockExpression) {
return !KtPsiUtil.checkVariableDeclarationInBlock(parent, left.getText()) return !KtPsiUtil.checkVariableDeclarationInBlock(parent, left.text)
} }
return true return true
@@ -40,10 +40,10 @@ object BranchedFoldingUtils {
} }
public fun getFoldableBranchedReturn(branch: KtExpression?): KtReturnExpression? { public fun getFoldableBranchedReturn(branch: KtExpression?): KtReturnExpression? {
return (branch?.lastBlockStatementOrThis() as? KtReturnExpression)?.check { it.getReturnedExpression() != null } return (branch?.lastBlockStatementOrThis() as? KtReturnExpression)?.check { it.returnedExpression != null }
} }
public fun checkAssignmentsMatch(a1: KtBinaryExpression, a2: KtBinaryExpression): Boolean { public fun checkAssignmentsMatch(a1: KtBinaryExpression, a2: KtBinaryExpression): Boolean {
return a1.getLeft()?.getText() == a2.getLeft()?.getText() && a1.getOperationToken() == a2.getOperationToken() return a1.left?.text == a2.left?.text && a1.operationToken == a2.operationToken
} }
} }
@@ -23,14 +23,14 @@ import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
public object BranchedUnfoldingUtils { public object BranchedUnfoldingUtils {
public fun unfoldAssignmentToIf(assignment: KtBinaryExpression, editor: Editor) { public fun unfoldAssignmentToIf(assignment: KtBinaryExpression, editor: Editor) {
val op = assignment.getOperationReference().getText() val op = assignment.operationReference.text
val left = assignment.getLeft()!! val left = assignment.left!!
val ifExpression = assignment.getRight() as KtIfExpression val ifExpression = assignment.right as KtIfExpression
val newIfExpression = ifExpression.copied() val newIfExpression = ifExpression.copied()
val thenExpr = newIfExpression.getThen()!!.lastBlockStatementOrThis() val thenExpr = newIfExpression.then!!.lastBlockStatementOrThis()
val elseExpr = newIfExpression.getElse()!!.lastBlockStatementOrThis() val elseExpr = newIfExpression.`else`!!.lastBlockStatementOrThis()
val psiFactory = KtPsiFactory(assignment) val psiFactory = KtPsiFactory(assignment)
thenExpr.replace(psiFactory.createExpressionByPattern("$0 $1 $2", left, op, thenExpr)) thenExpr.replace(psiFactory.createExpressionByPattern("$0 $1 $2", left, op, thenExpr))
@@ -38,23 +38,23 @@ public object BranchedUnfoldingUtils {
val resultIf = assignment.replace(newIfExpression) val resultIf = assignment.replace(newIfExpression)
editor.getCaretModel().moveToOffset(resultIf.getTextOffset()) editor.caretModel.moveToOffset(resultIf.textOffset)
} }
public fun unfoldAssignmentToWhen(assignment: KtBinaryExpression, editor: Editor) { public fun unfoldAssignmentToWhen(assignment: KtBinaryExpression, editor: Editor) {
val op = assignment.getOperationReference().getText() val op = assignment.operationReference.text
val left = assignment.getLeft()!! val left = assignment.left!!
val whenExpression = assignment.getRight() as KtWhenExpression val whenExpression = assignment.right as KtWhenExpression
val newWhenExpression = whenExpression.copied() val newWhenExpression = whenExpression.copied()
for (entry in newWhenExpression.getEntries()) { for (entry in newWhenExpression.entries) {
val expr = entry.getExpression()!!.lastBlockStatementOrThis() val expr = entry.expression!!.lastBlockStatementOrThis()
expr.replace(KtPsiFactory(assignment).createExpressionByPattern("$0 $1 $2", left, op, expr)) expr.replace(KtPsiFactory(assignment).createExpressionByPattern("$0 $1 $2", left, op, expr))
} }
val resultWhen = assignment.replace(newWhenExpression) val resultWhen = assignment.replace(newWhenExpression)
editor.getCaretModel().moveToOffset(resultWhen.getTextOffset()) editor.caretModel.moveToOffset(resultWhen.textOffset)
} }
} }
@@ -38,11 +38,11 @@ val NULL_PTR_EXCEPTION_FQ = "java.lang.NullPointerException"
val KOTLIN_NULL_PTR_EXCEPTION_FQ = "kotlin.KotlinNullPointerException" val KOTLIN_NULL_PTR_EXCEPTION_FQ = "kotlin.KotlinNullPointerException"
fun KtBinaryExpression.expressionComparedToNull(): KtExpression? { fun KtBinaryExpression.expressionComparedToNull(): KtExpression? {
val operationToken = this.getOperationToken() val operationToken = this.operationToken
if (operationToken != KtTokens.EQEQ && operationToken != KtTokens.EXCLEQ) return null if (operationToken != KtTokens.EQEQ && operationToken != KtTokens.EXCLEQ) return null
val right = this.getRight() ?: return null val right = this.right ?: return null
val left = this.getLeft() ?: return null val left = this.left ?: return null
val rightIsNull = right.isNullExpression() val rightIsNull = right.isNullExpression()
val leftIsNull = left.isNullExpression() val leftIsNull = left.isNullExpression()
@@ -53,31 +53,31 @@ fun KtBinaryExpression.expressionComparedToNull(): KtExpression? {
fun KtExpression.unwrapBlockOrParenthesis(): KtExpression { fun KtExpression.unwrapBlockOrParenthesis(): KtExpression {
val innerExpression = KtPsiUtil.safeDeparenthesize(this) val innerExpression = KtPsiUtil.safeDeparenthesize(this)
if (innerExpression is KtBlockExpression) { if (innerExpression is KtBlockExpression) {
val statement = innerExpression.getStatements().singleOrNull() ?: return this val statement = innerExpression.statements.singleOrNull() ?: return this
return KtPsiUtil.safeDeparenthesize(statement) return KtPsiUtil.safeDeparenthesize(statement)
} }
return innerExpression return innerExpression
} }
fun KtExpression?.isNullExpression(): Boolean = this?.unwrapBlockOrParenthesis()?.getNode()?.getElementType() == KtNodeTypes.NULL fun KtExpression?.isNullExpression(): Boolean = this?.unwrapBlockOrParenthesis()?.node?.elementType == KtNodeTypes.NULL
fun KtExpression?.isNullExpressionOrEmptyBlock(): Boolean = this.isNullExpression() || this is KtBlockExpression && this.getStatements().isEmpty() fun KtExpression?.isNullExpressionOrEmptyBlock(): Boolean = this.isNullExpression() || this is KtBlockExpression && this.statements.isEmpty()
fun KtThrowExpression.throwsNullPointerExceptionWithNoArguments(): Boolean { fun KtThrowExpression.throwsNullPointerExceptionWithNoArguments(): Boolean {
val thrownExpression = this.getThrownExpression() val thrownExpression = this.thrownExpression
if (thrownExpression !is KtCallExpression) return false if (thrownExpression !is KtCallExpression) return false
val context = this.analyze(BodyResolveMode.PARTIAL) val context = this.analyze(BodyResolveMode.PARTIAL)
val nameExpression = thrownExpression.calleeExpression as? KtNameReferenceExpression ?: return false val nameExpression = thrownExpression.calleeExpression as? KtNameReferenceExpression ?: return false
val descriptor = context[BindingContext.REFERENCE_TARGET, nameExpression] val descriptor = context[BindingContext.REFERENCE_TARGET, nameExpression]
val declDescriptor = descriptor?.getContainingDeclaration() ?: return false val declDescriptor = descriptor?.containingDeclaration ?: return false
val exceptionName = DescriptorUtils.getFqName(declDescriptor).asString() val exceptionName = DescriptorUtils.getFqName(declDescriptor).asString()
return (exceptionName == NULL_PTR_EXCEPTION_FQ || exceptionName == KOTLIN_NULL_PTR_EXCEPTION_FQ) && thrownExpression.getValueArguments().isEmpty() return (exceptionName == NULL_PTR_EXCEPTION_FQ || exceptionName == KOTLIN_NULL_PTR_EXCEPTION_FQ) && thrownExpression.valueArguments.isEmpty()
} }
fun KtExpression.evaluatesTo(other: KtExpression): Boolean { fun KtExpression.evaluatesTo(other: KtExpression): Boolean {
return this.unwrapBlockOrParenthesis().getText() == other.getText() return this.unwrapBlockOrParenthesis().text == other.text
} }
fun KtExpression.convertToIfNotNullExpression(conditionLhs: KtExpression, thenClause: KtExpression, elseClause: KtExpression?): KtIfExpression { fun KtExpression.convertToIfNotNullExpression(conditionLhs: KtExpression, thenClause: KtExpression, elseClause: KtExpression?): KtIfExpression {
@@ -95,8 +95,8 @@ fun KtExpression.convertToIfStatement(condition: KtExpression, thenClause: KtExp
} }
fun KtIfExpression.introduceValueForCondition(occurrenceInThenClause: KtExpression, editor: Editor) { fun KtIfExpression.introduceValueForCondition(occurrenceInThenClause: KtExpression, editor: Editor) {
val project = this.getProject() val project = this.project
val occurrenceInConditional = (this.getCondition() as KtBinaryExpression).getLeft()!! val occurrenceInConditional = (this.condition as KtBinaryExpression).left!!
KotlinIntroduceVariableHandler.doRefactoring(project, KotlinIntroduceVariableHandler.doRefactoring(project,
editor, editor,
occurrenceInConditional, occurrenceInConditional,
@@ -114,21 +114,21 @@ fun KtNameReferenceExpression.inlineIfDeclaredLocallyAndOnlyUsedOnceWithPrompt(e
val scope = LocalSearchScope(enclosingElement!!) val scope = LocalSearchScope(enclosingElement!!)
val references = ReferencesSearch.search(declaration, scope).findAll() val references = ReferencesSearch.search(declaration, scope).findAll()
if (references.size() == 1) { if (references.size == 1) {
KotlinInlineValHandler().inlineElement(this.getProject(), editor, declaration) KotlinInlineValHandler().inlineElement(this.project, editor, declaration)
} }
} }
fun KtSafeQualifiedExpression.inlineReceiverIfApplicableWithPrompt(editor: Editor) { fun KtSafeQualifiedExpression.inlineReceiverIfApplicableWithPrompt(editor: Editor) {
(this.getReceiverExpression() as? KtNameReferenceExpression)?.inlineIfDeclaredLocallyAndOnlyUsedOnceWithPrompt(editor) (this.receiverExpression as? KtNameReferenceExpression)?.inlineIfDeclaredLocallyAndOnlyUsedOnceWithPrompt(editor)
} }
fun KtBinaryExpression.inlineLeftSideIfApplicableWithPrompt(editor: Editor) { fun KtBinaryExpression.inlineLeftSideIfApplicableWithPrompt(editor: Editor) {
(this.getLeft() as? KtNameReferenceExpression)?.inlineIfDeclaredLocallyAndOnlyUsedOnceWithPrompt(editor) (this.left as? KtNameReferenceExpression)?.inlineIfDeclaredLocallyAndOnlyUsedOnceWithPrompt(editor)
} }
fun KtPostfixExpression.inlineBaseExpressionIfApplicableWithPrompt(editor: Editor) { fun KtPostfixExpression.inlineBaseExpressionIfApplicableWithPrompt(editor: Editor) {
(this.getBaseExpression() as? KtNameReferenceExpression)?.inlineIfDeclaredLocallyAndOnlyUsedOnceWithPrompt(editor) (this.baseExpression as? KtNameReferenceExpression)?.inlineIfDeclaredLocallyAndOnlyUsedOnceWithPrompt(editor)
} }
fun KtExpression.isStableVariable(): Boolean { fun KtExpression.isStableVariable(): Boolean {
@@ -25,21 +25,21 @@ fun KtWhenCondition.toExpression(subject: KtExpression?): KtExpression {
val factory = KtPsiFactory(this) val factory = KtPsiFactory(this)
when (this) { when (this) {
is KtWhenConditionIsPattern -> { is KtWhenConditionIsPattern -> {
val op = if (isNegated()) "!is" else "is" val op = if (isNegated) "!is" else "is"
return factory.createExpressionByPattern("$0 $op $1", subject ?: "_", getTypeReference() ?: "") return factory.createExpressionByPattern("$0 $op $1", subject ?: "_", typeReference ?: "")
} }
is KtWhenConditionInRange -> { is KtWhenConditionInRange -> {
val op = getOperationReference().getText() val op = operationReference.text
return factory.createExpressionByPattern("$0 $op $1", subject ?: "_", getRangeExpression() ?: "") return factory.createExpressionByPattern("$0 $op $1", subject ?: "_", rangeExpression ?: "")
} }
is KtWhenConditionWithExpression -> { is KtWhenConditionWithExpression -> {
return if (subject != null) { return if (subject != null) {
factory.createExpressionByPattern("$0 == $1", subject, getExpression() ?: "") factory.createExpressionByPattern("$0 == $1", subject, expression ?: "")
} }
else { else {
getExpression()!! expression!!
} }
} }
@@ -48,17 +48,17 @@ fun KtWhenCondition.toExpression(subject: KtExpression?): KtExpression {
} }
public fun KtWhenExpression.getSubjectToIntroduce(): KtExpression? { public fun KtWhenExpression.getSubjectToIntroduce(): KtExpression? {
if (getSubjectExpression() != null) return null if (subjectExpression != null) return null
var lastCandidate: KtExpression? = null var lastCandidate: KtExpression? = null
for (entry in getEntries()) { for (entry in entries) {
val conditions = entry.getConditions() val conditions = entry.conditions
if (!entry.isElse() && conditions.isEmpty()) return null if (!entry.isElse && conditions.isEmpty()) return null
for (condition in conditions) { for (condition in conditions) {
if (condition !is KtWhenConditionWithExpression) return null if (condition !is KtWhenConditionWithExpression) return null
val candidate = condition.getExpression()?.getWhenConditionSubjectCandidate() as? KtNameReferenceExpression ?: return null val candidate = condition.expression?.getWhenConditionSubjectCandidate() as? KtNameReferenceExpression ?: return null
if (lastCandidate == null) { if (lastCandidate == null) {
lastCandidate = candidate lastCandidate = candidate
@@ -75,14 +75,14 @@ public fun KtWhenExpression.getSubjectToIntroduce(): KtExpression? {
private fun KtExpression?.getWhenConditionSubjectCandidate(): KtExpression? { private fun KtExpression?.getWhenConditionSubjectCandidate(): KtExpression? {
return when(this) { return when(this) {
is KtIsExpression -> getLeftHandSide() is KtIsExpression -> leftHandSide
is KtBinaryExpression -> { is KtBinaryExpression -> {
val lhs = getLeft() val lhs = left
val op = getOperationToken() val op = operationToken
when (op) { when (op) {
KtTokens.IN_KEYWORD, KtTokens.NOT_IN -> lhs KtTokens.IN_KEYWORD, KtTokens.NOT_IN -> lhs
KtTokens.EQEQ -> lhs as? KtNameReferenceExpression ?: getRight() KtTokens.EQEQ -> lhs as? KtNameReferenceExpression ?: right
KtTokens.OROR -> { KtTokens.OROR -> {
val leftCandidate = lhs.getWhenConditionSubjectCandidate() val leftCandidate = lhs.getWhenConditionSubjectCandidate()
val rightCandidate = right.getWhenConditionSubjectCandidate() val rightCandidate = right.getWhenConditionSubjectCandidate()
@@ -103,17 +103,17 @@ public fun KtWhenExpression.introduceSubject(): KtWhenExpression {
val whenExpression = KtPsiFactory(this).buildExpression { val whenExpression = KtPsiFactory(this).buildExpression {
appendFixedText("when(").appendExpression(subject).appendFixedText("){\n") appendFixedText("when(").appendExpression(subject).appendFixedText("){\n")
for (entry in getEntries()) { for (entry in entries) {
val branchExpression = entry.getExpression() val branchExpression = entry.expression
if (entry.isElse()) { if (entry.isElse) {
appendFixedText("else") appendFixedText("else")
} }
else { else {
for ((i, condition) in entry.getConditions().withIndex()) { for ((i, condition) in entry.conditions.withIndex()) {
if (i > 0) appendFixedText(",") if (i > 0) appendFixedText(",")
val conditionExpression = (condition as KtWhenConditionWithExpression).getExpression() val conditionExpression = (condition as KtWhenConditionWithExpression).expression
appendConditionWithSubjectRemoved(conditionExpression, subject) appendConditionWithSubjectRemoved(conditionExpression, subject)
} }
} }
@@ -132,17 +132,17 @@ public fun KtWhenExpression.introduceSubject(): KtWhenExpression {
private fun BuilderByPattern<KtExpression>.appendConditionWithSubjectRemoved(conditionExpression: KtExpression?, subject: KtExpression) { private fun BuilderByPattern<KtExpression>.appendConditionWithSubjectRemoved(conditionExpression: KtExpression?, subject: KtExpression) {
when (conditionExpression) { when (conditionExpression) {
is KtIsExpression -> { is KtIsExpression -> {
if (conditionExpression.isNegated()) { if (conditionExpression.isNegated) {
appendFixedText("!") appendFixedText("!")
} }
appendFixedText("is ") appendFixedText("is ")
appendNonFormattedText(conditionExpression.getTypeReference()?.getText() ?: "") appendNonFormattedText(conditionExpression.typeReference?.text ?: "")
} }
is KtBinaryExpression -> { is KtBinaryExpression -> {
val lhs = conditionExpression.getLeft() val lhs = conditionExpression.left
val rhs = conditionExpression.getRight() val rhs = conditionExpression.right
val op = conditionExpression.getOperationToken() val op = conditionExpression.operationToken
when (op) { when (op) {
KtTokens.IN_KEYWORD -> appendFixedText("in ").appendExpression(rhs) KtTokens.IN_KEYWORD -> appendFixedText("in ").appendExpression(rhs)
KtTokens.NOT_IN -> appendFixedText("!in ").appendExpression(rhs) KtTokens.NOT_IN -> appendFixedText("!in ").appendExpression(rhs)
@@ -39,17 +39,17 @@ import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.KtThrowExpression import org.jetbrains.kotlin.psi.KtThrowExpression
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
public class DoubleBangToIfThenIntention : SelfTargetingRangeIntention<KtPostfixExpression>(javaClass(), "Replace '!!' expression with 'if' expression"), LowPriorityAction { public class DoubleBangToIfThenIntention : SelfTargetingRangeIntention<KtPostfixExpression>(KtPostfixExpression::class.java, "Replace '!!' expression with 'if' expression"), LowPriorityAction {
override fun applicabilityRange(element: KtPostfixExpression): TextRange? { override fun applicabilityRange(element: KtPostfixExpression): TextRange? {
return if (element.getOperationToken() == KtTokens.EXCLEXCL && element.getBaseExpression() != null) return if (element.operationToken == KtTokens.EXCLEXCL && element.baseExpression != null)
element.getOperationReference().getTextRange() element.operationReference.textRange
else else
null null
} }
override fun applyTo(element: KtPostfixExpression, editor: Editor) { override fun applyTo(element: KtPostfixExpression, editor: Editor) {
val base = KtPsiUtil.safeDeparenthesize(element.getBaseExpression()!!) val base = KtPsiUtil.safeDeparenthesize(element.baseExpression!!)
val expressionText = formatForUseInExceptionArgument(base.getText()!!) val expressionText = formatForUseInExceptionArgument(base.text!!)
val defaultException = KtPsiFactory(element).createExpression("throw NullPointerException()") val defaultException = KtPsiFactory(element).createExpression("throw NullPointerException()")
@@ -62,25 +62,25 @@ public class DoubleBangToIfThenIntention : SelfTargetingRangeIntention<KtPostfix
element.convertToIfNotNullExpression(base, base, defaultException) element.convertToIfNotNullExpression(base, base, defaultException)
val thrownExpression = val thrownExpression =
((if (isStatement) ifStatement.getThen() else ifStatement.getElse()) as KtThrowExpression).getThrownExpression()!! ((if (isStatement) ifStatement.then else ifStatement.`else`) as KtThrowExpression).thrownExpression!!
val message = escapeJava("Expression '$expressionText' must not be null") val message = escapeJava("Expression '$expressionText' must not be null")
val nullPtrExceptionText = "NullPointerException(\"$message\")" val nullPtrExceptionText = "NullPointerException(\"$message\")"
val kotlinNullPtrExceptionText = "KotlinNullPointerException()" val kotlinNullPtrExceptionText = "KotlinNullPointerException()"
val exceptionLookupExpression = ChooseStringExpression(listOf(nullPtrExceptionText, kotlinNullPtrExceptionText)) val exceptionLookupExpression = ChooseStringExpression(listOf(nullPtrExceptionText, kotlinNullPtrExceptionText))
val project = element.getProject() val project = element.project
val builder = TemplateBuilderImpl(thrownExpression) val builder = TemplateBuilderImpl(thrownExpression)
builder.replaceElement(thrownExpression, exceptionLookupExpression); builder.replaceElement(thrownExpression, exceptionLookupExpression);
PsiDocumentManager.getInstance(project).commitAllDocuments(); PsiDocumentManager.getInstance(project).commitAllDocuments();
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()); PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document);
editor.getCaretModel().moveToOffset(thrownExpression.getNode()!!.getStartOffset()); editor.caretModel.moveToOffset(thrownExpression.node!!.startOffset);
TemplateManager.getInstance(project).startTemplate(editor, builder.buildInlineTemplate(), object: TemplateEditingAdapter() { TemplateManager.getInstance(project).startTemplate(editor, builder.buildInlineTemplate(), object: TemplateEditingAdapter() {
override fun templateFinished(template: Template?, brokenOff: Boolean) { override fun templateFinished(template: Template?, brokenOff: Boolean) {
if (!isStable && !isStatement) { if (!isStable && !isStatement) {
ifStatement.introduceValueForCondition(ifStatement.getThen()!!, editor) ifStatement.introduceValueForCondition(ifStatement.then!!, editor)
} }
} }
}) })
@@ -88,7 +88,7 @@ public class DoubleBangToIfThenIntention : SelfTargetingRangeIntention<KtPostfix
private fun formatForUseInExceptionArgument(expressionText: String): String { private fun formatForUseInExceptionArgument(expressionText: String): String {
val lines = expressionText.split('\n') val lines = expressionText.split('\n')
return if (lines.size() > 1) return if (lines.size > 1)
lines.first().trim() + " ..." lines.first().trim() + " ..."
else else
expressionText.trim() expressionText.trim()
@@ -26,23 +26,23 @@ import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.psi.buildExpression import org.jetbrains.kotlin.psi.buildExpression
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
public class EliminateWhenSubjectIntention : SelfTargetingIntention<KtWhenExpression>(javaClass(), "Eliminate argument of 'when'"), LowPriorityAction { public class EliminateWhenSubjectIntention : SelfTargetingIntention<KtWhenExpression>(KtWhenExpression::class.java, "Eliminate argument of 'when'"), LowPriorityAction {
override fun isApplicableTo(element: KtWhenExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtWhenExpression, caretOffset: Int): Boolean {
if (element.getSubjectExpression() !is KtNameReferenceExpression) return false if (element.subjectExpression !is KtNameReferenceExpression) return false
val lBrace = element.getOpenBrace() ?: return false val lBrace = element.openBrace ?: return false
return caretOffset <= lBrace.startOffset return caretOffset <= lBrace.startOffset
} }
override fun applyTo(element: KtWhenExpression, editor: Editor) { override fun applyTo(element: KtWhenExpression, editor: Editor) {
val subject = element.getSubjectExpression()!! val subject = element.subjectExpression!!
val whenExpression = KtPsiFactory(element).buildExpression { val whenExpression = KtPsiFactory(element).buildExpression {
appendFixedText("when {\n") appendFixedText("when {\n")
for (entry in element.getEntries()) { for (entry in element.entries) {
val branchExpression = entry.getExpression() val branchExpression = entry.expression
if (entry.isElse()) { if (entry.isElse) {
appendFixedText("else") appendFixedText("else")
} }
else { else {
@@ -27,24 +27,24 @@ import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.psi.KtPsiUtil
public class ElvisToIfThenIntention : SelfTargetingRangeIntention<KtBinaryExpression>(javaClass(), "Replace elvis expression with 'if' expression"), LowPriorityAction { public class ElvisToIfThenIntention : SelfTargetingRangeIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Replace elvis expression with 'if' expression"), LowPriorityAction {
override fun applicabilityRange(element: KtBinaryExpression): TextRange? { override fun applicabilityRange(element: KtBinaryExpression): TextRange? {
return if (element.getOperationToken() == KtTokens.ELVIS && element.getLeft() != null && element.getRight() != null) return if (element.operationToken == KtTokens.ELVIS && element.left != null && element.right != null)
element.getOperationReference().getTextRange() element.operationReference.textRange
else else
null null
} }
override fun applyTo(element: KtBinaryExpression, editor: Editor) { override fun applyTo(element: KtBinaryExpression, editor: Editor) {
val left = KtPsiUtil.safeDeparenthesize(element.getLeft()!!) val left = KtPsiUtil.safeDeparenthesize(element.left!!)
val right = KtPsiUtil.safeDeparenthesize(element.getRight()!!) val right = KtPsiUtil.safeDeparenthesize(element.right!!)
val leftIsStable = left.isStableVariable() val leftIsStable = left.isStableVariable()
val ifStatement = element.convertToIfNotNullExpression(left, left, right) val ifStatement = element.convertToIfNotNullExpression(left, left, right)
if (!leftIsStable) { if (!leftIsStable) {
ifStatement.introduceValueForCondition(ifStatement.getThen()!!, editor) ifStatement.introduceValueForCondition(ifStatement.then!!, editor)
} }
} }
@@ -25,29 +25,29 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
public class FlattenWhenIntention : SelfTargetingIntention<KtWhenExpression>(javaClass(), "Flatten 'when' expression") { public class FlattenWhenIntention : SelfTargetingIntention<KtWhenExpression>(KtWhenExpression::class.java, "Flatten 'when' expression") {
override fun isApplicableTo(element: KtWhenExpression, caretOffset: Int): Boolean { override fun isApplicableTo(element: KtWhenExpression, caretOffset: Int): Boolean {
val subject = element.getSubjectExpression() val subject = element.subjectExpression
if (subject != null && subject !is KtNameReferenceExpression) return false if (subject != null && subject !is KtNameReferenceExpression) return false
if (!KtPsiUtil.checkWhenExpressionHasSingleElse(element)) return false if (!KtPsiUtil.checkWhenExpressionHasSingleElse(element)) return false
val elseEntry = element.getEntries().singleOrNull { it.isElse() } ?: return false val elseEntry = element.entries.singleOrNull { it.isElse } ?: return false
val innerWhen = elseEntry.getExpression() as? KtWhenExpression ?: return false val innerWhen = elseEntry.expression as? KtWhenExpression ?: return false
if (!subject.matches(innerWhen.getSubjectExpression())) return false if (!subject.matches(innerWhen.subjectExpression)) return false
if (!KtPsiUtil.checkWhenExpressionHasSingleElse(innerWhen)) return false if (!KtPsiUtil.checkWhenExpressionHasSingleElse(innerWhen)) return false
return elseEntry.startOffset <= caretOffset && caretOffset <= innerWhen.getWhenKeyword().endOffset return elseEntry.startOffset <= caretOffset && caretOffset <= innerWhen.whenKeyword.endOffset
} }
override fun applyTo(element: KtWhenExpression, editor: Editor) { override fun applyTo(element: KtWhenExpression, editor: Editor) {
val subjectExpression = element.getSubjectExpression() val subjectExpression = element.subjectExpression
val nestedWhen = element.getElseExpression() as KtWhenExpression val nestedWhen = element.elseExpression as KtWhenExpression
val outerEntries = element.getEntries() val outerEntries = element.entries
val innerEntries = nestedWhen.getEntries() val innerEntries = nestedWhen.entries
val whenExpression = KtPsiFactory(element).buildExpression { val whenExpression = KtPsiFactory(element).buildExpression {
appendFixedText("when") appendFixedText("when")
@@ -57,12 +57,12 @@ public class FlattenWhenIntention : SelfTargetingIntention<KtWhenExpression>(jav
appendFixedText("{\n") appendFixedText("{\n")
for (entry in outerEntries) { for (entry in outerEntries) {
if (entry.isElse()) continue if (entry.isElse) continue
appendNonFormattedText(entry.getText()) appendNonFormattedText(entry.text)
appendFixedText("\n") appendFixedText("\n")
} }
for (entry in innerEntries) { for (entry in innerEntries) {
appendNonFormattedText(entry.getText()) appendNonFormattedText(entry.text)
appendFixedText("\n") appendFixedText("\n")
} }
@@ -71,7 +71,7 @@ public class FlattenWhenIntention : SelfTargetingIntention<KtWhenExpression>(jav
val newWhen = element.replaced(whenExpression) val newWhen = element.replaced(whenExpression)
val firstNewEntry = newWhen.getEntries()[outerEntries.size() - 1] val firstNewEntry = newWhen.entries[outerEntries.size - 1]
editor.moveCaret(firstNewEntry.getTextOffset()) editor.moveCaret(firstNewEntry.textOffset)
} }
} }
@@ -24,23 +24,23 @@ import org.jetbrains.kotlin.psi.KtIfExpression
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.createExpressionByPattern import org.jetbrains.kotlin.psi.createExpressionByPattern
public class FoldIfToAssignmentIntention : SelfTargetingRangeIntention<KtIfExpression>(javaClass(), "Replace 'if' expression with assignment") { public class FoldIfToAssignmentIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' expression with assignment") {
override fun applicabilityRange(element: KtIfExpression): TextRange? { override fun applicabilityRange(element: KtIfExpression): TextRange? {
val thenAssignment = BranchedFoldingUtils.getFoldableBranchedAssignment(element.getThen()) ?: return null val thenAssignment = BranchedFoldingUtils.getFoldableBranchedAssignment(element.then) ?: return null
val elseAssignment = BranchedFoldingUtils.getFoldableBranchedAssignment(element.getElse()) ?: return null val elseAssignment = BranchedFoldingUtils.getFoldableBranchedAssignment(element.`else`) ?: return null
if (!BranchedFoldingUtils.checkAssignmentsMatch(thenAssignment, elseAssignment)) return null if (!BranchedFoldingUtils.checkAssignmentsMatch(thenAssignment, elseAssignment)) return null
return element.getIfKeyword().getTextRange() return element.ifKeyword.textRange
} }
override fun applyTo(element: KtIfExpression, editor: Editor) { override fun applyTo(element: KtIfExpression, editor: Editor) {
var thenAssignment = BranchedFoldingUtils.getFoldableBranchedAssignment(element.getThen()!!)!! var thenAssignment = BranchedFoldingUtils.getFoldableBranchedAssignment(element.then!!)!!
val elseAssignment = BranchedFoldingUtils.getFoldableBranchedAssignment(element.getElse()!!)!! val elseAssignment = BranchedFoldingUtils.getFoldableBranchedAssignment(element.`else`!!)!!
val op = thenAssignment.getOperationReference().getText() val op = thenAssignment.operationReference.text
val leftText = thenAssignment.getLeft()!!.getText() val leftText = thenAssignment.left!!.text
thenAssignment.replace(thenAssignment.getRight()!!) thenAssignment.replace(thenAssignment.right!!)
elseAssignment.replace(elseAssignment.getRight()!!) elseAssignment.replace(elseAssignment.right!!)
element.replace(KtPsiFactory(element).createExpressionByPattern("$0 $1 $2", leftText, op, element)) element.replace(KtPsiFactory(element).createExpressionByPattern("$0 $1 $2", leftText, op, element))
} }
@@ -22,30 +22,30 @@ import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.BranchedFoldingUtils import org.jetbrains.kotlin.idea.intentions.branchedTransformations.BranchedFoldingUtils
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
public class FoldIfToReturnAsymmetricallyIntention : SelfTargetingRangeIntention<KtIfExpression>(javaClass(), "Replace 'if' expression with return") { public class FoldIfToReturnAsymmetricallyIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' expression with return") {
override fun applicabilityRange(element: KtIfExpression): TextRange? { override fun applicabilityRange(element: KtIfExpression): TextRange? {
if (BranchedFoldingUtils.getFoldableBranchedReturn(element.getThen()) == null || element.getElse() != null) { if (BranchedFoldingUtils.getFoldableBranchedReturn(element.then) == null || element.`else` != null) {
return null return null
} }
val nextElement = KtPsiUtil.skipTrailingWhitespacesAndComments(element) as? KtReturnExpression val nextElement = KtPsiUtil.skipTrailingWhitespacesAndComments(element) as? KtReturnExpression
if (nextElement?.getReturnedExpression() == null) return null if (nextElement?.returnedExpression == null) return null
return element.getIfKeyword().getTextRange() return element.ifKeyword.textRange
} }
override fun applyTo(element: KtIfExpression, editor: Editor) { override fun applyTo(element: KtIfExpression, editor: Editor) {
val condition = element.getCondition()!! val condition = element.condition!!
val thenBranch = element.getThen()!! val thenBranch = element.then!!
val elseBranch = KtPsiUtil.skipTrailingWhitespacesAndComments(element) as KtReturnExpression val elseBranch = KtPsiUtil.skipTrailingWhitespacesAndComments(element) as KtReturnExpression
val psiFactory = KtPsiFactory(element) val psiFactory = KtPsiFactory(element)
var newIfExpression = psiFactory.createIf(condition, thenBranch, elseBranch) var newIfExpression = psiFactory.createIf(condition, thenBranch, elseBranch)
val thenReturn = BranchedFoldingUtils.getFoldableBranchedReturn(newIfExpression.getThen()!!)!! val thenReturn = BranchedFoldingUtils.getFoldableBranchedReturn(newIfExpression.then!!)!!
val elseReturn = BranchedFoldingUtils.getFoldableBranchedReturn(newIfExpression.getElse()!!)!! val elseReturn = BranchedFoldingUtils.getFoldableBranchedReturn(newIfExpression.`else`!!)!!
thenReturn.replace(thenReturn.getReturnedExpression()!!) thenReturn.replace(thenReturn.returnedExpression!!)
elseReturn.replace(elseReturn.getReturnedExpression()!!) elseReturn.replace(elseReturn.returnedExpression!!)
element.replace(psiFactory.createExpressionByPattern("return $0", newIfExpression)) element.replace(psiFactory.createExpressionByPattern("return $0", newIfExpression))
elseBranch.delete() elseBranch.delete()
@@ -24,19 +24,19 @@ import org.jetbrains.kotlin.psi.KtIfExpression
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.createExpressionByPattern import org.jetbrains.kotlin.psi.createExpressionByPattern
public class FoldIfToReturnIntention : SelfTargetingRangeIntention<KtIfExpression>(javaClass(), "Replace 'if' expression with return") { public class FoldIfToReturnIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' expression with return") {
override fun applicabilityRange(element: KtIfExpression): TextRange? { override fun applicabilityRange(element: KtIfExpression): TextRange? {
if (BranchedFoldingUtils.getFoldableBranchedReturn(element.getThen()) == null) return null if (BranchedFoldingUtils.getFoldableBranchedReturn(element.then) == null) return null
if (BranchedFoldingUtils.getFoldableBranchedReturn(element.getElse()) == null) return null if (BranchedFoldingUtils.getFoldableBranchedReturn(element.`else`) == null) return null
return element.getIfKeyword().getTextRange() return element.ifKeyword.textRange
} }
override fun applyTo(element: KtIfExpression, editor: Editor) { override fun applyTo(element: KtIfExpression, editor: Editor) {
val thenReturn = BranchedFoldingUtils.getFoldableBranchedReturn(element.getThen()!!)!! val thenReturn = BranchedFoldingUtils.getFoldableBranchedReturn(element.then!!)!!
val elseReturn = BranchedFoldingUtils.getFoldableBranchedReturn(element.getElse()!!)!! val elseReturn = BranchedFoldingUtils.getFoldableBranchedReturn(element.`else`!!)!!
thenReturn.replace(thenReturn.getReturnedExpression()!!) thenReturn.replace(thenReturn.returnedExpression!!)
elseReturn.replace(elseReturn.getReturnedExpression()!!) elseReturn.replace(elseReturn.returnedExpression!!)
element.replace(KtPsiFactory(element).createExpressionByPattern("return $0", element)) element.replace(KtPsiFactory(element).createExpressionByPattern("return $0", element))
} }
@@ -23,44 +23,44 @@ import org.jetbrains.kotlin.idea.intentions.branchedTransformations.BranchedFold
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import java.util.* import java.util.*
public class FoldWhenToAssignmentIntention : SelfTargetingRangeIntention<KtWhenExpression>(javaClass(), "Replace 'when' expression with assignment") { public class FoldWhenToAssignmentIntention : SelfTargetingRangeIntention<KtWhenExpression>(KtWhenExpression::class.java, "Replace 'when' expression with assignment") {
override fun applicabilityRange(element: KtWhenExpression): TextRange? { override fun applicabilityRange(element: KtWhenExpression): TextRange? {
if (!KtPsiUtil.checkWhenExpressionHasSingleElse(element)) return null if (!KtPsiUtil.checkWhenExpressionHasSingleElse(element)) return null
val entries = element.getEntries() val entries = element.entries
if (entries.isEmpty()) return null if (entries.isEmpty()) return null
val assignments = ArrayList<KtBinaryExpression>() val assignments = ArrayList<KtBinaryExpression>()
for (entry in entries) { for (entry in entries) {
val assignment = BranchedFoldingUtils.getFoldableBranchedAssignment(entry.getExpression()) ?: return null val assignment = BranchedFoldingUtils.getFoldableBranchedAssignment(entry.expression) ?: return null
assignments.add(assignment) assignments.add(assignment)
} }
assert(!assignments.isEmpty()) assert(!assignments.isEmpty())
val firstAssignment = assignments.get(0) val firstAssignment = assignments.first()
for (assignment in assignments) { for (assignment in assignments) {
if (!BranchedFoldingUtils.checkAssignmentsMatch(assignment, firstAssignment)) return null if (!BranchedFoldingUtils.checkAssignmentsMatch(assignment, firstAssignment)) return null
} }
return element.getWhenKeyword().getTextRange() return element.whenKeyword.textRange
} }
override fun applyTo(element: KtWhenExpression, editor: Editor) { override fun applyTo(element: KtWhenExpression, editor: Editor) {
assert(!element.getEntries().isEmpty()) assert(!element.entries.isEmpty())
val firstAssignment = BranchedFoldingUtils.getFoldableBranchedAssignment(element.getEntries().get(0).getExpression()!!)!! val firstAssignment = BranchedFoldingUtils.getFoldableBranchedAssignment(element.entries.first().expression!!)!!
val op = firstAssignment.getOperationReference().getText() val op = firstAssignment.operationReference.text
val lhs = firstAssignment.getLeft() as KtNameReferenceExpression val lhs = firstAssignment.left as KtNameReferenceExpression
val assignment = KtPsiFactory(element).createExpressionByPattern("$0 $1 $2", lhs, op, element) val assignment = KtPsiFactory(element).createExpressionByPattern("$0 $1 $2", lhs, op, element)
val newWhenExpression = (assignment as KtBinaryExpression).getRight() as KtWhenExpression val newWhenExpression = (assignment as KtBinaryExpression).right as KtWhenExpression
for (entry in newWhenExpression.getEntries()) { for (entry in newWhenExpression.entries) {
val currAssignment = BranchedFoldingUtils.getFoldableBranchedAssignment(entry.getExpression()!!)!! val currAssignment = BranchedFoldingUtils.getFoldableBranchedAssignment(entry.expression!!)!!
val currRhs = currAssignment.getRight()!! val currRhs = currAssignment.right!!
currAssignment.replace(currRhs) currAssignment.replace(currRhs)
} }
@@ -22,30 +22,30 @@ import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.BranchedFoldingUtils import org.jetbrains.kotlin.idea.intentions.branchedTransformations.BranchedFoldingUtils
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
public class FoldWhenToReturnIntention : SelfTargetingRangeIntention<KtWhenExpression>(javaClass(), "Replace 'when' expression with return") { public class FoldWhenToReturnIntention : SelfTargetingRangeIntention<KtWhenExpression>(KtWhenExpression::class.java, "Replace 'when' expression with return") {
override fun applicabilityRange(element: KtWhenExpression): TextRange? { override fun applicabilityRange(element: KtWhenExpression): TextRange? {
if (!KtPsiUtil.checkWhenExpressionHasSingleElse(element)) return null if (!KtPsiUtil.checkWhenExpressionHasSingleElse(element)) return null
val entries = element.getEntries() val entries = element.entries
if (entries.isEmpty()) return null if (entries.isEmpty()) return null
for (entry in entries) { for (entry in entries) {
if (BranchedFoldingUtils.getFoldableBranchedReturn(entry.getExpression()) == null) return null if (BranchedFoldingUtils.getFoldableBranchedReturn(entry.expression) == null) return null
} }
return element.getWhenKeyword().getTextRange() return element.whenKeyword.textRange
} }
override fun applyTo(element: KtWhenExpression, editor: Editor) { override fun applyTo(element: KtWhenExpression, editor: Editor) {
assert(!element.getEntries().isEmpty()) assert(!element.entries.isEmpty())
val newReturnExpression = KtPsiFactory(element).createExpressionByPattern("return $0", element) as KtReturnExpression val newReturnExpression = KtPsiFactory(element).createExpressionByPattern("return $0", element) as KtReturnExpression
val newWhenExpression = newReturnExpression.getReturnedExpression() as KtWhenExpression val newWhenExpression = newReturnExpression.returnedExpression as KtWhenExpression
for (entry in newWhenExpression.getEntries()) { for (entry in newWhenExpression.entries) {
val currReturn = BranchedFoldingUtils.getFoldableBranchedReturn(entry.getExpression()!!)!! val currReturn = BranchedFoldingUtils.getFoldableBranchedReturn(entry.expression!!)!!
val currExpr = currReturn.getReturnedExpression()!! val currExpr = currReturn.returnedExpression!!
currReturn.replace(currExpr) currReturn.replace(currExpr)
} }
@@ -27,15 +27,15 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
public class IfThenToDoubleBangIntention : SelfTargetingRangeIntention<KtIfExpression>(javaClass(), "Replace 'if' expression with '!!' expression") { public class IfThenToDoubleBangIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' expression with '!!' expression") {
override fun applicabilityRange(element: KtIfExpression): TextRange? { override fun applicabilityRange(element: KtIfExpression): TextRange? {
val condition = element.getCondition() as? KtBinaryExpression ?: return null val condition = element.condition as? KtBinaryExpression ?: return null
val thenClause = element.getThen() ?: return null val thenClause = element.then ?: return null
val elseClause = element.getElse() val elseClause = element.`else`
val expression = condition.expressionComparedToNull() ?: return null val expression = condition.expressionComparedToNull() ?: return null
val token = condition.getOperationToken() val token = condition.operationToken
val throwExpression: KtThrowExpression val throwExpression: KtThrowExpression
val matchingClause: KtExpression? val matchingClause: KtExpression?
@@ -62,12 +62,12 @@ public class IfThenToDoubleBangIntention : SelfTargetingRangeIntention<KtIfExpre
} }
setText(text) setText(text)
val rParen = element.getRightParenthesis() ?: return null val rParen = element.rightParenthesis ?: return null
return TextRange(element.startOffset, rParen.endOffset) return TextRange(element.startOffset, rParen.endOffset)
} }
override fun applyTo(element: KtIfExpression, editor: Editor) { override fun applyTo(element: KtIfExpression, editor: Editor) {
val condition = element.getCondition() as KtBinaryExpression val condition = element.condition as KtBinaryExpression
val expression = condition.expressionComparedToNull()!! val expression = condition.expressionComparedToNull()!!
val result = element.replace(KtPsiFactory(element).createExpressionByPattern("$0!!", expression)) as KtPostfixExpression val result = element.replace(KtPsiFactory(element).createExpressionByPattern("$0!!", expression)) as KtPostfixExpression
@@ -27,17 +27,17 @@ import org.jetbrains.kotlin.idea.core.replaced
public class IfThenToElvisInspection : IntentionBasedInspection<KtIfExpression>(IfThenToElvisIntention()) public class IfThenToElvisInspection : IntentionBasedInspection<KtIfExpression>(IfThenToElvisIntention())
public class IfThenToElvisIntention : SelfTargetingOffsetIndependentIntention<KtIfExpression>(javaClass(), "Replace 'if' expression with elvis expression") { public class IfThenToElvisIntention : SelfTargetingOffsetIndependentIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' expression with elvis expression") {
override fun isApplicableTo(element: KtIfExpression): Boolean { override fun isApplicableTo(element: KtIfExpression): Boolean {
val condition = element.getCondition() as? KtBinaryExpression ?: return false val condition = element.condition as? KtBinaryExpression ?: return false
val thenClause = element.getThen() ?: return false val thenClause = element.then ?: return false
val elseClause = element.getElse() ?: return false val elseClause = element.`else` ?: return false
val expression = condition.expressionComparedToNull() ?: return false val expression = condition.expressionComparedToNull() ?: return false
if (!expression.isStableVariable()) return false if (!expression.isStableVariable()) return false
return when (condition.getOperationToken()) { return when (condition.operationToken) {
KtTokens.EQEQ -> KtTokens.EQEQ ->
thenClause.isNotNullExpression() && elseClause.evaluatesTo(expression) && thenClause.isNotNullExpression() && elseClause.evaluatesTo(expression) &&
!(thenClause is KtThrowExpression && thenClause.throwsNullPointerExceptionWithNoArguments()) !(thenClause is KtThrowExpression && thenClause.throwsNullPointerExceptionWithNoArguments())
@@ -53,7 +53,7 @@ public class IfThenToElvisIntention : SelfTargetingOffsetIndependentIntention<Kt
private fun KtExpression.isNotNullExpression(): Boolean { private fun KtExpression.isNotNullExpression(): Boolean {
val innerExpression = this.unwrapBlockOrParenthesis() val innerExpression = this.unwrapBlockOrParenthesis()
return innerExpression !is KtBlockExpression && innerExpression.getNode().getElementType() != KtNodeTypes.NULL return innerExpression !is KtBlockExpression && innerExpression.node.elementType != KtNodeTypes.NULL
} }
override fun applyTo(element: KtIfExpression, editor: Editor) { override fun applyTo(element: KtIfExpression, editor: Editor) {
@@ -62,15 +62,15 @@ public class IfThenToElvisIntention : SelfTargetingOffsetIndependentIntention<Kt
} }
public fun applyTo(element: KtIfExpression): KtBinaryExpression { public fun applyTo(element: KtIfExpression): KtBinaryExpression {
val condition = element.getCondition() as KtBinaryExpression val condition = element.condition as KtBinaryExpression
val thenClause = element.getThen()!! val thenClause = element.then!!
val elseClause = element.getElse()!! val elseClause = element.`else`!!
val thenExpression = thenClause.unwrapBlockOrParenthesis() val thenExpression = thenClause.unwrapBlockOrParenthesis()
val elseExpression = elseClause.unwrapBlockOrParenthesis() val elseExpression = elseClause.unwrapBlockOrParenthesis()
val (left, right) = val (left, right) =
when(condition.getOperationToken()) { when(condition.operationToken) {
KtTokens.EQEQ -> Pair(elseExpression, thenExpression) KtTokens.EQEQ -> Pair(elseExpression, thenExpression)
KtTokens.EXCLEQ -> Pair(thenExpression, elseExpression) KtTokens.EXCLEQ -> Pair(thenExpression, elseExpression)
else -> throw IllegalArgumentException() else -> throw IllegalArgumentException()
@@ -26,17 +26,17 @@ import org.jetbrains.kotlin.idea.core.replaced
public class IfThenToSafeAccessInspection : IntentionBasedInspection<KtIfExpression>(IfThenToSafeAccessIntention()) public class IfThenToSafeAccessInspection : IntentionBasedInspection<KtIfExpression>(IfThenToSafeAccessIntention())
public class IfThenToSafeAccessIntention : SelfTargetingOffsetIndependentIntention<KtIfExpression>(javaClass(), "Replace 'if' expression with safe access expression") { public class IfThenToSafeAccessIntention : SelfTargetingOffsetIndependentIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' expression with safe access expression") {
override fun isApplicableTo(element: KtIfExpression): Boolean { override fun isApplicableTo(element: KtIfExpression): Boolean {
val condition = element.getCondition() as? KtBinaryExpression ?: return false val condition = element.condition as? KtBinaryExpression ?: return false
val thenClause = element.getThen() val thenClause = element.then
val elseClause = element.getElse() val elseClause = element.`else`
val receiverExpression = condition.expressionComparedToNull() ?: return false val receiverExpression = condition.expressionComparedToNull() ?: return false
if (!receiverExpression.isStableVariable()) return false if (!receiverExpression.isStableVariable()) return false
return when (condition.getOperationToken()) { return when (condition.operationToken) {
KtTokens.EQEQ -> KtTokens.EQEQ ->
thenClause?.isNullExpressionOrEmptyBlock() ?: true && thenClause?.isNullExpressionOrEmptyBlock() ?: true &&
elseClause != null && clauseContainsAppropriateDotQualifiedExpression(elseClause, receiverExpression) elseClause != null && clauseContainsAppropriateDotQualifiedExpression(elseClause, receiverExpression)
@@ -56,14 +56,14 @@ public class IfThenToSafeAccessIntention : SelfTargetingOffsetIndependentIntenti
} }
public fun applyTo(element: KtIfExpression): KtSafeQualifiedExpression { public fun applyTo(element: KtIfExpression): KtSafeQualifiedExpression {
val condition = element.getCondition() as KtBinaryExpression val condition = element.condition as KtBinaryExpression
val receiverExpression = condition.expressionComparedToNull()!! val receiverExpression = condition.expressionComparedToNull()!!
val selectorExpression = val selectorExpression =
when(condition.getOperationToken()) { when(condition.operationToken) {
KtTokens.EQEQ -> findSelectorExpressionInClause(element.getElse()!!, receiverExpression)!! KtTokens.EQEQ -> findSelectorExpressionInClause(element.`else`!!, receiverExpression)!!
KtTokens.EXCLEQ -> findSelectorExpressionInClause(element.getThen()!!, receiverExpression)!! KtTokens.EXCLEQ -> findSelectorExpressionInClause(element.then!!, receiverExpression)!!
else -> throw IllegalArgumentException() else -> throw IllegalArgumentException()
} }
@@ -78,8 +78,8 @@ public class IfThenToSafeAccessIntention : SelfTargetingOffsetIndependentIntenti
private fun findSelectorExpressionInClause(clause: KtExpression, receiverExpression: KtExpression): KtExpression? { private fun findSelectorExpressionInClause(clause: KtExpression, receiverExpression: KtExpression): KtExpression? {
val expression = clause.unwrapBlockOrParenthesis() as? KtDotQualifiedExpression ?: return null val expression = clause.unwrapBlockOrParenthesis() as? KtDotQualifiedExpression ?: return null
if (expression.getReceiverExpression().getText() != receiverExpression.getText()) return null if (expression.receiverExpression.text != receiverExpression.text) return null
return expression.getSelectorExpression() return expression.selectorExpression
} }
} }
@@ -25,10 +25,10 @@ import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import java.util.* import java.util.*
public class IfToWhenIntention : SelfTargetingRangeIntention<KtIfExpression>(javaClass(), "Replace 'if' with 'when'") { public class IfToWhenIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' with 'when'") {
override fun applicabilityRange(element: KtIfExpression): TextRange? { override fun applicabilityRange(element: KtIfExpression): TextRange? {
if (element.getThen() == null) return null if (element.then == null) return null
return element.getIfKeyword().getTextRange() return element.ifKeyword.textRange
} }
override fun applyTo(element: KtIfExpression, editor: Editor) { override fun applyTo(element: KtIfExpression, editor: Editor) {
@@ -37,7 +37,7 @@ public class IfToWhenIntention : SelfTargetingRangeIntention<KtIfExpression>(jav
var ifExpression = element var ifExpression = element
while (true) { while (true) {
val condition = ifExpression.getCondition() val condition = ifExpression.condition
val orBranches = ArrayList<KtExpression>() val orBranches = ArrayList<KtExpression>()
if (condition != null) { if (condition != null) {
orBranches.addOrBranches(condition) orBranches.addOrBranches(condition)
@@ -47,11 +47,11 @@ public class IfToWhenIntention : SelfTargetingRangeIntention<KtIfExpression>(jav
appendFixedText("->") appendFixedText("->")
val thenBranch = ifExpression.getThen() val thenBranch = ifExpression.then
appendExpression(thenBranch) appendExpression(thenBranch)
appendFixedText("\n") appendFixedText("\n")
val elseBranch = ifExpression.getElse() ?: break val elseBranch = ifExpression.`else` ?: break
if (elseBranch is KtIfExpression) { if (elseBranch is KtIfExpression) {
ifExpression = elseBranch ifExpression = elseBranch
} }
@@ -75,9 +75,9 @@ public class IfToWhenIntention : SelfTargetingRangeIntention<KtIfExpression>(jav
} }
private fun MutableList<KtExpression>.addOrBranches(expression: KtExpression): List<KtExpression> { private fun MutableList<KtExpression>.addOrBranches(expression: KtExpression): List<KtExpression> {
if (expression is KtBinaryExpression && expression.getOperationToken() == KtTokens.OROR) { if (expression is KtBinaryExpression && expression.operationToken == KtTokens.OROR) {
val left = expression.getLeft() val left = expression.left
val right = expression.getRight() val right = expression.right
if (left != null && right != null) { if (left != null && right != null) {
addOrBranches(left) addOrBranches(left)
addOrBranches(right) addOrBranches(right)
@@ -26,11 +26,11 @@ import org.jetbrains.kotlin.psi.KtWhenExpression
public class IntroduceWhenSubjectInspection : IntentionBasedInspection<KtWhenExpression>(IntroduceWhenSubjectIntention()) public class IntroduceWhenSubjectInspection : IntentionBasedInspection<KtWhenExpression>(IntroduceWhenSubjectIntention())
public class IntroduceWhenSubjectIntention : SelfTargetingRangeIntention<KtWhenExpression>(javaClass(), "Introduce argument to 'when'") { public class IntroduceWhenSubjectIntention : SelfTargetingRangeIntention<KtWhenExpression>(KtWhenExpression::class.java, "Introduce argument to 'when'") {
override fun applicabilityRange(element: KtWhenExpression): TextRange? { override fun applicabilityRange(element: KtWhenExpression): TextRange? {
val subject = element.getSubjectToIntroduce() ?: return null val subject = element.getSubjectToIntroduce() ?: return null
setText("Introduce '${subject.getText()}' as argument to 'when'") text = "Introduce '${subject.text}' as argument to 'when'"
return element.getWhenKeyword().getTextRange() return element.whenKeyword.textRange
} }
override fun applyTo(element: KtWhenExpression, editor: Editor) { override fun applyTo(element: KtWhenExpression, editor: Editor) {
@@ -29,52 +29,52 @@ import org.jetbrains.kotlin.idea.util.psi.patternMatching.toRange
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.* import org.jetbrains.kotlin.psi.psiUtil.*
public class MergeWhenIntention : SelfTargetingRangeIntention<KtWhenExpression>(javaClass(), "Merge with next 'when'", "Merge 'when' expressions") { public class MergeWhenIntention : SelfTargetingRangeIntention<KtWhenExpression>(KtWhenExpression::class.java, "Merge with next 'when'", "Merge 'when' expressions") {
override fun applicabilityRange(element: KtWhenExpression): TextRange? { override fun applicabilityRange(element: KtWhenExpression): TextRange? {
val next = PsiTreeUtil.skipSiblingsForward(element, javaClass<PsiWhiteSpace>()) as? KtWhenExpression ?: return null val next = PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace::class.java) as? KtWhenExpression ?: return null
val subject1 = element.getSubjectExpression() val subject1 = element.subjectExpression
val subject2 = next.getSubjectExpression() val subject2 = next.subjectExpression
if (!subject1.matches(subject2)) return null if (!subject1.matches(subject2)) return null
if (subject1 != null && !subject1.isStableVariable()) return null if (subject1 != null && !subject1.isStableVariable()) return null
val entries1 = element.getEntries() val entries1 = element.entries
val entries2 = next.getEntries() val entries2 = next.entries
if (entries1.size() != entries2.size()) return null if (entries1.size != entries2.size) return null
if (!entries1.zip(entries2).all { pair -> if (!entries1.zip(entries2).all { pair ->
conditionsMatch(pair.first, pair.second) && checkBodies(pair.first, pair.second) conditionsMatch(pair.first, pair.second) && checkBodies(pair.first, pair.second)
}) return null }) return null
return element.getWhenKeyword().getTextRange() return element.whenKeyword.textRange
} }
private fun conditionsMatch(e1: KtWhenEntry, e2: KtWhenEntry): Boolean = private fun conditionsMatch(e1: KtWhenEntry, e2: KtWhenEntry): Boolean =
e1.getConditions().toList().toRange().matches(e2.getConditions().toList().toRange()) e1.conditions.toList().toRange().matches(e2.conditions.toList().toRange())
private fun checkBodies(e1: KtWhenEntry, e2: KtWhenEntry): Boolean { private fun checkBodies(e1: KtWhenEntry, e2: KtWhenEntry): Boolean {
val names1 = e1.declarationNames() val names1 = e1.declarationNames()
val names2 = e2.declarationNames() val names2 = e2.declarationNames()
if (names1.any { it in names2 }) return false if (names1.any { it in names2 }) return false
return when (e1.getExpression()?.lastBlockStatementOrThis()) { return when (e1.expression?.lastBlockStatementOrThis()) {
is KtReturnExpression, is KtThrowExpression, is KtBreakExpression, is KtContinueExpression -> false is KtReturnExpression, is KtThrowExpression, is KtBreakExpression, is KtContinueExpression -> false
else -> true else -> true
} }
} }
private fun KtWhenEntry.declarationNames(): Set<String> = private fun KtWhenEntry.declarationNames(): Set<String> =
getExpression()?.blockExpressionsOrSingle() expression?.blockExpressionsOrSingle()
?.filter { it is KtNamedDeclaration } ?.filter { it is KtNamedDeclaration }
?.mapNotNull { it.getName() } ?.mapNotNull { it.name }
?.toSet() ?: emptySet() ?.toSet() ?: emptySet()
override fun applyTo(element: KtWhenExpression, editor: Editor) { override fun applyTo(element: KtWhenExpression, editor: Editor) {
val nextWhen = PsiTreeUtil.skipSiblingsForward(element, javaClass<PsiWhiteSpace>()) as KtWhenExpression val nextWhen = PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace::class.java) as KtWhenExpression
for ((entry1, entry2) in element.getEntries().zip(nextWhen.getEntries())) { for ((entry1, entry2) in element.entries.zip(nextWhen.entries)) {
entry1.getExpression().mergeWith(entry2.getExpression()) entry1.expression.mergeWith(entry2.expression)
} }
element.getParent().deleteChildRange(element.getNextSibling(), nextWhen) element.parent.deleteChildRange(element.nextSibling, nextWhen)
} }
private fun KtExpression?.mergeWith(that: KtExpression?): KtExpression? = when { private fun KtExpression?.mergeWith(that: KtExpression?): KtExpression? = when {
@@ -27,15 +27,15 @@ import org.jetbrains.kotlin.idea.intentions.branchedTransformations.isStableVari
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement import org.jetbrains.kotlin.resolve.bindingContextUtil.isUsedAsStatement
public class SafeAccessToIfThenIntention : SelfTargetingRangeIntention<KtSafeQualifiedExpression>(javaClass(), "Replace safe access expression with 'if' expression"), LowPriorityAction { public class SafeAccessToIfThenIntention : SelfTargetingRangeIntention<KtSafeQualifiedExpression>(KtSafeQualifiedExpression::class.java, "Replace safe access expression with 'if' expression"), LowPriorityAction {
override fun applicabilityRange(element: KtSafeQualifiedExpression): TextRange? { override fun applicabilityRange(element: KtSafeQualifiedExpression): TextRange? {
if (element.getSelectorExpression() == null) return null if (element.selectorExpression == null) return null
return element.getOperationTokenNode().getTextRange() return element.operationTokenNode.textRange
} }
override fun applyTo(element: KtSafeQualifiedExpression, editor: Editor) { override fun applyTo(element: KtSafeQualifiedExpression, editor: Editor) {
val receiver = KtPsiUtil.safeDeparenthesize(element.getReceiverExpression()) val receiver = KtPsiUtil.safeDeparenthesize(element.receiverExpression)
val selector = element.getSelectorExpression()!! val selector = element.selectorExpression!!
val receiverIsStable = receiver.isStableVariable() val receiverIsStable = receiver.isStableVariable()
@@ -46,7 +46,7 @@ public class SafeAccessToIfThenIntention : SelfTargetingRangeIntention<KtSafeQua
val ifExpression = element.convertToIfNotNullExpression(receiver, dotQualified, elseClause) val ifExpression = element.convertToIfNotNullExpression(receiver, dotQualified, elseClause)
if (!receiverIsStable) { if (!receiverIsStable) {
val valueToExtract = (ifExpression.getThen() as KtDotQualifiedExpression).getReceiverExpression() val valueToExtract = (ifExpression.then as KtDotQualifiedExpression).receiverExpression
ifExpression.introduceValueForCondition(valueToExtract, editor) ifExpression.introduceValueForCondition(valueToExtract, editor)
} }
} }
@@ -27,12 +27,12 @@ import org.jetbrains.kotlin.psi.KtIfExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
public class UnfoldAssignmentToIfIntention : SelfTargetingRangeIntention<KtBinaryExpression>(javaClass(), "Replace assignment with 'if' expression"), LowPriorityAction { public class UnfoldAssignmentToIfIntention : SelfTargetingRangeIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Replace assignment with 'if' expression"), LowPriorityAction {
override fun applicabilityRange(element: KtBinaryExpression): TextRange? { override fun applicabilityRange(element: KtBinaryExpression): TextRange? {
if (element.getOperationToken() !in KtTokens.ALL_ASSIGNMENTS) return null if (element.operationToken !in KtTokens.ALL_ASSIGNMENTS) return null
if (element.getLeft() == null) return null if (element.left == null) return null
val right = element.getRight() as? KtIfExpression ?: return null val right = element.right as? KtIfExpression ?: return null
return TextRange(element.startOffset, right.getIfKeyword().endOffset) return TextRange(element.startOffset, right.ifKeyword.endOffset)
} }
override fun applyTo(element: KtBinaryExpression, editor: Editor) { override fun applyTo(element: KtBinaryExpression, editor: Editor) {
@@ -28,14 +28,14 @@ import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
public class UnfoldAssignmentToWhenIntention : SelfTargetingRangeIntention<KtBinaryExpression>(javaClass(), "Replace assignment with 'when' expression" ), LowPriorityAction { public class UnfoldAssignmentToWhenIntention : SelfTargetingRangeIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Replace assignment with 'when' expression" ), LowPriorityAction {
override fun applicabilityRange(element: KtBinaryExpression): TextRange? { override fun applicabilityRange(element: KtBinaryExpression): TextRange? {
if (element.getOperationToken() !in KtTokens.ALL_ASSIGNMENTS) return null if (element.operationToken !in KtTokens.ALL_ASSIGNMENTS) return null
if (element.getLeft() == null) return null if (element.left == null) return null
val right = element.getRight() as? KtWhenExpression ?: return null val right = element.right as? KtWhenExpression ?: return null
if (!KtPsiUtil.checkWhenExpressionHasSingleElse(right)) return null if (!KtPsiUtil.checkWhenExpressionHasSingleElse(right)) return null
if (right.getEntries().any { it.getExpression() == null }) return null if (right.entries.any { it.expression == null }) return null
return TextRange(element.startOffset, right.getWhenKeyword().endOffset) return TextRange(element.startOffset, right.whenKeyword.endOffset)
} }
override fun applyTo(element: KtBinaryExpression, editor: Editor) { override fun applyTo(element: KtBinaryExpression, editor: Editor) {
@@ -27,11 +27,11 @@ import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
public class UnfoldPropertyToIfIntention : SelfTargetingRangeIntention<KtProperty>(javaClass(), "Replace property initializer with 'if' expression"), LowPriorityAction { public class UnfoldPropertyToIfIntention : SelfTargetingRangeIntention<KtProperty>(KtProperty::class.java, "Replace property initializer with 'if' expression"), LowPriorityAction {
override fun applicabilityRange(element: KtProperty): TextRange? { override fun applicabilityRange(element: KtProperty): TextRange? {
if (!element.isLocal()) return null if (!element.isLocal) return null
val initializer = element.getInitializer() as? KtIfExpression ?: return null val initializer = element.initializer as? KtIfExpression ?: return null
return TextRange(element.startOffset, initializer.getIfKeyword().endOffset) return TextRange(element.startOffset, initializer.ifKeyword.endOffset)
} }
override fun applyTo(element: KtProperty, editor: Editor) { override fun applyTo(element: KtProperty, editor: Editor) {
@@ -28,13 +28,13 @@ import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.psi.psiUtil.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
public class UnfoldPropertyToWhenIntention : SelfTargetingRangeIntention<KtProperty>(javaClass(), "Replace property initializer with 'when' expression"), LowPriorityAction { public class UnfoldPropertyToWhenIntention : SelfTargetingRangeIntention<KtProperty>(KtProperty::class.java, "Replace property initializer with 'when' expression"), LowPriorityAction {
override fun applicabilityRange(element: KtProperty): TextRange? { override fun applicabilityRange(element: KtProperty): TextRange? {
if (!element.isLocal()) return null if (!element.isLocal) return null
val initializer = element.getInitializer() as? KtWhenExpression ?: return null val initializer = element.initializer as? KtWhenExpression ?: return null
if (!KtPsiUtil.checkWhenExpressionHasSingleElse(initializer)) return null if (!KtPsiUtil.checkWhenExpressionHasSingleElse(initializer)) return null
if (initializer.getEntries().any { it.getExpression() == null }) return null if (initializer.entries.any { it.expression == null }) return null
return TextRange(element.startOffset, initializer.getWhenKeyword().endOffset) return TextRange(element.startOffset, initializer.whenKeyword.endOffset)
} }
override fun applyTo(element: KtProperty, editor: Editor) { override fun applyTo(element: KtProperty, editor: Editor) {
@@ -29,17 +29,17 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
public class UnfoldReturnToIfIntention : SelfTargetingRangeIntention<KtReturnExpression>(javaClass(), "Replace return with 'if' expression"), LowPriorityAction { public class UnfoldReturnToIfIntention : SelfTargetingRangeIntention<KtReturnExpression>(KtReturnExpression::class.java, "Replace return with 'if' expression"), LowPriorityAction {
override fun applicabilityRange(element: KtReturnExpression): TextRange? { override fun applicabilityRange(element: KtReturnExpression): TextRange? {
val ifExpression = element.getReturnedExpression() as? KtIfExpression ?: return null val ifExpression = element.returnedExpression as? KtIfExpression ?: return null
return TextRange(element.startOffset, ifExpression.getIfKeyword().endOffset) return TextRange(element.startOffset, ifExpression.ifKeyword.endOffset)
} }
override fun applyTo(element: KtReturnExpression, editor: Editor) { override fun applyTo(element: KtReturnExpression, editor: Editor) {
val ifExpression = element.getReturnedExpression() as KtIfExpression val ifExpression = element.returnedExpression as KtIfExpression
val newIfExpression = ifExpression.copied() val newIfExpression = ifExpression.copied()
val thenExpr = newIfExpression.getThen()!!.lastBlockStatementOrThis() val thenExpr = newIfExpression.then!!.lastBlockStatementOrThis()
val elseExpr = newIfExpression.getElse()!!.lastBlockStatementOrThis() val elseExpr = newIfExpression.`else`!!.lastBlockStatementOrThis()
val psiFactory = KtPsiFactory(element) val psiFactory = KtPsiFactory(element)
thenExpr.replace(psiFactory.createExpressionByPattern("return $0", thenExpr)) thenExpr.replace(psiFactory.createExpressionByPattern("return $0", thenExpr))
@@ -26,20 +26,20 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis import org.jetbrains.kotlin.psi.psiUtil.lastBlockStatementOrThis
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
public class UnfoldReturnToWhenIntention : SelfTargetingRangeIntention<KtReturnExpression>(javaClass(), "Replace return with 'when' expression"), LowPriorityAction { public class UnfoldReturnToWhenIntention : SelfTargetingRangeIntention<KtReturnExpression>(KtReturnExpression::class.java, "Replace return with 'when' expression"), LowPriorityAction {
override fun applicabilityRange(element: KtReturnExpression): TextRange? { override fun applicabilityRange(element: KtReturnExpression): TextRange? {
val whenExpr = element.getReturnedExpression() as? KtWhenExpression ?: return null val whenExpr = element.returnedExpression as? KtWhenExpression ?: return null
if (!KtPsiUtil.checkWhenExpressionHasSingleElse(whenExpr)) return null if (!KtPsiUtil.checkWhenExpressionHasSingleElse(whenExpr)) return null
if (whenExpr.getEntries().any { it.getExpression() == null }) return null if (whenExpr.entries.any { it.expression == null }) return null
return TextRange(element.startOffset, whenExpr.getWhenKeyword().endOffset) return TextRange(element.startOffset, whenExpr.whenKeyword.endOffset)
} }
override fun applyTo(element: KtReturnExpression, editor: Editor) { override fun applyTo(element: KtReturnExpression, editor: Editor) {
val whenExpression = element.getReturnedExpression() as KtWhenExpression val whenExpression = element.returnedExpression as KtWhenExpression
val newWhenExpression = whenExpression.copied() val newWhenExpression = whenExpression.copied()
for (entry in newWhenExpression.getEntries()) { for (entry in newWhenExpression.entries) {
val expr = entry.getExpression()!!.lastBlockStatementOrThis() val expr = entry.expression!!.lastBlockStatementOrThis()
expr.replace(KtPsiFactory(element).createExpressionByPattern("return $0", expr)) expr.replace(KtPsiFactory(element).createExpressionByPattern("return $0", expr))
} }
@@ -23,29 +23,29 @@ import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.combineWhenConditions import org.jetbrains.kotlin.idea.intentions.branchedTransformations.combineWhenConditions
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
public class WhenToIfIntention : SelfTargetingRangeIntention<KtWhenExpression>(javaClass(), "Replace 'when' with 'if'"), LowPriorityAction { public class WhenToIfIntention : SelfTargetingRangeIntention<KtWhenExpression>(KtWhenExpression::class.java, "Replace 'when' with 'if'"), LowPriorityAction {
override fun applicabilityRange(element: KtWhenExpression): TextRange? { override fun applicabilityRange(element: KtWhenExpression): TextRange? {
val entries = element.getEntries() val entries = element.entries
if (entries.isEmpty()) return null if (entries.isEmpty()) return null
val lastEntry = entries.last() val lastEntry = entries.last()
if (entries.any { it != lastEntry && it.isElse() }) return null if (entries.any { it != lastEntry && it.isElse }) return null
return element.getWhenKeyword().getTextRange() return element.whenKeyword.textRange
} }
override fun applyTo(element: KtWhenExpression, editor: Editor) { override fun applyTo(element: KtWhenExpression, editor: Editor) {
val factory = KtPsiFactory(element) val factory = KtPsiFactory(element)
val ifExpression = factory.buildExpression { val ifExpression = factory.buildExpression {
val entries = element.getEntries() val entries = element.entries
for ((i, entry) in entries.withIndex()) { for ((i, entry) in entries.withIndex()) {
if (i > 0) { if (i > 0) {
appendFixedText("else ") appendFixedText("else ")
} }
val branch = entry.getExpression() val branch = entry.expression
if (entry.isElse()) { if (entry.isElse) {
appendExpression(branch) appendExpression(branch)
} }
else { else {
val condition = factory.combineWhenConditions(entry.getConditions(), element.getSubjectExpression()) val condition = factory.combineWhenConditions(entry.conditions, element.subjectExpression)
appendFixedText("if (") appendFixedText("if (")
appendExpression(condition) appendExpression(condition)
appendFixedText(")") appendFixedText(")")
@@ -29,32 +29,32 @@ import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.types.expressions.OperatorConventions
public class ReplaceCallWithBinaryOperatorIntention : SelfTargetingRangeIntention<KtDotQualifiedExpression>(javaClass(), "Replace call with binary operator"), HighPriorityAction { public class ReplaceCallWithBinaryOperatorIntention : SelfTargetingRangeIntention<KtDotQualifiedExpression>(KtDotQualifiedExpression::class.java, "Replace call with binary operator"), HighPriorityAction {
override fun applicabilityRange(element: KtDotQualifiedExpression): TextRange? { override fun applicabilityRange(element: KtDotQualifiedExpression): TextRange? {
val operation = operation(element.calleeName) ?: return null val operation = operation(element.calleeName) ?: return null
val resolvedCall = element.toResolvedCall(BodyResolveMode.PARTIAL) ?: return null val resolvedCall = element.toResolvedCall(BodyResolveMode.PARTIAL) ?: return null
if (!resolvedCall.isReallySuccess()) return null if (!resolvedCall.isReallySuccess()) return null
if (resolvedCall.getCall().getTypeArgumentList() != null) return null if (resolvedCall.call.typeArgumentList != null) return null
val argument = resolvedCall.getCall().getValueArguments().singleOrNull() ?: return null val argument = resolvedCall.call.valueArguments.singleOrNull() ?: return null
if ((resolvedCall.getArgumentMapping(argument) as ArgumentMatch).valueParameter.index != 0) return null if ((resolvedCall.getArgumentMapping(argument) as ArgumentMatch).valueParameter.index != 0) return null
if (!element.isReceiverExpressionWithValue()) return null if (!element.isReceiverExpressionWithValue()) return null
setText("Replace with '$operation' operator") text = "Replace with '$operation' operator"
return element.callExpression!!.getCalleeExpression()!!.getTextRange() return element.callExpression!!.calleeExpression!!.textRange
} }
override fun applyTo(element: KtDotQualifiedExpression, editor: Editor) { override fun applyTo(element: KtDotQualifiedExpression, editor: Editor) {
val operation = operation(element.calleeName)!! val operation = operation(element.calleeName)!!
val argument = element.callExpression!!.getValueArguments().single().getArgumentExpression()!! val argument = element.callExpression!!.valueArguments.single().getArgumentExpression()!!
val receiver = element.getReceiverExpression() val receiver = element.receiverExpression
element.replace(KtPsiFactory(element).createExpressionByPattern("$0 $operation $1", receiver, argument)) element.replace(KtPsiFactory(element).createExpressionByPattern("$0 $operation $1", receiver, argument))
} }
private fun operation(functionName: String?): String? { private fun operation(functionName: String?): String? {
if (functionName == null) return null if (functionName == null) return null
return OperatorConventions.BINARY_OPERATION_NAMES.inverse()[Name.identifier(functionName)]?.getValue() return OperatorConventions.BINARY_OPERATION_NAMES.inverse()[Name.identifier(functionName)]?.value
} }
} }
@@ -29,28 +29,28 @@ import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.createExpressionByPattern import org.jetbrains.kotlin.psi.createExpressionByPattern
import org.jetbrains.kotlin.types.expressions.OperatorConventions import org.jetbrains.kotlin.types.expressions.OperatorConventions
public class ReplaceCallWithUnaryOperatorIntention : SelfTargetingRangeIntention<KtDotQualifiedExpression>(javaClass(), "Replace call with unary operator"), HighPriorityAction { public class ReplaceCallWithUnaryOperatorIntention : SelfTargetingRangeIntention<KtDotQualifiedExpression>(KtDotQualifiedExpression::class.java, "Replace call with unary operator"), HighPriorityAction {
override fun applicabilityRange(element: KtDotQualifiedExpression): TextRange? { override fun applicabilityRange(element: KtDotQualifiedExpression): TextRange? {
val operation = operation(element.calleeName) ?: return null val operation = operation(element.calleeName) ?: return null
val call = element.callExpression ?: return null val call = element.callExpression ?: return null
if (call.getTypeArgumentList() != null) return null if (call.typeArgumentList != null) return null
if (!call.getValueArguments().isEmpty()) return null if (!call.valueArguments.isEmpty()) return null
if (!element.isReceiverExpressionWithValue()) return null if (!element.isReceiverExpressionWithValue()) return null
setText("Replace with '$operation' operator") text = "Replace with '$operation' operator"
return call.getCalleeExpression()!!.getTextRange() return call.calleeExpression!!.textRange
} }
override fun applyTo(element: KtDotQualifiedExpression, editor: Editor) { override fun applyTo(element: KtDotQualifiedExpression, editor: Editor) {
val operation = operation(element.calleeName)!! val operation = operation(element.calleeName)!!
val receiver = element.getReceiverExpression() val receiver = element.receiverExpression
element.replace(KtPsiFactory(element).createExpressionByPattern("$0$1", operation, receiver)) element.replace(KtPsiFactory(element).createExpressionByPattern("$0$1", operation, receiver))
} }
private fun operation(functionName: String?) : String? { private fun operation(functionName: String?) : String? {
if (functionName == null) return null if (functionName == null) return null
return OperatorConventions.UNARY_OPERATION_NAMES.inverse()[Name.identifier(functionName)]?.getValue() return OperatorConventions.UNARY_OPERATION_NAMES.inverse()[Name.identifier(functionName)]?.value
} }
} }
@@ -28,32 +28,32 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
public class ReplaceContainsIntention : SelfTargetingRangeIntention<KtDotQualifiedExpression>(javaClass(), "Replace 'contains' call with 'in' operator"), HighPriorityAction { public class ReplaceContainsIntention : SelfTargetingRangeIntention<KtDotQualifiedExpression>(KtDotQualifiedExpression::class.java, "Replace 'contains' call with 'in' operator"), HighPriorityAction {
override fun applicabilityRange(element: KtDotQualifiedExpression): TextRange? { override fun applicabilityRange(element: KtDotQualifiedExpression): TextRange? {
if (element.calleeName != OperatorNameConventions.CONTAINS.asString()) return null if (element.calleeName != OperatorNameConventions.CONTAINS.asString()) return null
val resolvedCall = element.toResolvedCall(BodyResolveMode.PARTIAL) ?: return null val resolvedCall = element.toResolvedCall(BodyResolveMode.PARTIAL) ?: return null
if (!resolvedCall.isReallySuccess()) return null if (!resolvedCall.isReallySuccess()) return null
val argument = resolvedCall.getCall().getValueArguments().singleOrNull() ?: return null val argument = resolvedCall.call.valueArguments.singleOrNull() ?: return null
if ((resolvedCall.getArgumentMapping(argument) as ArgumentMatch).valueParameter.index != 0) return null if ((resolvedCall.getArgumentMapping(argument) as ArgumentMatch).valueParameter.index != 0) return null
val target = resolvedCall.getResultingDescriptor() val target = resolvedCall.resultingDescriptor
val returnType = target.getReturnType() ?: return null val returnType = target.returnType ?: return null
if (!target.builtIns.isBooleanOrSubtype(returnType)) return null if (!target.builtIns.isBooleanOrSubtype(returnType)) return null
if (!element.isReceiverExpressionWithValue()) return null if (!element.isReceiverExpressionWithValue()) return null
return element.callExpression!!.getCalleeExpression()!!.getTextRange() return element.callExpression!!.calleeExpression!!.textRange
} }
override fun applyTo(element: KtDotQualifiedExpression, editor: Editor) { override fun applyTo(element: KtDotQualifiedExpression, editor: Editor) {
val argument = element.callExpression!!.getValueArguments().single().getArgumentExpression()!! val argument = element.callExpression!!.valueArguments.single().getArgumentExpression()!!
val receiver = element.getReceiverExpression() val receiver = element.receiverExpression
val psiFactory = KtPsiFactory(element) val psiFactory = KtPsiFactory(element)
val prefixExpression = element.getParent() as? KtPrefixExpression val prefixExpression = element.parent as? KtPrefixExpression
val expression = if (prefixExpression != null && prefixExpression.getOperationToken() == KtTokens.EXCL) { val expression = if (prefixExpression != null && prefixExpression.operationToken == KtTokens.EXCL) {
prefixExpression.replace(psiFactory.createExpressionByPattern("$0 !in $1", argument, receiver)) prefixExpression.replace(psiFactory.createExpressionByPattern("$0 !in $1", argument, receiver))
} }
else { else {
@@ -63,10 +63,10 @@ public class ReplaceContainsIntention : SelfTargetingRangeIntention<KtDotQualifi
// Append semicolon to previous statement if needed // Append semicolon to previous statement if needed
if (argument is KtLambdaExpression) { if (argument is KtLambdaExpression) {
val previousElement = KtPsiUtil.skipSiblingsBackwardByPredicate(expression) { val previousElement = KtPsiUtil.skipSiblingsBackwardByPredicate(expression) {
it.getNode().getElementType() in KtTokens.WHITE_SPACE_OR_COMMENT_BIT_SET it.node.elementType in KtTokens.WHITE_SPACE_OR_COMMENT_BIT_SET
} }
if (previousElement != null && previousElement is KtExpression) { if (previousElement != null && previousElement is KtExpression) {
previousElement.getParent()!!.addAfter(psiFactory.createSemicolon(), previousElement) previousElement.parent!!.addAfter(psiFactory.createSemicolon(), previousElement)
} }
} }
} }
@@ -71,9 +71,9 @@ class ReplaceGetOrSetIntention : SelfTargetingRangeIntention<KtDotQualifiedExpre
val target = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return null val target = resolvedCall.resultingDescriptor as? FunctionDescriptor ?: return null
if (!target.isValidOperator() || target.name !in operatorNames) return null if (!target.isValidOperator() || target.name !in operatorNames) return null
if (callExpression.getTypeArgumentList() != null) return null if (callExpression.typeArgumentList != null) return null
val arguments = callExpression.getValueArguments() val arguments = callExpression.valueArguments
if (arguments.isEmpty()) return null if (arguments.isEmpty()) return null
if (arguments.any { it.isNamed() }) return null if (arguments.any { it.isNamed() }) return null
@@ -83,7 +83,7 @@ class ReplaceGetOrSetIntention : SelfTargetingRangeIntention<KtDotQualifiedExpre
text = "Replace '${target.name.asString()}' call with indexing operator" text = "Replace '${target.name.asString()}' call with indexing operator"
return callExpression.getCalleeExpression()!!.getTextRange() return callExpression.calleeExpression!!.textRange
} }
override fun applyTo(element: KtDotQualifiedExpression, editor: Editor) { override fun applyTo(element: KtDotQualifiedExpression, editor: Editor) {
@@ -96,7 +96,7 @@ class ReplaceGetOrSetIntention : SelfTargetingRangeIntention<KtDotQualifiedExpre
assert(allArguments.isNotEmpty()) assert(allArguments.isNotEmpty())
val expression = KtPsiFactory(element).buildExpression { val expression = KtPsiFactory(element).buildExpression {
appendExpression(element.getReceiverExpression()) appendExpression(element.receiverExpression)
appendFixedText("[") appendFixedText("[")
@@ -26,16 +26,16 @@ import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
public class ReplaceInvokeIntention : SelfTargetingRangeIntention<KtDotQualifiedExpression>(javaClass(), "Replace 'invoke' with direct call"), HighPriorityAction { public class ReplaceInvokeIntention : SelfTargetingRangeIntention<KtDotQualifiedExpression>(KtDotQualifiedExpression::class.java, "Replace 'invoke' with direct call"), HighPriorityAction {
override fun applicabilityRange(element: KtDotQualifiedExpression): TextRange? { override fun applicabilityRange(element: KtDotQualifiedExpression): TextRange? {
if (element.calleeName != OperatorNameConventions.INVOKE.asString()) return null if (element.calleeName != OperatorNameConventions.INVOKE.asString()) return null
return element.callExpression!!.getCalleeExpression()!!.getTextRange() return element.callExpression!!.calleeExpression!!.textRange
} }
override fun applyTo(element: KtDotQualifiedExpression, editor: Editor) { override fun applyTo(element: KtDotQualifiedExpression, editor: Editor) {
val receiver = element.getReceiverExpression() val receiver = element.receiverExpression
val callExpression = element.callExpression!!.copy() as KtCallExpression val callExpression = element.callExpression!!.copy() as KtCallExpression
callExpression.getCalleeExpression()!!.replace(receiver) callExpression.calleeExpression!!.replace(receiver)
element.replace(callExpression) element.replace(callExpression)
} }
} }
@@ -29,31 +29,31 @@ import org.jetbrains.kotlin.idea.quickfix.moveCaret
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
public class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtCallableDeclaration>(javaClass(), "Convert member to extension"), LowPriorityAction { public class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtCallableDeclaration>(KtCallableDeclaration::class.java, "Convert member to extension"), LowPriorityAction {
override fun applicabilityRange(element: KtCallableDeclaration): TextRange? { override fun applicabilityRange(element: KtCallableDeclaration): TextRange? {
val classBody = element.getParent() as? KtClassBody ?: return null val classBody = element.parent as? KtClassBody ?: return null
if (classBody.getParent() !is KtClass) return null if (classBody.parent !is KtClass) return null
if (element.getReceiverTypeReference() != null) return null if (element.receiverTypeReference != null) return null
if (element.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return null if (element.hasModifier(KtTokens.OVERRIDE_KEYWORD)) return null
when (element) { when (element) {
is KtProperty -> if (element.hasInitializer()) return null is KtProperty -> if (element.hasInitializer()) return null
is KtSecondaryConstructor -> return null is KtSecondaryConstructor -> return null
} }
return (element.getNameIdentifier() ?: return null).getTextRange() return (element.nameIdentifier ?: return null).textRange
} }
//TODO: local class //TODO: local class
override fun applyTo(element: KtCallableDeclaration, editor: Editor) { override fun applyTo(element: KtCallableDeclaration, editor: Editor) {
val descriptor = element.resolveToDescriptor() val descriptor = element.resolveToDescriptor()
val containingClass = descriptor.getContainingDeclaration() as ClassDescriptor val containingClass = descriptor.containingDeclaration as ClassDescriptor
val file = element.getContainingKtFile() val file = element.getContainingKtFile()
val outermostParent = KtPsiUtil.getOutermostParent(element, file, false) val outermostParent = KtPsiUtil.getOutermostParent(element, file, false)
val typeParameterList = newTypeParameterList(element) val typeParameterList = newTypeParameterList(element)
val project = element.getProject() val project = element.project
val psiFactory = KtPsiFactory(element) val psiFactory = KtPsiFactory(element)
val extension = file.addAfter(element, outermostParent) as KtCallableDeclaration val extension = file.addAfter(element, outermostParent) as KtCallableDeclaration
@@ -61,27 +61,27 @@ public class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtC
file.addAfter(psiFactory.createNewLine(), outermostParent) file.addAfter(psiFactory.createNewLine(), outermostParent)
element.delete() element.delete()
extension.setReceiverType(containingClass.getDefaultType()) extension.setReceiverType(containingClass.defaultType)
if (typeParameterList != null) { if (typeParameterList != null) {
if (extension.getTypeParameterList() != null) { if (extension.typeParameterList != null) {
extension.getTypeParameterList()!!.replace(typeParameterList) extension.typeParameterList!!.replace(typeParameterList)
} }
else { else {
extension.addBefore(typeParameterList, extension.getReceiverTypeReference()) extension.addBefore(typeParameterList, extension.receiverTypeReference)
extension.addBefore(psiFactory.createWhiteSpace(), extension.getReceiverTypeReference()) extension.addBefore(psiFactory.createWhiteSpace(), extension.receiverTypeReference)
} }
} }
extension.getModifierList()?.getModifier(KtTokens.PROTECTED_KEYWORD)?.delete() extension.modifierList?.getModifier(KtTokens.PROTECTED_KEYWORD)?.delete()
extension.getModifierList()?.getModifier(KtTokens.ABSTRACT_KEYWORD)?.delete() extension.modifierList?.getModifier(KtTokens.ABSTRACT_KEYWORD)?.delete()
var bodyToSelect: KtExpression? = null var bodyToSelect: KtExpression? = null
fun selectBody(declaration: KtDeclarationWithBody) { fun selectBody(declaration: KtDeclarationWithBody) {
if (bodyToSelect == null) { if (bodyToSelect == null) {
val body = declaration.getBodyExpression() val body = declaration.bodyExpression
bodyToSelect = if (body is KtBlockExpression) body.getStatements().single() else body bodyToSelect = if (body is KtBlockExpression) body.statements.single() else body
} }
} }
@@ -96,12 +96,12 @@ public class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtC
is KtProperty -> { is KtProperty -> {
val templateProperty = psiFactory.createDeclaration<KtProperty>("var v: Any\nget()=$THROW_UNSUPPORTED_OPERATION_EXCEPTION\nset(value){$THROW_UNSUPPORTED_OPERATION_EXCEPTION}") val templateProperty = psiFactory.createDeclaration<KtProperty>("var v: Any\nget()=$THROW_UNSUPPORTED_OPERATION_EXCEPTION\nset(value){$THROW_UNSUPPORTED_OPERATION_EXCEPTION}")
val templateGetter = templateProperty.getGetter()!! val templateGetter = templateProperty.getter!!
val templateSetter = templateProperty.getSetter()!! val templateSetter = templateProperty.setter!!
var getter = extension.getGetter() var getter = extension.getter
if (getter == null) { if (getter == null) {
getter = extension.addAfter(templateGetter, extension.getTypeReference()) as KtPropertyAccessor getter = extension.addAfter(templateGetter, extension.typeReference) as KtPropertyAccessor
extension.addBefore(psiFactory.createNewLine(), getter) extension.addBefore(psiFactory.createNewLine(), getter)
selectBody(getter) selectBody(getter)
} }
@@ -110,8 +110,8 @@ public class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtC
selectBody(getter) selectBody(getter)
} }
if (extension.isVar()) { if (extension.isVar) {
var setter = extension.getSetter() var setter = extension.setter
if (setter == null) { if (setter == null) {
setter = extension.addAfter(templateSetter, getter) as KtPropertyAccessor setter = extension.addAfter(templateSetter, getter) as KtPropertyAccessor
extension.addBefore(psiFactory.createNewLine(), setter) extension.addBefore(psiFactory.createNewLine(), setter)
@@ -125,15 +125,15 @@ public class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtC
} }
} }
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.getDocument()) PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(editor.document)
if (bodyToSelect != null) { if (bodyToSelect != null) {
val range = bodyToSelect!!.getTextRange() val range = bodyToSelect!!.textRange
editor.moveCaret(range.getStartOffset(), ScrollType.CENTER) editor.moveCaret(range.startOffset, ScrollType.CENTER)
editor.getSelectionModel().setSelection(range.getStartOffset(), range.getEndOffset()) editor.selectionModel.setSelection(range.startOffset, range.endOffset)
} }
else { else {
editor.moveCaret(extension.getTextOffset(), ScrollType.CENTER) editor.moveCaret(extension.textOffset, ScrollType.CENTER)
} }
} }
@@ -141,11 +141,11 @@ public class ConvertMemberToExtensionIntention : SelfTargetingRangeIntention<KtC
private val THROW_UNSUPPORTED_OPERATION_EXCEPTION = "throw UnsupportedOperationException()" private val THROW_UNSUPPORTED_OPERATION_EXCEPTION = "throw UnsupportedOperationException()"
private fun newTypeParameterList(member: KtCallableDeclaration): KtTypeParameterList? { private fun newTypeParameterList(member: KtCallableDeclaration): KtTypeParameterList? {
val classElement = member.getParent().getParent() as KtClass val classElement = member.parent.parent as KtClass
val classParams = classElement.getTypeParameters() val classParams = classElement.typeParameters
if (classParams.isEmpty()) return null if (classParams.isEmpty()) return null
val allTypeParameters = classParams + member.getTypeParameters() val allTypeParameters = classParams + member.typeParameters
val text = allTypeParameters.map { it.getText() }.joinToString(",", "<", ">") val text = allTypeParameters.map { it.text }.joinToString(",", "<", ">")
return KtPsiFactory(member).createDeclaration<KtFunction>("fun $text foo()").getTypeParameterList() return KtPsiFactory(member).createDeclaration<KtFunction>("fun $text foo()").typeParameterList
} }
} }
@@ -24,10 +24,10 @@ import org.jetbrains.kotlin.idea.intentions.splitPropertyDeclaration
import org.jetbrains.kotlin.psi.KtProperty import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
public class SplitPropertyDeclarationIntention : SelfTargetingRangeIntention<KtProperty>(javaClass(), "Split property declaration"), LowPriorityAction { public class SplitPropertyDeclarationIntention : SelfTargetingRangeIntention<KtProperty>(KtProperty::class.java, "Split property declaration"), LowPriorityAction {
override fun applicabilityRange(element: KtProperty): TextRange? { override fun applicabilityRange(element: KtProperty): TextRange? {
if (!element.isLocal()) return null if (!element.isLocal) return null
val initializer = element.getInitializer() ?: return null val initializer = element.initializer ?: return null
return TextRange(element.startOffset, initializer.startOffset) return TextRange(element.startOffset, initializer.startOffset)
} }