IntentionBasedInspection: Removing synchronizing on intention instances
Recreate intention instance in `buildVisitor` Lock caused contention for UpSource
This commit is contained in:
+28
-23
@@ -31,34 +31,34 @@ import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.psi.PsiFile
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
abstract class IntentionBasedInspection<TElement : PsiElement>(
|
||||
val intentions: List<IntentionBasedInspection.IntentionData<TElement>>,
|
||||
protected open val problemText: String?,
|
||||
protected val elementType: Class<TElement>
|
||||
val intentionInfos: List<IntentionBasedInspection.IntentionData<TElement>>,
|
||||
protected open val problemText: String?
|
||||
) : AbstractKotlinInspection() {
|
||||
|
||||
constructor(
|
||||
intention: SelfTargetingRangeIntention<TElement>,
|
||||
intention: KClass<out SelfTargetingRangeIntention<TElement>>,
|
||||
problemText: String? = null
|
||||
) : this(listOf(IntentionData(intention)), problemText, intention.elementType)
|
||||
) : this(listOf(IntentionData(intention)), problemText)
|
||||
|
||||
constructor(
|
||||
intention: SelfTargetingRangeIntention<TElement>,
|
||||
intention: KClass<out SelfTargetingRangeIntention<TElement>>,
|
||||
additionalChecker: (TElement, IntentionBasedInspection<TElement>) -> Boolean,
|
||||
problemText: String? = null
|
||||
) : this(listOf(IntentionData(intention, additionalChecker)), problemText, intention.elementType)
|
||||
) : this(listOf(IntentionData(intention, additionalChecker)), problemText)
|
||||
|
||||
constructor(
|
||||
intention: SelfTargetingRangeIntention<TElement>,
|
||||
intention: KClass<out SelfTargetingRangeIntention<TElement>>,
|
||||
additionalChecker: (TElement) -> Boolean,
|
||||
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>(
|
||||
val intention: SelfTargetingRangeIntention<TElement>,
|
||||
val intention: KClass<out SelfTargetingRangeIntention<TElement>>,
|
||||
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
|
||||
|
||||
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() {
|
||||
override fun visitElement(element: PsiElement) {
|
||||
if (!elementType.isInstance(element) || element.textLength == 0) return
|
||||
@@ -77,21 +84,19 @@ abstract class IntentionBasedInspection<TElement : PsiElement>(
|
||||
var problemRange: TextRange? = null
|
||||
var fixes: SmartList<LocalQuickFix>? = null
|
||||
|
||||
for ((intention, additionalChecker) in intentions) {
|
||||
synchronized(intention) {
|
||||
val range = intention.applicabilityRange(targetElement)?.let { range ->
|
||||
val elementRange = targetElement.textRange
|
||||
assert(range in elementRange) { "Wrong applicabilityRange() result for $intention - should be within element's range" }
|
||||
range.shiftRight(-elementRange.startOffset)
|
||||
}
|
||||
for ((intention, additionalChecker) in intentionsAndCheckers) {
|
||||
val range = intention.applicabilityRange(targetElement)?.let { range ->
|
||||
val elementRange = targetElement.textRange
|
||||
assert(range in elementRange) { "Wrong applicabilityRange() result for $intention - should be within element's range" }
|
||||
range.shiftRight(-elementRange.startOffset)
|
||||
}
|
||||
|
||||
if (range != null && additionalChecker(targetElement, this@IntentionBasedInspection)) {
|
||||
problemRange = problemRange?.union(range) ?: range
|
||||
if (fixes == null) {
|
||||
fixes = SmartList<LocalQuickFix>()
|
||||
}
|
||||
fixes!!.add(createQuickFix(intention, additionalChecker, targetElement))
|
||||
if (range != null && additionalChecker(targetElement, this@IntentionBasedInspection)) {
|
||||
problemRange = problemRange?.union(range) ?: range
|
||||
if (fixes == null) {
|
||||
fixes = SmartList<LocalQuickFix>()
|
||||
}
|
||||
fixes!!.add(createQuickFix(intention, additionalChecker, targetElement))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
-5
@@ -33,6 +33,7 @@ import org.jetbrains.kotlin.psi.KtElement
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containsInside
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf
|
||||
import java.util.*
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
abstract class SelfTargetingIntention<TElement : PsiElement>(
|
||||
val elementType: Class<TElement>,
|
||||
@@ -88,14 +89,14 @@ abstract class SelfTargetingIntention<TElement : PsiElement>(
|
||||
}
|
||||
|
||||
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)
|
||||
if (!InspectionProjectProfileManager.getInstance(project).getInspectionProfile(target).isToolEnabled(key)) {
|
||||
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 {
|
||||
@@ -109,9 +110,9 @@ abstract class SelfTargetingIntention<TElement : PsiElement>(
|
||||
override fun toString(): String = getText()
|
||||
|
||||
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)) {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return intentionBasedInspections[intentionClass] as IntentionBasedInspection<TElement>?
|
||||
@@ -119,7 +120,7 @@ abstract class SelfTargetingIntention<TElement : PsiElement>(
|
||||
|
||||
for (extension in Extensions.getExtensions(LocalInspectionEP.LOCAL_INSPECTION)) {
|
||||
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
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return inspection as IntentionBasedInspection<TElement>
|
||||
|
||||
@@ -33,14 +33,13 @@ import org.jetbrains.kotlin.types.isNullabilityFlexible
|
||||
import javax.swing.JComponent
|
||||
|
||||
class HasPlatformTypeInspection(
|
||||
val intention: SpecifyTypeExplicitlyIntention = SpecifyTypeExplicitlyIntention(),
|
||||
@JvmField var publicAPIOnly: Boolean = true,
|
||||
@JvmField var reportPlatformArguments: Boolean = false
|
||||
) : IntentionBasedInspection<KtCallableDeclaration>(
|
||||
intention,
|
||||
SpecifyTypeExplicitlyIntention::class,
|
||||
{ element, inspection ->
|
||||
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 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()) {
|
||||
val expression = element.node.findChildByType(KtTokens.EQ)?.psi?.getNextSiblingIgnoringWhitespaceAndComments()
|
||||
|
||||
+34
-34
@@ -32,11 +32,9 @@ import org.jetbrains.kotlin.types.isDynamic
|
||||
import org.jetbrains.kotlin.types.typeUtil.isTypeParameter
|
||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||
|
||||
class ConvertLambdaToReferenceInspection(
|
||||
val intention: ConvertLambdaToReferenceIntention = ConvertLambdaToReferenceIntention()
|
||||
) : IntentionBasedInspection<KtLambdaExpression>(
|
||||
intention,
|
||||
{ it -> intention.shouldSuggestToConvert(it) }
|
||||
class ConvertLambdaToReferenceInspection() : IntentionBasedInspection<KtLambdaExpression>(
|
||||
ConvertLambdaToReferenceIntention::class,
|
||||
{ it -> ConvertLambdaToReferenceIntention.shouldSuggestToConvert(it) }
|
||||
)
|
||||
|
||||
class ConvertLambdaToReferenceIntention : SelfTargetingOffsetIndependentIntention<KtLambdaExpression>(
|
||||
@@ -79,7 +77,7 @@ class ConvertLambdaToReferenceIntention : SelfTargetingOffsetIndependentIntentio
|
||||
if (calleeDescriptor.typeParameters.isNotEmpty()) return false
|
||||
// No references to Java synthetic properties
|
||||
if (calleeDescriptor is SyntheticJavaPropertyDescriptor) return false
|
||||
val descriptorHasReceiver = with (calleeDescriptor) {
|
||||
val descriptorHasReceiver = with(calleeDescriptor) {
|
||||
// No references to both member / extension
|
||||
if (dispatchReceiverParameter != null && extensionReceiverParameter != null) return false
|
||||
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?) {
|
||||
val body = element.bodyExpression ?: 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
|
||||
|
||||
class ConvertToStringTemplateInspection : IntentionBasedInspection<KtBinaryExpression>(
|
||||
ConvertToStringTemplateIntention(),
|
||||
{ it -> ConvertToStringTemplateIntention().shouldSuggestToConvert(it) }
|
||||
ConvertToStringTemplateIntention::class,
|
||||
{ it -> ConvertToStringTemplateIntention.shouldSuggestToConvert(it) }
|
||||
)
|
||||
|
||||
class ConvertToStringTemplateIntention : SelfTargetingOffsetIndependentIntention<KtBinaryExpression>(KtBinaryExpression::class.java, "Convert concatenation to template") {
|
||||
@@ -47,101 +47,103 @@ class ConvertToStringTemplateIntention : SelfTargetingOffsetIndependentIntention
|
||||
element.replaced(buildReplacement(element))
|
||||
}
|
||||
|
||||
fun shouldSuggestToConvert(expression: KtBinaryExpression): Boolean {
|
||||
val entries = buildReplacement(expression).entries
|
||||
return entries.none { it is KtBlockStringTemplateEntry }
|
||||
&& !entries.all { it is KtLiteralStringTemplateEntry || it is KtEscapeStringTemplateEntry }
|
||||
&& 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)
|
||||
companion object {
|
||||
fun shouldSuggestToConvert(expression: KtBinaryExpression): Boolean {
|
||||
val entries = buildReplacement(expression).entries
|
||||
return entries.none { it is KtBlockStringTemplateEntry }
|
||||
&& !entries.all { it is KtLiteralStringTemplateEntry || it is KtEscapeStringTemplateEntry }
|
||||
&& entries.count { it is KtLiteralStringTemplateEntry } > 1
|
||||
&& !expression.textContains('\n')
|
||||
}
|
||||
|
||||
if (PsiUtilCore.hasErrorElementChild(expression)) return false
|
||||
if (expression.textContains('\n')) return false
|
||||
return true
|
||||
}
|
||||
|
||||
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)
|
||||
private fun buildReplacement(expression: KtBinaryExpression): KtStringTemplateExpression {
|
||||
val rightText = buildText(expression.right, false)
|
||||
return fold(expression.left, rightText, KtPsiFactory(expression))
|
||||
}
|
||||
else {
|
||||
val leftText = buildText(left, forceBraces)
|
||||
return factory.createExpression("\"$leftText$right\"") as KtStringTemplateExpression
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildText(expr: KtExpression?, forceBraces: Boolean): String {
|
||||
if (expr == null) return ""
|
||||
val expression = KtPsiUtil.safeDeparenthesize(expr)
|
||||
val expressionText = expression.text
|
||||
when (expression) {
|
||||
is KtConstantExpression -> {
|
||||
val bindingContext = expression.analyze(BodyResolveMode.PARTIAL)
|
||||
val type = bindingContext.getType(expression)!!
|
||||
private fun fold(left: KtExpression?, right: String, factory: KtPsiFactory): KtStringTemplateExpression {
|
||||
val forceBraces = !right.isEmpty() && right.first() != '$' && right.first().isJavaIdentifierPart()
|
||||
|
||||
if (KotlinBuiltIns.isChar(type)) {
|
||||
val value = expressionText.removePrefix("'").removeSuffix("'")
|
||||
return when (value) { // escape double quote and unescape single one
|
||||
"\"" -> "\\\""
|
||||
"\\'" -> "'"
|
||||
else -> value
|
||||
}
|
||||
}
|
||||
|
||||
val constant = ConstantExpressionEvaluator.getConstant(expression, bindingContext)
|
||||
val stringValue = constant?.getValue(type).toString()
|
||||
if (stringValue == expressionText) {
|
||||
return StringUtil.escapeStringCharacters(stringValue)
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
is KtStringTemplateExpression -> {
|
||||
val base = if (expressionText.startsWith("\"\"\"") && expressionText.endsWith("\"\"\"")) {
|
||||
val unquoted = expressionText.substring(3, expressionText.length - 3)
|
||||
StringUtil.escapeStringCharacters(unquoted)
|
||||
}
|
||||
else {
|
||||
StringUtil.unquoteString(expressionText)
|
||||
}
|
||||
private fun buildText(expr: KtExpression?, forceBraces: Boolean): String {
|
||||
if (expr == null) return ""
|
||||
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 (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) + "}"
|
||||
if (KotlinBuiltIns.isChar(type)) {
|
||||
val value = expressionText.removePrefix("'").removeSuffix("'")
|
||||
return when (value) { // escape double quote and unescape single one
|
||||
"\"" -> "\\\""
|
||||
"\\'" -> "'"
|
||||
else -> value
|
||||
}
|
||||
}
|
||||
|
||||
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 "$" + (if (forceBraces) "{$expressionText}" else expressionText)
|
||||
return "\${$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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -25,12 +25,12 @@ import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
import org.jetbrains.kotlin.idea.imports.importableFqName
|
||||
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.idea.core.moveCaret
|
||||
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.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression
|
||||
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 java.util.*
|
||||
|
||||
class DeprecatedCallableAddReplaceWithInspection : IntentionBasedInspection<KtCallableDeclaration>(DeprecatedCallableAddReplaceWithIntention())
|
||||
class DeprecatedCallableAddReplaceWithInspection : IntentionBasedInspection<KtCallableDeclaration>(DeprecatedCallableAddReplaceWithIntention::class)
|
||||
|
||||
class DeprecatedCallableAddReplaceWithIntention : SelfTargetingRangeIntention<KtCallableDeclaration>(
|
||||
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.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"){
|
||||
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.idea.caches.resolve.analyze
|
||||
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.replaced
|
||||
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
|
||||
import org.jetbrains.kotlin.idea.inspections.RedundantSamConstructorInspection
|
||||
import org.jetbrains.kotlin.idea.util.CommentSaver
|
||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||
import org.jetbrains.kotlin.idea.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.load.java.sam.SingleAbstractMethodUtils
|
||||
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.types.KotlinType
|
||||
|
||||
class ObjectLiteralToLambdaInspection : IntentionBasedInspection<KtObjectLiteralExpression>(ObjectLiteralToLambdaIntention())
|
||||
class ObjectLiteralToLambdaInspection : IntentionBasedInspection<KtObjectLiteralExpression>(ObjectLiteralToLambdaIntention::class)
|
||||
|
||||
class ObjectLiteralToLambdaIntention : SelfTargetingRangeIntention<KtObjectLiteralExpression>(
|
||||
KtObjectLiteralExpression::class.java,
|
||||
|
||||
+1
-1
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.psi.KtAnnotatedExpression
|
||||
import org.jetbrains.kotlin.psi.KtAnnotationEntry
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
|
||||
class RemoveAtFromAnnotationArgumentInspection : IntentionBasedInspection<KtAnnotatedExpression>(RemoveAtFromAnnotationArgumentIntention())
|
||||
class RemoveAtFromAnnotationArgumentInspection : IntentionBasedInspection<KtAnnotatedExpression>(RemoveAtFromAnnotationArgumentIntention::class)
|
||||
|
||||
class RemoveAtFromAnnotationArgumentIntention : SelfTargetingOffsetIndependentIntention<KtAnnotatedExpression>(
|
||||
KtAnnotatedExpression::class.java,
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.KtStringTemplateEntryWithExpression
|
||||
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") {
|
||||
override fun isApplicableTo(element: KtBlockStringTemplateEntry): Boolean {
|
||||
|
||||
+2
-2
@@ -23,8 +23,8 @@ import com.intellij.openapi.util.TextRange
|
||||
import org.jetbrains.kotlin.idea.analysis.analyzeInContext
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||
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.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.KtQualifiedExpression
|
||||
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.TypeUtils
|
||||
|
||||
class RemoveExplicitSuperQualifierInspection : IntentionBasedInspection<KtSuperExpression>(RemoveExplicitSuperQualifierIntention()), CleanupLocalInspectionTool {
|
||||
class RemoveExplicitSuperQualifierInspection : IntentionBasedInspection<KtSuperExpression>(RemoveExplicitSuperQualifierIntention::class), CleanupLocalInspectionTool {
|
||||
override val problemHighlightType: ProblemHighlightType
|
||||
get() = ProblemHighlightType.LIKE_UNUSED_SYMBOL
|
||||
}
|
||||
|
||||
+2
-2
@@ -18,9 +18,9 @@ package org.jetbrains.kotlin.idea.intentions
|
||||
|
||||
import com.intellij.codeInspection.ProblemHighlightType
|
||||
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.inspections.IntentionBasedInspection
|
||||
import org.jetbrains.kotlin.idea.resolve.frontendService
|
||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
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.checker.KotlinTypeChecker
|
||||
|
||||
class RemoveExplicitTypeArgumentsInspection : IntentionBasedInspection<KtTypeArgumentList>(RemoveExplicitTypeArgumentsIntention()) {
|
||||
class RemoveExplicitTypeArgumentsInspection : IntentionBasedInspection<KtTypeArgumentList>(RemoveExplicitTypeArgumentsIntention::class) {
|
||||
override val problemHighlightType: ProblemHighlightType
|
||||
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.startOffset
|
||||
|
||||
class RemoveSetterParameterTypeInspection(
|
||||
val intention: RemoveExplicitTypeIntention = RemoveExplicitTypeIntention()
|
||||
) : IntentionBasedInspection<KtCallableDeclaration>(
|
||||
intention,
|
||||
{ it -> intention.isSetterParameter(it) }
|
||||
class RemoveSetterParameterTypeInspection()
|
||||
: IntentionBasedInspection<KtCallableDeclaration>(
|
||||
RemoveExplicitTypeIntention::class,
|
||||
{ it -> RemoveExplicitTypeIntention.isSetterParameter(it) }
|
||||
) {
|
||||
override val problemHighlightType = ProblemHighlightType.LIKE_UNUSED_SYMBOL
|
||||
|
||||
@@ -44,11 +43,6 @@ class RemoveExplicitTypeIntention : SelfTargetingRangeIntention<KtCallableDeclar
|
||||
"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? {
|
||||
if (element.containingFile is KtCodeFragment) return null
|
||||
if (element.typeReference == null) return null
|
||||
@@ -66,4 +60,11 @@ class RemoveExplicitTypeIntention : SelfTargetingRangeIntention<KtCallableDeclar
|
||||
override fun applyTo(element: KtCallableDeclaration, editor: Editor?) {
|
||||
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
|
||||
|
||||
class RemoveForLoopIndicesInspection : IntentionBasedInspection<KtForExpression>(
|
||||
RemoveForLoopIndicesIntention(),
|
||||
problemText = "Index is not used in the loop body"
|
||||
RemoveForLoopIndicesIntention::class,
|
||||
"Index is not used in the loop body"
|
||||
) {
|
||||
override val problemHighlightType: ProblemHighlightType
|
||||
get() = ProblemHighlightType.LIKE_UNUSED_SYMBOL
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ private fun KtStringTemplateExpression.singleExpressionOrNull() =
|
||||
children.singleOrNull()?.children?.firstOrNull() as? KtExpression
|
||||
|
||||
class RemoveSingleExpressionStringTemplateInspection : IntentionBasedInspection<KtStringTemplateExpression>(
|
||||
RemoveSingleExpressionStringTemplateIntention(),
|
||||
RemoveSingleExpressionStringTemplateIntention::class,
|
||||
additionalChecker = {
|
||||
templateExpression ->
|
||||
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.inspections.IntentionBasedInspection
|
||||
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.resolve.DescriptorToSourceUtils
|
||||
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 problemText = "Unnecessary lateinit"
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfo
|
||||
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") {
|
||||
override fun isApplicableTo(element: KtBinaryExpression): Boolean {
|
||||
|
||||
@@ -20,12 +20,12 @@ import com.intellij.codeInsight.CodeInsightUtilCore
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
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.inspections.IntentionBasedInspection
|
||||
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.core.ShortenReferences
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
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.utils.addToStdlib.firstIsInstanceOrNull
|
||||
|
||||
class SimplifyAssertNotNullInspection : IntentionBasedInspection<KtCallExpression>(SimplifyAssertNotNullIntention())
|
||||
class SimplifyAssertNotNullInspection : IntentionBasedInspection<KtCallExpression>(SimplifyAssertNotNullIntention::class)
|
||||
|
||||
class SimplifyAssertNotNullIntention : SelfTargetingOffsetIndependentIntention<KtCallExpression>(
|
||||
KtCallExpression::class.java,
|
||||
|
||||
+1
-2
@@ -26,9 +26,8 @@ import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
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") {
|
||||
|
||||
|
||||
@@ -37,9 +37,8 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import java.util.*
|
||||
import kotlin.collections.forEach
|
||||
|
||||
class SimplifyForInspection : IntentionBasedInspection<KtForExpression>(SimplifyForIntention())
|
||||
class SimplifyForInspection : IntentionBasedInspection<KtForExpression>(SimplifyForIntention::class)
|
||||
|
||||
class SimplifyForIntention : SelfTargetingRangeIntention<KtForExpression>(
|
||||
KtForExpression::class.java,
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.lexer.KtSingleValueToken
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
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") {
|
||||
|
||||
|
||||
@@ -51,29 +51,6 @@ class SpecifyTypeExplicitlyIntention :
|
||||
SelfTargetingRangeIntention<KtCallableDeclaration>(KtCallableDeclaration::class.java, "Specify type explicitly"),
|
||||
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? {
|
||||
if (element.containingFile is KtCodeFragment) return null
|
||||
if (element is KtFunctionLiteral) return null // TODO: should KtFunctionLiteral be KtCallableDeclaration at all?
|
||||
@@ -108,6 +85,29 @@ class SpecifyTypeExplicitlyIntention :
|
||||
private val PropertyDescriptor.setterType: KotlinType?
|
||||
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 {
|
||||
val descriptor = declaration.analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, declaration]
|
||||
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.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") {
|
||||
override fun isApplicableTo(element: KtCallExpression): Boolean {
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.idea.intentions.branchedTransformations.*
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
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") {
|
||||
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.idea.intentions.branchedTransformations.*
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
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") {
|
||||
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ import org.jetbrains.kotlin.idea.intentions.branchedTransformations.getSubjectTo
|
||||
import org.jetbrains.kotlin.idea.intentions.branchedTransformations.introduceSubject
|
||||
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'") {
|
||||
override fun applicabilityRange(element: KtWhenExpression): TextRange? {
|
||||
|
||||
+7
-7
@@ -19,25 +19,25 @@ package org.jetbrains.kotlin.idea.intentions.conventionNameCalls
|
||||
import com.intellij.codeInsight.intention.HighPriorityAction
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.tree.IElementType
|
||||
import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
|
||||
import com.intellij.psi.PsiElement
|
||||
import org.jetbrains.kotlin.idea.intentions.*
|
||||
import org.jetbrains.kotlin.idea.intentions.SelfTargetingRangeIntention
|
||||
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.KtTokens
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
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.isReallySuccess
|
||||
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
class ReplaceCallWithComparisonInspection(
|
||||
val intention: ReplaceCallWithBinaryOperatorIntention = ReplaceCallWithBinaryOperatorIntention()
|
||||
) : IntentionBasedInspection<KtDotQualifiedExpression>(
|
||||
intention,
|
||||
class ReplaceCallWithComparisonInspection() : IntentionBasedInspection<KtDotQualifiedExpression>(
|
||||
ReplaceCallWithBinaryOperatorIntention::class,
|
||||
{ qualifiedExpression ->
|
||||
val calleeExpression = qualifiedExpression.callExpression?.calleeExpression as? KtSimpleNameExpression
|
||||
val identifier = calleeExpression?.getReferencedNameAsName()
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.util.isValidOperator
|
||||
|
||||
class ReplaceGetOrSetInspection : IntentionBasedInspection<KtDotQualifiedExpression>(
|
||||
ReplaceGetOrSetIntention(), ReplaceGetOrSetInspection.additionalChecker
|
||||
ReplaceGetOrSetIntention::class, ReplaceGetOrSetInspection.additionalChecker
|
||||
|
||||
) {
|
||||
companion object {
|
||||
|
||||
+3
-3
@@ -28,9 +28,9 @@ import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffset
|
||||
|
||||
class LoopToCallChainInspection : IntentionBasedInspection<KtForExpression>(
|
||||
listOf(IntentionData(LoopToCallChainIntention()), IntentionData(LoopToLazyCallChainIntention())),
|
||||
problemText = "Loop can be replaced with stdlib operations",
|
||||
elementType = KtForExpression::class.java)
|
||||
listOf(IntentionData(LoopToCallChainIntention::class), IntentionData(LoopToLazyCallChainIntention::class)),
|
||||
problemText = "Loop can be replaced with stdlib operations"
|
||||
)
|
||||
|
||||
class LoopToCallChainIntention : AbstractLoopToCallChainIntention(lazy = false, text = "Replace with stdlib operations")
|
||||
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.psi.KtForExpression
|
||||
import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.createExpressionByPattern
|
||||
|
||||
class UseWithIndexInspection : IntentionBasedInspection<KtForExpression>(UseWithIndexIntention())
|
||||
class UseWithIndexInspection : IntentionBasedInspection<KtForExpression>(UseWithIndexIntention::class)
|
||||
|
||||
class UseWithIndexIntention : SelfTargetingRangeIntention<KtForExpression>(
|
||||
KtForExpression::class.java,
|
||||
|
||||
@@ -190,7 +190,7 @@ object J2KPostProcessingRegistrar {
|
||||
private val intention = ConvertToStringTemplateIntention()
|
||||
|
||||
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) }
|
||||
}
|
||||
else {
|
||||
|
||||
+4
-3
@@ -20,7 +20,8 @@ import org.jetbrains.kotlin.idea.inspections.IntentionBasedInspection
|
||||
import org.jetbrains.kotlin.psi.KtPackageDirective
|
||||
|
||||
class PackageDirectoryMismatchInspection: IntentionBasedInspection<KtPackageDirective>(
|
||||
listOf(IntentionBasedInspection.IntentionData(MoveFileToPackageMatchingDirectoryIntention()), IntentionBasedInspection.IntentionData(ChangePackageToMatchDirectoryIntention())),
|
||||
"Package directive doesn't match file location",
|
||||
KtPackageDirective::class.java
|
||||
listOf(
|
||||
IntentionBasedInspection.IntentionData(MoveFileToPackageMatchingDirectoryIntention::class),
|
||||
IntentionBasedInspection.IntentionData(ChangePackageToMatchDirectoryIntention::class)),
|
||||
"Package directive doesn't match file location"
|
||||
)
|
||||
Reference in New Issue
Block a user