IntentionBasedInspection: Removing synchronizing on intention instances

Recreate intention instance in `buildVisitor`
Lock caused contention for UpSource
This commit is contained in:
Pavel V. Talanov
2016-08-18 15:42:55 +03:00
parent 742d7db953
commit a683c2b68d
32 changed files with 239 additions and 229 deletions
@@ -31,34 +31,34 @@ import com.intellij.psi.PsiElementVisitor
import com.intellij.psi.PsiFile import com.intellij.psi.PsiFile
import com.intellij.util.SmartList import com.intellij.util.SmartList
import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
import kotlin.reflect.KClass
abstract class IntentionBasedInspection<TElement : PsiElement>( abstract class IntentionBasedInspection<TElement : PsiElement>(
val intentions: List<IntentionBasedInspection.IntentionData<TElement>>, val intentionInfos: List<IntentionBasedInspection.IntentionData<TElement>>,
protected open val problemText: String?, protected open val problemText: String?
protected val elementType: Class<TElement>
) : AbstractKotlinInspection() { ) : AbstractKotlinInspection() {
constructor( constructor(
intention: SelfTargetingRangeIntention<TElement>, intention: KClass<out SelfTargetingRangeIntention<TElement>>,
problemText: String? = null problemText: String? = null
) : this(listOf(IntentionData(intention)), problemText, intention.elementType) ) : this(listOf(IntentionData(intention)), problemText)
constructor( constructor(
intention: SelfTargetingRangeIntention<TElement>, intention: KClass<out SelfTargetingRangeIntention<TElement>>,
additionalChecker: (TElement, IntentionBasedInspection<TElement>) -> Boolean, additionalChecker: (TElement, IntentionBasedInspection<TElement>) -> Boolean,
problemText: String? = null problemText: String? = null
) : this(listOf(IntentionData(intention, additionalChecker)), problemText, intention.elementType) ) : this(listOf(IntentionData(intention, additionalChecker)), problemText)
constructor( constructor(
intention: SelfTargetingRangeIntention<TElement>, intention: KClass<out SelfTargetingRangeIntention<TElement>>,
additionalChecker: (TElement) -> Boolean, additionalChecker: (TElement) -> Boolean,
problemText: String? = null problemText: String? = null
) : this(listOf(IntentionData(intention, { element, inspection -> additionalChecker(element) } )), problemText, intention.elementType) ) : this(listOf(IntentionData(intention, { element, inspection -> additionalChecker(element) } )), problemText)
data class IntentionData<TElement : PsiElement>( data class IntentionData<TElement : PsiElement>(
val intention: SelfTargetingRangeIntention<TElement>, val intention: KClass<out SelfTargetingRangeIntention<TElement>>,
val additionalChecker: (TElement, IntentionBasedInspection<TElement>) -> Boolean = { element, inspection -> true } val additionalChecker: (TElement, IntentionBasedInspection<TElement>) -> Boolean = { element, inspection -> true }
) )
@@ -67,6 +67,13 @@ abstract class IntentionBasedInspection<TElement : PsiElement>(
open fun inspectionRange(element: TElement): TextRange? = null open fun inspectionRange(element: TElement): TextRange? = null
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor { override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
val intentionsAndCheckers = intentionInfos.map {
it.intention.constructors.single().call() to it.additionalChecker
}
val elementType = intentionsAndCheckers.map { it.first.elementType }.distinct().singleOrNull()
?: error("$intentionInfos should have the same elementType")
return object : PsiElementVisitor() { return object : PsiElementVisitor() {
override fun visitElement(element: PsiElement) { override fun visitElement(element: PsiElement) {
if (!elementType.isInstance(element) || element.textLength == 0) return if (!elementType.isInstance(element) || element.textLength == 0) return
@@ -77,21 +84,19 @@ abstract class IntentionBasedInspection<TElement : PsiElement>(
var problemRange: TextRange? = null var problemRange: TextRange? = null
var fixes: SmartList<LocalQuickFix>? = null var fixes: SmartList<LocalQuickFix>? = null
for ((intention, additionalChecker) in intentions) { for ((intention, additionalChecker) in intentionsAndCheckers) {
synchronized(intention) { val range = intention.applicabilityRange(targetElement)?.let { range ->
val range = intention.applicabilityRange(targetElement)?.let { range -> val elementRange = targetElement.textRange
val elementRange = targetElement.textRange assert(range in elementRange) { "Wrong applicabilityRange() result for $intention - should be within element's range" }
assert(range in elementRange) { "Wrong applicabilityRange() result for $intention - should be within element's range" } range.shiftRight(-elementRange.startOffset)
range.shiftRight(-elementRange.startOffset) }
}
if (range != null && additionalChecker(targetElement, this@IntentionBasedInspection)) { if (range != null && additionalChecker(targetElement, this@IntentionBasedInspection)) {
problemRange = problemRange?.union(range) ?: range problemRange = problemRange?.union(range) ?: range
if (fixes == null) { if (fixes == null) {
fixes = SmartList<LocalQuickFix>() fixes = SmartList<LocalQuickFix>()
}
fixes!!.add(createQuickFix(intention, additionalChecker, targetElement))
} }
fixes!!.add(createQuickFix(intention, additionalChecker, targetElement))
} }
} }
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.psiUtil.containsInside import org.jetbrains.kotlin.psi.psiUtil.containsInside
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
import java.util.* import java.util.*
import kotlin.reflect.KClass
abstract class SelfTargetingIntention<TElement : PsiElement>( abstract class SelfTargetingIntention<TElement : PsiElement>(
val elementType: Class<TElement>, val elementType: Class<TElement>,
@@ -88,14 +89,14 @@ abstract class SelfTargetingIntention<TElement : PsiElement>(
} }
protected fun isIntentionBaseInspectionEnabled(project: Project, target: TElement): Boolean { protected fun isIntentionBaseInspectionEnabled(project: Project, target: TElement): Boolean {
val inspection = findInspection(javaClass) ?: return false val inspection = findInspection(this.javaClass.kotlin) ?: return false
val key = HighlightDisplayKey.find(inspection.shortName) val key = HighlightDisplayKey.find(inspection.shortName)
if (!InspectionProjectProfileManager.getInstance(project).getInspectionProfile(target).isToolEnabled(key)) { if (!InspectionProjectProfileManager.getInstance(project).getInspectionProfile(target).isToolEnabled(key)) {
return false return false
} }
return inspection.intentions.single { it.intention.javaClass == javaClass }.additionalChecker(target, inspection) return inspection.intentionInfos.single { it.intention == this.javaClass.kotlin }.additionalChecker(target, inspection)
} }
final override fun invoke(project: Project, editor: Editor, file: PsiFile): Unit { final override fun invoke(project: Project, editor: Editor, file: PsiFile): Unit {
@@ -109,9 +110,9 @@ abstract class SelfTargetingIntention<TElement : PsiElement>(
override fun toString(): String = getText() override fun toString(): String = getText()
companion object { companion object {
private val intentionBasedInspections = HashMap<Class<out SelfTargetingIntention<*>>, IntentionBasedInspection<*>?>() private val intentionBasedInspections = HashMap<KClass<out SelfTargetingIntention<*>>, IntentionBasedInspection<*>?>()
fun <TElement : PsiElement> findInspection(intentionClass: Class<out SelfTargetingIntention<TElement>>): IntentionBasedInspection<TElement>? { fun <TElement : PsiElement> findInspection(intentionClass: KClass<out SelfTargetingIntention<TElement>>): IntentionBasedInspection<TElement>? {
if (intentionBasedInspections.containsKey(intentionClass)) { if (intentionBasedInspections.containsKey(intentionClass)) {
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return intentionBasedInspections[intentionClass] as IntentionBasedInspection<TElement>? return intentionBasedInspections[intentionClass] as IntentionBasedInspection<TElement>?
@@ -119,7 +120,7 @@ abstract class SelfTargetingIntention<TElement : PsiElement>(
for (extension in Extensions.getExtensions(LocalInspectionEP.LOCAL_INSPECTION)) { for (extension in Extensions.getExtensions(LocalInspectionEP.LOCAL_INSPECTION)) {
val inspection = extension.instance as? IntentionBasedInspection<*> ?: continue val inspection = extension.instance as? IntentionBasedInspection<*> ?: continue
if (inspection.intentions.any { it.intention.javaClass == intentionClass }) { if (inspection.intentionInfos.any { it.intention == intentionClass }) {
intentionBasedInspections[intentionClass] = inspection intentionBasedInspections[intentionClass] = inspection
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
return inspection as IntentionBasedInspection<TElement> return inspection as IntentionBasedInspection<TElement>
@@ -33,14 +33,13 @@ import org.jetbrains.kotlin.types.isNullabilityFlexible
import javax.swing.JComponent import javax.swing.JComponent
class HasPlatformTypeInspection( class HasPlatformTypeInspection(
val intention: SpecifyTypeExplicitlyIntention = SpecifyTypeExplicitlyIntention(),
@JvmField var publicAPIOnly: Boolean = true, @JvmField var publicAPIOnly: Boolean = true,
@JvmField var reportPlatformArguments: Boolean = false @JvmField var reportPlatformArguments: Boolean = false
) : IntentionBasedInspection<KtCallableDeclaration>( ) : IntentionBasedInspection<KtCallableDeclaration>(
intention, SpecifyTypeExplicitlyIntention::class,
{ element, inspection -> { element, inspection ->
with(inspection as HasPlatformTypeInspection) { with(inspection as HasPlatformTypeInspection) {
intention.dangerousFlexibleTypeOrNull(element, this.publicAPIOnly, this.reportPlatformArguments) != null SpecifyTypeExplicitlyIntention.dangerousFlexibleTypeOrNull(element, this.publicAPIOnly, this.reportPlatformArguments) != null
} }
} }
) { ) {
@@ -50,7 +49,7 @@ class HasPlatformTypeInspection(
override val problemText = "Declaration has platform type. Make the type explicit to prevent subtle bugs." override val problemText = "Declaration has platform type. Make the type explicit to prevent subtle bugs."
override fun additionalFixes(element: KtCallableDeclaration): List<LocalQuickFix>? { override fun additionalFixes(element: KtCallableDeclaration): List<LocalQuickFix>? {
val type = intention.dangerousFlexibleTypeOrNull(element, publicAPIOnly, reportPlatformArguments) ?: return null val type = SpecifyTypeExplicitlyIntention.dangerousFlexibleTypeOrNull(element, publicAPIOnly, reportPlatformArguments) ?: return null
if (type.isNullabilityFlexible()) { if (type.isNullabilityFlexible()) {
val expression = element.node.findChildByType(KtTokens.EQ)?.psi?.getNextSiblingIgnoringWhitespaceAndComments() val expression = element.node.findChildByType(KtTokens.EQ)?.psi?.getNextSiblingIgnoringWhitespaceAndComments()
@@ -32,11 +32,9 @@ import org.jetbrains.kotlin.types.isDynamic
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.isUnit
class ConvertLambdaToReferenceInspection( class ConvertLambdaToReferenceInspection() : IntentionBasedInspection<KtLambdaExpression>(
val intention: ConvertLambdaToReferenceIntention = ConvertLambdaToReferenceIntention() ConvertLambdaToReferenceIntention::class,
) : IntentionBasedInspection<KtLambdaExpression>( { it -> ConvertLambdaToReferenceIntention.shouldSuggestToConvert(it) }
intention,
{ it -> intention.shouldSuggestToConvert(it) }
) )
class ConvertLambdaToReferenceIntention : SelfTargetingOffsetIndependentIntention<KtLambdaExpression>( class ConvertLambdaToReferenceIntention : SelfTargetingOffsetIndependentIntention<KtLambdaExpression>(
@@ -79,7 +77,7 @@ class ConvertLambdaToReferenceIntention : SelfTargetingOffsetIndependentIntentio
if (calleeDescriptor.typeParameters.isNotEmpty()) return false if (calleeDescriptor.typeParameters.isNotEmpty()) return false
// No references to Java synthetic properties // No references to Java synthetic properties
if (calleeDescriptor is SyntheticJavaPropertyDescriptor) return false if (calleeDescriptor is SyntheticJavaPropertyDescriptor) return false
val descriptorHasReceiver = with (calleeDescriptor) { val descriptorHasReceiver = with(calleeDescriptor) {
// No references to both member / extension // No references to both member / extension
if (dispatchReceiverParameter != null && extensionReceiverParameter != null) return false if (dispatchReceiverParameter != null && extensionReceiverParameter != null) return false
dispatchReceiverParameter != null || extensionReceiverParameter != null dispatchReceiverParameter != null || extensionReceiverParameter != null
@@ -144,34 +142,6 @@ class ConvertLambdaToReferenceIntention : SelfTargetingOffsetIndependentIntentio
} }
} }
internal fun shouldSuggestToConvert(element: KtLambdaExpression): Boolean {
val body = element.bodyExpression ?: return false
val referenceName = buildReferenceText(body.statements.singleOrNull() ?: return false) ?: return false
return referenceName.length < element.text.length
}
private fun KtCallExpression.getCallReferencedName() = (calleeExpression as? KtNameReferenceExpression)?.getReferencedName()
private fun buildReferenceText(expression: KtExpression): String? {
return when (expression) {
is KtCallExpression -> "::${expression.getCallReferencedName()}"
is KtDotQualifiedExpression -> {
val selector = expression.selectorExpression
val selectorReferenceName = when (selector) {
is KtCallExpression -> selector.getCallReferencedName() ?: return null
is KtNameReferenceExpression -> selector.getReferencedName()
else -> return null
}
val receiver = expression.receiverExpression as? KtNameReferenceExpression ?: return null
val context = receiver.analyze()
val receiverDescriptor = context[REFERENCE_TARGET, receiver] as? ParameterDescriptor ?: return null
val receiverType = receiverDescriptor.type
"$receiverType::$selectorReferenceName"
}
else -> null
}
}
override fun applyTo(element: KtLambdaExpression, editor: Editor?) { override fun applyTo(element: KtLambdaExpression, editor: Editor?) {
val body = element.bodyExpression ?: return val body = element.bodyExpression ?: return
val referenceName = buildReferenceText(body.statements.singleOrNull() ?: return) ?: return val referenceName = buildReferenceText(body.statements.singleOrNull() ?: return) ?: return
@@ -221,4 +191,34 @@ class ConvertLambdaToReferenceIntention : SelfTargetingOffsetIndependentIntentio
} }
} }
} }
companion object {
internal fun shouldSuggestToConvert(element: KtLambdaExpression): Boolean {
val body = element.bodyExpression ?: return false
val referenceName = buildReferenceText(body.statements.singleOrNull() ?: return false) ?: return false
return referenceName.length < element.text.length
}
private fun buildReferenceText(expression: KtExpression): String? {
return when (expression) {
is KtCallExpression -> "::${expression.getCallReferencedName()}"
is KtDotQualifiedExpression -> {
val selector = expression.selectorExpression
val selectorReferenceName = when (selector) {
is KtCallExpression -> selector.getCallReferencedName() ?: return null
is KtNameReferenceExpression -> selector.getReferencedName()
else -> return null
}
val receiver = expression.receiverExpression as? KtNameReferenceExpression ?: return null
val context = receiver.analyze()
val receiverDescriptor = context[REFERENCE_TARGET, receiver] as? ParameterDescriptor ?: return null
val receiverType = receiverDescriptor.type
"$receiverType::$selectorReferenceName"
}
else -> null
}
}
private fun KtCallExpression.getCallReferencedName() = (calleeExpression as? KtNameReferenceExpression)?.getReferencedName()
}
} }
@@ -29,8 +29,8 @@ import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluat
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class ConvertToStringTemplateInspection : IntentionBasedInspection<KtBinaryExpression>( class ConvertToStringTemplateInspection : IntentionBasedInspection<KtBinaryExpression>(
ConvertToStringTemplateIntention(), ConvertToStringTemplateIntention::class,
{ it -> ConvertToStringTemplateIntention().shouldSuggestToConvert(it) } { it -> ConvertToStringTemplateIntention.shouldSuggestToConvert(it) }
) )
class ConvertToStringTemplateIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Convert concatenation to template") { class ConvertToStringTemplateIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Convert concatenation to template") {
@@ -47,101 +47,103 @@ class ConvertToStringTemplateIntention : SelfTargetingOffsetIndependentIntention
element.replaced(buildReplacement(element)) element.replaced(buildReplacement(element))
} }
fun shouldSuggestToConvert(expression: KtBinaryExpression): Boolean { companion object {
val entries = buildReplacement(expression).entries fun shouldSuggestToConvert(expression: KtBinaryExpression): Boolean {
return entries.none { it is KtBlockStringTemplateEntry } val entries = buildReplacement(expression).entries
&& !entries.all { it is KtLiteralStringTemplateEntry || it is KtEscapeStringTemplateEntry } return entries.none { it is KtBlockStringTemplateEntry }
&& entries.count { it is KtLiteralStringTemplateEntry } > 1 && !entries.all { it is KtLiteralStringTemplateEntry || it is KtEscapeStringTemplateEntry }
&& !expression.textContains('\n') && entries.count { it is KtLiteralStringTemplateEntry } > 1
} && !expression.textContains('\n')
private fun isApplicableToNoParentCheck(expression: KtBinaryExpression): Boolean {
if (expression.operationToken != KtTokens.PLUS) return false
val expressionType = expression.analyze(BodyResolveMode.PARTIAL).getType(expression)
if (!KotlinBuiltIns.isString(expressionType)) return false
return isSuitable(expression)
}
private fun isSuitable(expression: KtExpression): Boolean {
if (expression is KtBinaryExpression && expression.operationToken == KtTokens.PLUS) {
return isSuitable(expression.left ?: return false) && isSuitable(expression.right ?: return false)
} }
if (PsiUtilCore.hasErrorElementChild(expression)) return false private fun buildReplacement(expression: KtBinaryExpression): KtStringTemplateExpression {
if (expression.textContains('\n')) return false val rightText = buildText(expression.right, false)
return true return fold(expression.left, rightText, KtPsiFactory(expression))
}
private fun buildReplacement(expression: KtBinaryExpression): KtStringTemplateExpression {
val rightText = buildText(expression.right, false)
return fold(expression.left, rightText, KtPsiFactory(expression))
}
private fun fold(left: KtExpression?, right: String, factory: KtPsiFactory): KtStringTemplateExpression {
val forceBraces = !right.isEmpty() && right.first() != '$' && right.first().isJavaIdentifierPart()
if (left is KtBinaryExpression && isApplicableToNoParentCheck(left)) {
val leftRight = buildText(left.right, forceBraces)
return fold(left.left, leftRight + right, factory)
} }
else {
val leftText = buildText(left, forceBraces)
return factory.createExpression("\"$leftText$right\"") as KtStringTemplateExpression
}
}
private fun buildText(expr: KtExpression?, forceBraces: Boolean): String { private fun fold(left: KtExpression?, right: String, factory: KtPsiFactory): KtStringTemplateExpression {
if (expr == null) return "" val forceBraces = !right.isEmpty() && right.first() != '$' && right.first().isJavaIdentifierPart()
val expression = KtPsiUtil.safeDeparenthesize(expr)
val expressionText = expression.text
when (expression) {
is KtConstantExpression -> {
val bindingContext = expression.analyze(BodyResolveMode.PARTIAL)
val type = bindingContext.getType(expression)!!
if (KotlinBuiltIns.isChar(type)) { if (left is KtBinaryExpression && isApplicableToNoParentCheck(left)) {
val value = expressionText.removePrefix("'").removeSuffix("'") val leftRight = buildText(left.right, forceBraces)
return when (value) { // escape double quote and unescape single one return fold(left.left, leftRight + right, factory)
"\"" -> "\\\""
"\\'" -> "'"
else -> value
}
}
val constant = ConstantExpressionEvaluator.getConstant(expression, bindingContext)
val stringValue = constant?.getValue(type).toString()
if (stringValue == expressionText) {
return StringUtil.escapeStringCharacters(stringValue)
}
} }
else {
val leftText = buildText(left, forceBraces)
return factory.createExpression("\"$leftText$right\"") as KtStringTemplateExpression
}
}
is KtStringTemplateExpression -> { private fun buildText(expr: KtExpression?, forceBraces: Boolean): String {
val base = if (expressionText.startsWith("\"\"\"") && expressionText.endsWith("\"\"\"")) { if (expr == null) return ""
val unquoted = expressionText.substring(3, expressionText.length - 3) val expression = KtPsiUtil.safeDeparenthesize(expr)
StringUtil.escapeStringCharacters(unquoted) val expressionText = expression.text
} when (expression) {
else { is KtConstantExpression -> {
StringUtil.unquoteString(expressionText) val bindingContext = expression.analyze(BodyResolveMode.PARTIAL)
} val type = bindingContext.getType(expression)!!
if (forceBraces) { if (KotlinBuiltIns.isChar(type)) {
if (base.endsWith('$')) { val value = expressionText.removePrefix("'").removeSuffix("'")
return base.dropLast(1) + "\\$" return when (value) { // escape double quote and unescape single one
} "\"" -> "\\\""
else { "\\'" -> "'"
val lastPart = expression.children.lastOrNull() else -> value
if (lastPart is KtSimpleNameStringTemplateEntry) {
return base.dropLast(lastPart.textLength) + "\${" + lastPart.text.drop(1) + "}"
} }
} }
val constant = ConstantExpressionEvaluator.getConstant(expression, bindingContext)
val stringValue = constant?.getValue(type).toString()
if (stringValue == expressionText) {
return StringUtil.escapeStringCharacters(stringValue)
}
} }
return base
is KtStringTemplateExpression -> {
val base = if (expressionText.startsWith("\"\"\"") && expressionText.endsWith("\"\"\"")) {
val unquoted = expressionText.substring(3, expressionText.length - 3)
StringUtil.escapeStringCharacters(unquoted)
}
else {
StringUtil.unquoteString(expressionText)
}
if (forceBraces) {
if (base.endsWith('$')) {
return base.dropLast(1) + "\\$"
}
else {
val lastPart = expression.children.lastOrNull()
if (lastPart is KtSimpleNameStringTemplateEntry) {
return base.dropLast(lastPart.textLength) + "\${" + lastPart.text.drop(1) + "}"
}
}
}
return base
}
is KtNameReferenceExpression ->
return "$" + (if (forceBraces) "{$expressionText}" else expressionText)
} }
is KtNameReferenceExpression -> return "\${$expressionText}"
return "$" + (if (forceBraces) "{$expressionText}" else expressionText)
} }
return "\${$expressionText}" private fun isApplicableToNoParentCheck(expression: KtBinaryExpression): Boolean {
if (expression.operationToken != KtTokens.PLUS) return false
val expressionType = expression.analyze(BodyResolveMode.PARTIAL).getType(expression)
if (!KotlinBuiltIns.isString(expressionType)) return false
return isSuitable(expression)
}
private fun isSuitable(expression: KtExpression): Boolean {
if (expression is KtBinaryExpression && expression.operationToken == KtTokens.PLUS) {
return isSuitable(expression.left ?: return false) && isSuitable(expression.right ?: return false)
}
if (PsiUtilCore.hasErrorElementChild(expression)) return false
if (expression.textContains('\n')) return false
return true
}
} }
} }
@@ -25,12 +25,12 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.idea.core.moveCaret import org.jetbrains.kotlin.idea.core.moveCaret
import org.jetbrains.kotlin.idea.core.unblockDocument import org.jetbrains.kotlin.idea.core.unblockDocument
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.idea.util.ImportInsertHelper import org.jetbrains.kotlin.idea.util.ImportInsertHelper
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
@@ -42,7 +42,7 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension
import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.isUnit
import java.util.* import java.util.*
class DeprecatedCallableAddReplaceWithInspection : IntentionBasedInspection<KtCallableDeclaration>(DeprecatedCallableAddReplaceWithIntention()) class DeprecatedCallableAddReplaceWithInspection : IntentionBasedInspection<KtCallableDeclaration>(DeprecatedCallableAddReplaceWithIntention::class)
class DeprecatedCallableAddReplaceWithIntention : SelfTargetingRangeIntention<KtCallableDeclaration>( class DeprecatedCallableAddReplaceWithIntention : SelfTargetingRangeIntention<KtCallableDeclaration>(
KtCallableDeclaration::class.java, "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"
@@ -35,7 +35,7 @@ import org.jetbrains.kotlin.types.typeUtil.isNothing
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
class IfNullToElvisInspection : IntentionBasedInspection<KtIfExpression>(IfNullToElvisIntention()) class IfNullToElvisInspection : IntentionBasedInspection<KtIfExpression>(IfNullToElvisIntention::class)
class IfNullToElvisIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' with elvis operator"){ class IfNullToElvisIntention : SelfTargetingRangeIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' with elvis operator"){
override fun applicabilityRange(element: KtIfExpression): TextRange? { override fun applicabilityRange(element: KtIfExpression): TextRange? {
@@ -24,13 +24,13 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.core.moveFunctionLiteralOutsideParentheses import org.jetbrains.kotlin.idea.core.moveFunctionLiteralOutsideParentheses
import org.jetbrains.kotlin.idea.core.replaced import org.jetbrains.kotlin.idea.core.replaced
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.idea.inspections.RedundantSamConstructorInspection 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.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
@@ -43,7 +43,7 @@ import org.jetbrains.kotlin.resolve.calls.callUtil.getCalleeExpressionIfAny
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
class ObjectLiteralToLambdaInspection : IntentionBasedInspection<KtObjectLiteralExpression>(ObjectLiteralToLambdaIntention()) class ObjectLiteralToLambdaInspection : IntentionBasedInspection<KtObjectLiteralExpression>(ObjectLiteralToLambdaIntention::class)
class ObjectLiteralToLambdaIntention : SelfTargetingRangeIntention<KtObjectLiteralExpression>( class ObjectLiteralToLambdaIntention : SelfTargetingRangeIntention<KtObjectLiteralExpression>(
KtObjectLiteralExpression::class.java, KtObjectLiteralExpression::class.java,
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.psi.KtAnnotatedExpression
import org.jetbrains.kotlin.psi.KtAnnotationEntry import org.jetbrains.kotlin.psi.KtAnnotationEntry
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
class RemoveAtFromAnnotationArgumentInspection : IntentionBasedInspection<KtAnnotatedExpression>(RemoveAtFromAnnotationArgumentIntention()) class RemoveAtFromAnnotationArgumentInspection : IntentionBasedInspection<KtAnnotatedExpression>(RemoveAtFromAnnotationArgumentIntention::class)
class RemoveAtFromAnnotationArgumentIntention : SelfTargetingOffsetIndependentIntention<KtAnnotatedExpression>( class RemoveAtFromAnnotationArgumentIntention : SelfTargetingOffsetIndependentIntention<KtAnnotatedExpression>(
KtAnnotatedExpression::class.java, KtAnnotatedExpression::class.java,
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtStringTemplateEntryWithExpression import org.jetbrains.kotlin.psi.KtStringTemplateEntryWithExpression
import org.jetbrains.kotlin.psi.psiUtil.canPlaceAfterSimpleNameEntry import org.jetbrains.kotlin.psi.psiUtil.canPlaceAfterSimpleNameEntry
class RemoveCurlyBracesFromTemplateInspection : IntentionBasedInspection<KtBlockStringTemplateEntry>(RemoveCurlyBracesFromTemplateIntention()) class RemoveCurlyBracesFromTemplateInspection : IntentionBasedInspection<KtBlockStringTemplateEntry>(RemoveCurlyBracesFromTemplateIntention::class)
class RemoveCurlyBracesFromTemplateIntention : SelfTargetingOffsetIndependentIntention<KtBlockStringTemplateEntry>(KtBlockStringTemplateEntry::class.java, "Remove curly braces") { class RemoveCurlyBracesFromTemplateIntention : SelfTargetingOffsetIndependentIntention<KtBlockStringTemplateEntry>(KtBlockStringTemplateEntry::class.java, "Remove curly braces") {
override fun isApplicableTo(element: KtBlockStringTemplateEntry): Boolean { override fun isApplicableTo(element: KtBlockStringTemplateEntry): Boolean {
@@ -23,8 +23,8 @@ import com.intellij.openapi.util.TextRange
import org.jetbrains.kotlin.idea.analysis.analyzeInContext import org.jetbrains.kotlin.idea.analysis.analyzeInContext
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.util.getResolutionScope
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.KtQualifiedExpression import org.jetbrains.kotlin.psi.KtQualifiedExpression
import org.jetbrains.kotlin.psi.KtSuperExpression import org.jetbrains.kotlin.psi.KtSuperExpression
@@ -39,7 +39,7 @@ import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.types.ErrorUtils import org.jetbrains.kotlin.types.ErrorUtils
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
class RemoveExplicitSuperQualifierInspection : IntentionBasedInspection<KtSuperExpression>(RemoveExplicitSuperQualifierIntention()), CleanupLocalInspectionTool { class RemoveExplicitSuperQualifierInspection : IntentionBasedInspection<KtSuperExpression>(RemoveExplicitSuperQualifierIntention::class), CleanupLocalInspectionTool {
override val problemHighlightType: ProblemHighlightType override val problemHighlightType: ProblemHighlightType
get() = ProblemHighlightType.LIKE_UNUSED_SYMBOL get() = ProblemHighlightType.LIKE_UNUSED_SYMBOL
} }
@@ -18,9 +18,9 @@ package org.jetbrains.kotlin.idea.intentions
import com.intellij.codeInspection.ProblemHighlightType import com.intellij.codeInspection.ProblemHighlightType
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.idea.resolve.frontendService
import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.idea.util.getResolutionScope
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
@@ -34,7 +34,7 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.checker.KotlinTypeChecker import org.jetbrains.kotlin.types.checker.KotlinTypeChecker
class RemoveExplicitTypeArgumentsInspection : IntentionBasedInspection<KtTypeArgumentList>(RemoveExplicitTypeArgumentsIntention()) { class RemoveExplicitTypeArgumentsInspection : IntentionBasedInspection<KtTypeArgumentList>(RemoveExplicitTypeArgumentsIntention::class) {
override val problemHighlightType: ProblemHighlightType override val problemHighlightType: ProblemHighlightType
get() = ProblemHighlightType.LIKE_UNUSED_SYMBOL get() = ProblemHighlightType.LIKE_UNUSED_SYMBOL
} }
@@ -25,11 +25,10 @@ import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.getStartOffsetIn import org.jetbrains.kotlin.psi.psiUtil.getStartOffsetIn
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
class RemoveSetterParameterTypeInspection( class RemoveSetterParameterTypeInspection()
val intention: RemoveExplicitTypeIntention = RemoveExplicitTypeIntention() : IntentionBasedInspection<KtCallableDeclaration>(
) : IntentionBasedInspection<KtCallableDeclaration>( RemoveExplicitTypeIntention::class,
intention, { it -> RemoveExplicitTypeIntention.isSetterParameter(it) }
{ it -> intention.isSetterParameter(it) }
) { ) {
override val problemHighlightType = ProblemHighlightType.LIKE_UNUSED_SYMBOL override val problemHighlightType = ProblemHighlightType.LIKE_UNUSED_SYMBOL
@@ -44,11 +43,6 @@ class RemoveExplicitTypeIntention : SelfTargetingRangeIntention<KtCallableDeclar
"Remove explicit type specification" "Remove explicit type specification"
) { ) {
private val KtParameter.isSetterParameter: Boolean get() = (parent?.parent as? KtPropertyAccessor)?.isSetter ?: false
fun isSetterParameter(element: KtCallableDeclaration) =
element is KtParameter && element.isSetterParameter
override fun applicabilityRange(element: KtCallableDeclaration): TextRange? { override fun applicabilityRange(element: KtCallableDeclaration): TextRange? {
if (element.containingFile is KtCodeFragment) return null if (element.containingFile is KtCodeFragment) return null
if (element.typeReference == null) return null if (element.typeReference == null) return null
@@ -66,4 +60,11 @@ class RemoveExplicitTypeIntention : SelfTargetingRangeIntention<KtCallableDeclar
override fun applyTo(element: KtCallableDeclaration, editor: Editor?) { override fun applyTo(element: KtCallableDeclaration, editor: Editor?) {
element.typeReference = null element.typeReference = null
} }
companion object {
fun isSetterParameter(element: KtCallableDeclaration) =
element is KtParameter && element.isSetterParameter
private val KtParameter.isSetterParameter: Boolean get() = (parent?.parent as? KtPropertyAccessor)?.isSetter ?: false
}
} }
@@ -32,8 +32,8 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class RemoveForLoopIndicesInspection : IntentionBasedInspection<KtForExpression>( class RemoveForLoopIndicesInspection : IntentionBasedInspection<KtForExpression>(
RemoveForLoopIndicesIntention(), RemoveForLoopIndicesIntention::class,
problemText = "Index is not used in the loop body" "Index is not used in the loop body"
) { ) {
override val problemHighlightType: ProblemHighlightType override val problemHighlightType: ProblemHighlightType
get() = ProblemHighlightType.LIKE_UNUSED_SYMBOL get() = ProblemHighlightType.LIKE_UNUSED_SYMBOL
@@ -30,7 +30,7 @@ private fun KtStringTemplateExpression.singleExpressionOrNull() =
children.singleOrNull()?.children?.firstOrNull() as? KtExpression children.singleOrNull()?.children?.firstOrNull() as? KtExpression
class RemoveSingleExpressionStringTemplateInspection : IntentionBasedInspection<KtStringTemplateExpression>( class RemoveSingleExpressionStringTemplateInspection : IntentionBasedInspection<KtStringTemplateExpression>(
RemoveSingleExpressionStringTemplateIntention(), RemoveSingleExpressionStringTemplateIntention::class,
additionalChecker = { additionalChecker = {
templateExpression -> templateExpression ->
templateExpression.singleExpressionOrNull()?.let { templateExpression.singleExpressionOrNull()?.let {
@@ -23,12 +23,15 @@ import org.jetbrains.kotlin.idea.caches.resolve.analyzeFully
import org.jetbrains.kotlin.idea.conversion.copy.range import org.jetbrains.kotlin.idea.conversion.copy.range
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
class RemoveUnnecessaryLateinitInspection : IntentionBasedInspection<KtProperty>(RemoveUnnecessaryLateinitIntention()) { class RemoveUnnecessaryLateinitInspection : IntentionBasedInspection<KtProperty>(RemoveUnnecessaryLateinitIntention::class) {
override val problemHighlightType = ProblemHighlightType.LIKE_UNUSED_SYMBOL override val problemHighlightType = ProblemHighlightType.LIKE_UNUSED_SYMBOL
override val problemText = "Unnecessary lateinit" override val problemText = "Unnecessary lateinit"
@@ -35,7 +35,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
class ReplaceWithOperatorAssignmentInspection : IntentionBasedInspection<KtBinaryExpression>(ReplaceWithOperatorAssignmentIntention()) class ReplaceWithOperatorAssignmentInspection : IntentionBasedInspection<KtBinaryExpression>(ReplaceWithOperatorAssignmentIntention::class)
class ReplaceWithOperatorAssignmentIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Replace with operator-assignment") { class ReplaceWithOperatorAssignmentIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Replace with operator-assignment") {
override fun isApplicableTo(element: KtBinaryExpression): Boolean { override fun isApplicableTo(element: KtBinaryExpression): Boolean {
@@ -20,12 +20,12 @@ import com.intellij.codeInsight.CodeInsightUtilCore
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.core.ShortenReferences
import org.jetbrains.kotlin.idea.core.moveCaret
import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.expressionComparedToNull import org.jetbrains.kotlin.idea.intentions.branchedTransformations.expressionComparedToNull
import org.jetbrains.kotlin.idea.core.moveCaret
import org.jetbrains.kotlin.idea.util.CommentSaver import org.jetbrains.kotlin.idea.util.CommentSaver
import org.jetbrains.kotlin.idea.core.ShortenReferences
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.endOffset import org.jetbrains.kotlin.psi.psiUtil.endOffset
@@ -36,7 +36,7 @@ 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.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
class SimplifyAssertNotNullInspection : IntentionBasedInspection<KtCallExpression>(SimplifyAssertNotNullIntention()) class SimplifyAssertNotNullInspection : IntentionBasedInspection<KtCallExpression>(SimplifyAssertNotNullIntention::class)
class SimplifyAssertNotNullIntention : SelfTargetingOffsetIndependentIntention<KtCallExpression>( class SimplifyAssertNotNullIntention : SelfTargetingOffsetIndependentIntention<KtCallExpression>(
KtCallExpression::class.java, KtCallExpression::class.java,
@@ -26,9 +26,8 @@ import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
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.CompileTimeConstantUtils import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
import org.jetbrains.kotlin.resolve.DelegatingBindingTrace
class SimplifyBooleanWithConstantsInspection : IntentionBasedInspection<KtBinaryExpression>(SimplifyBooleanWithConstantsIntention()) class SimplifyBooleanWithConstantsInspection : IntentionBasedInspection<KtBinaryExpression>(SimplifyBooleanWithConstantsIntention::class)
class SimplifyBooleanWithConstantsIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Simplify boolean expression") { class SimplifyBooleanWithConstantsIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Simplify boolean expression") {
@@ -37,9 +37,8 @@ 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.descriptorUtil.builtIns import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import java.util.* import java.util.*
import kotlin.collections.forEach
class SimplifyForInspection : IntentionBasedInspection<KtForExpression>(SimplifyForIntention()) class SimplifyForInspection : IntentionBasedInspection<KtForExpression>(SimplifyForIntention::class)
class SimplifyForIntention : SelfTargetingRangeIntention<KtForExpression>( class SimplifyForIntention : SelfTargetingRangeIntention<KtForExpression>(
KtForExpression::class.java, KtForExpression::class.java,
@@ -24,7 +24,7 @@ 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.*
class SimplifyNegatedBinaryExpressionInspection : IntentionBasedInspection<KtPrefixExpression>(SimplifyNegatedBinaryExpressionIntention()) class SimplifyNegatedBinaryExpressionInspection : IntentionBasedInspection<KtPrefixExpression>(SimplifyNegatedBinaryExpressionIntention::class)
class SimplifyNegatedBinaryExpressionIntention : SelfTargetingRangeIntention<KtPrefixExpression>(KtPrefixExpression::class.java, "Simplify negated binary expression") { class SimplifyNegatedBinaryExpressionIntention : SelfTargetingRangeIntention<KtPrefixExpression>(KtPrefixExpression::class.java, "Simplify negated binary expression") {
@@ -51,29 +51,6 @@ class SpecifyTypeExplicitlyIntention :
SelfTargetingRangeIntention<KtCallableDeclaration>(KtCallableDeclaration::class.java, "Specify type explicitly"), SelfTargetingRangeIntention<KtCallableDeclaration>(KtCallableDeclaration::class.java, "Specify type explicitly"),
LowPriorityAction { LowPriorityAction {
fun dangerousFlexibleTypeOrNull(
declaration: KtCallableDeclaration, publicAPIOnly: Boolean, reportPlatformArguments: Boolean
): KotlinType? {
when (declaration) {
is KtFunction -> if (declaration.isLocal || declaration.hasDeclaredReturnType()) return null
is KtProperty -> if (declaration.isLocal || declaration.typeReference != null) return null
else -> return null
}
if (declaration.containingClassOrObject?.isLocal() ?: false) return null
val callable = declaration.resolveToDescriptorIfAny() as? CallableDescriptor ?: return null
if (publicAPIOnly && !callable.visibility.isPublicAPI) return null
val type = callable.returnType ?: return null
if (reportPlatformArguments) {
if (!type.isFlexibleRecursive()) return null
}
else {
if (!type.isFlexible()) return null
}
return type
}
override fun applicabilityRange(element: KtCallableDeclaration): TextRange? { override fun applicabilityRange(element: KtCallableDeclaration): TextRange? {
if (element.containingFile is KtCodeFragment) return null if (element.containingFile is KtCodeFragment) return null
if (element is KtFunctionLiteral) return null // TODO: should KtFunctionLiteral be KtCallableDeclaration at all? if (element is KtFunctionLiteral) return null // TODO: should KtFunctionLiteral be KtCallableDeclaration at all?
@@ -108,6 +85,29 @@ class SpecifyTypeExplicitlyIntention :
private val PropertyDescriptor.setterType: KotlinType? private val PropertyDescriptor.setterType: KotlinType?
get() = setter?.valueParameters?.firstOrNull()?.type?.let { if (it.isError) null else it } get() = setter?.valueParameters?.firstOrNull()?.type?.let { if (it.isError) null else it }
fun dangerousFlexibleTypeOrNull(
declaration: KtCallableDeclaration, publicAPIOnly: Boolean, reportPlatformArguments: Boolean
): KotlinType? {
when (declaration) {
is KtFunction -> if (declaration.isLocal || declaration.hasDeclaredReturnType()) return null
is KtProperty -> if (declaration.isLocal || declaration.typeReference != null) return null
else -> return null
}
if (declaration.containingClassOrObject?.isLocal() ?: false) return null
val callable = declaration.resolveToDescriptorIfAny() as? CallableDescriptor ?: return null
if (publicAPIOnly && !callable.visibility.isPublicAPI) return null
val type = callable.returnType ?: return null
if (reportPlatformArguments) {
if (!type.isFlexibleRecursive()) return null
}
else {
if (!type.isFlexible()) return null
}
return type
}
fun getTypeForDeclaration(declaration: KtCallableDeclaration): KotlinType { 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)?.returnType val type = (descriptor as? CallableDescriptor)?.returnType
@@ -55,7 +55,7 @@ import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.typeUtil.isUnit import org.jetbrains.kotlin.types.typeUtil.isUnit
class UsePropertyAccessSyntaxInspection : IntentionBasedInspection<KtCallExpression>(UsePropertyAccessSyntaxIntention()), CleanupLocalInspectionTool class UsePropertyAccessSyntaxInspection : IntentionBasedInspection<KtCallExpression>(UsePropertyAccessSyntaxIntention::class), CleanupLocalInspectionTool
class UsePropertyAccessSyntaxIntention : SelfTargetingOffsetIndependentIntention<KtCallExpression>(KtCallExpression::class.java, "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 {
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.idea.intentions.branchedTransformations.*
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
class IfThenToElvisInspection : IntentionBasedInspection<KtIfExpression>(IfThenToElvisIntention()) class IfThenToElvisInspection : IntentionBasedInspection<KtIfExpression>(IfThenToElvisIntention::class)
class IfThenToElvisIntention : SelfTargetingOffsetIndependentIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' expression with elvis expression") { class IfThenToElvisIntention : SelfTargetingOffsetIndependentIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' expression with elvis expression") {
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.idea.intentions.branchedTransformations.*
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
class IfThenToSafeAccessInspection : IntentionBasedInspection<KtIfExpression>(IfThenToSafeAccessIntention()) class IfThenToSafeAccessInspection : IntentionBasedInspection<KtIfExpression>(IfThenToSafeAccessIntention::class)
class IfThenToSafeAccessIntention : SelfTargetingOffsetIndependentIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' expression with safe access expression") { class IfThenToSafeAccessIntention : SelfTargetingOffsetIndependentIntention<KtIfExpression>(KtIfExpression::class.java, "Replace 'if' expression with safe access expression") {
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.idea.intentions.branchedTransformations.getSubjectTo
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.introduceSubject import org.jetbrains.kotlin.idea.intentions.branchedTransformations.introduceSubject
import org.jetbrains.kotlin.psi.KtWhenExpression import org.jetbrains.kotlin.psi.KtWhenExpression
class IntroduceWhenSubjectInspection : IntentionBasedInspection<KtWhenExpression>(IntroduceWhenSubjectIntention()) class IntroduceWhenSubjectInspection : IntentionBasedInspection<KtWhenExpression>(IntroduceWhenSubjectIntention::class)
class IntroduceWhenSubjectIntention : SelfTargetingRangeIntention<KtWhenExpression>(KtWhenExpression::class.java, "Introduce argument to 'when'") { class IntroduceWhenSubjectIntention : SelfTargetingRangeIntention<KtWhenExpression>(KtWhenExpression::class.java, "Introduce argument to 'when'") {
override fun applicabilityRange(element: KtWhenExpression): TextRange? { override fun applicabilityRange(element: KtWhenExpression): TextRange? {
@@ -19,25 +19,25 @@ package org.jetbrains.kotlin.idea.intentions.conventionNameCalls
import com.intellij.codeInsight.intention.HighPriorityAction import com.intellij.codeInsight.intention.HighPriorityAction
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.TextRange import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.IElementType import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import com.intellij.psi.PsiElement import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
import org.jetbrains.kotlin.idea.intentions.* import org.jetbrains.kotlin.idea.intentions.callExpression
import org.jetbrains.kotlin.idea.intentions.isReceiverExpressionWithValue
import org.jetbrains.kotlin.idea.intentions.toResolvedCall
import org.jetbrains.kotlin.lexer.KtSingleValueToken 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 org.jetbrains.kotlin.psi.psiUtil.getLastParentOfTypeInRow import org.jetbrains.kotlin.psi.psiUtil.getLastParentOfTypeInRow
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess 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
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
class ReplaceCallWithComparisonInspection( class ReplaceCallWithComparisonInspection() : IntentionBasedInspection<KtDotQualifiedExpression>(
val intention: ReplaceCallWithBinaryOperatorIntention = ReplaceCallWithBinaryOperatorIntention() ReplaceCallWithBinaryOperatorIntention::class,
) : IntentionBasedInspection<KtDotQualifiedExpression>(
intention,
{ qualifiedExpression -> { qualifiedExpression ->
val calleeExpression = qualifiedExpression.callExpression?.calleeExpression as? KtSimpleNameExpression val calleeExpression = qualifiedExpression.callExpression?.calleeExpression as? KtSimpleNameExpression
val identifier = calleeExpression?.getReferencedNameAsName() val identifier = calleeExpression?.getReferencedNameAsName()
@@ -42,7 +42,7 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.util.isValidOperator import org.jetbrains.kotlin.util.isValidOperator
class ReplaceGetOrSetInspection : IntentionBasedInspection<KtDotQualifiedExpression>( class ReplaceGetOrSetInspection : IntentionBasedInspection<KtDotQualifiedExpression>(
ReplaceGetOrSetIntention(), ReplaceGetOrSetInspection.additionalChecker ReplaceGetOrSetIntention::class, ReplaceGetOrSetInspection.additionalChecker
) { ) {
companion object { companion object {
@@ -28,9 +28,9 @@ import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.psiUtil.startOffset import org.jetbrains.kotlin.psi.psiUtil.startOffset
class LoopToCallChainInspection : IntentionBasedInspection<KtForExpression>( class LoopToCallChainInspection : IntentionBasedInspection<KtForExpression>(
listOf(IntentionData(LoopToCallChainIntention()), IntentionData(LoopToLazyCallChainIntention())), listOf(IntentionData(LoopToCallChainIntention::class), IntentionData(LoopToLazyCallChainIntention::class)),
problemText = "Loop can be replaced with stdlib operations", problemText = "Loop can be replaced with stdlib operations"
elementType = KtForExpression::class.java) )
class LoopToCallChainIntention : AbstractLoopToCallChainIntention(lazy = false, text = "Replace with stdlib operations") class LoopToCallChainIntention : AbstractLoopToCallChainIntention(lazy = false, text = "Replace with stdlib operations")
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.psi.KtForExpression
import org.jetbrains.kotlin.psi.KtPsiFactory import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.psi.createExpressionByPattern import org.jetbrains.kotlin.psi.createExpressionByPattern
class UseWithIndexInspection : IntentionBasedInspection<KtForExpression>(UseWithIndexIntention()) class UseWithIndexInspection : IntentionBasedInspection<KtForExpression>(UseWithIndexIntention::class)
class UseWithIndexIntention : SelfTargetingRangeIntention<KtForExpression>( class UseWithIndexIntention : SelfTargetingRangeIntention<KtForExpression>(
KtForExpression::class.java, KtForExpression::class.java,
@@ -190,7 +190,7 @@ object J2KPostProcessingRegistrar {
private val intention = ConvertToStringTemplateIntention() private val intention = ConvertToStringTemplateIntention()
override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? { override fun createAction(element: KtElement, diagnostics: Diagnostics): (() -> Unit)? {
if (element is KtBinaryExpression && intention.isApplicableTo(element) && intention.shouldSuggestToConvert(element)) { if (element is KtBinaryExpression && intention.isApplicableTo(element) && ConvertToStringTemplateIntention.shouldSuggestToConvert(element)) {
return { intention.applyTo(element, null) } return { intention.applyTo(element, null) }
} }
else { else {
@@ -20,7 +20,8 @@ import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
import org.jetbrains.kotlin.psi.KtPackageDirective import org.jetbrains.kotlin.psi.KtPackageDirective
class PackageDirectoryMismatchInspection: IntentionBasedInspection<KtPackageDirective>( class PackageDirectoryMismatchInspection: IntentionBasedInspection<KtPackageDirective>(
listOf(IntentionBasedInspection.IntentionData(MoveFileToPackageMatchingDirectoryIntention()), IntentionBasedInspection.IntentionData(ChangePackageToMatchDirectoryIntention())), listOf(
"Package directive doesn't match file location", IntentionBasedInspection.IntentionData(MoveFileToPackageMatchingDirectoryIntention::class),
KtPackageDirective::class.java IntentionBasedInspection.IntentionData(ChangePackageToMatchDirectoryIntention::class)),
"Package directive doesn't match file location"
) )