OperatorModifierInspection: reused code from OperatorChecks
This commit is contained in:
@@ -23,97 +23,36 @@ import com.intellij.codeInspection.ProblemDescriptor
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticWithParameters2
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptor
|
||||
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
|
||||
import org.jetbrains.kotlin.idea.quickfix.AddModifierFix
|
||||
import org.jetbrains.kotlin.idea.quickfix.CleanupFix
|
||||
import org.jetbrains.kotlin.idea.quickfix.JetSingleIntentionActionFactory
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
|
||||
import org.jetbrains.kotlin.lexer.JetModifierKeywordToken
|
||||
import org.jetbrains.kotlin.lexer.JetTokens
|
||||
import org.jetbrains.kotlin.psi.JetClassOrObject
|
||||
import org.jetbrains.kotlin.psi.JetModifierListOwner
|
||||
import org.jetbrains.kotlin.psi.JetNamedFunction
|
||||
import org.jetbrains.kotlin.psi.JetVisitorVoid
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.OverrideResolver
|
||||
import org.jetbrains.kotlin.resolve.dataClassUtils.isComponentLike
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.util.OperatorChecks
|
||||
|
||||
public class OperatorModifierInspection : AbstractKotlinInspection() {
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
|
||||
return object : JetVisitorVoid() {
|
||||
override fun visitNamedFunction(function: JetNamedFunction) {
|
||||
val nameIdentifier = function.nameIdentifier
|
||||
if (nameIdentifier != null &&
|
||||
function.isMemberOrExtension() &&
|
||||
function.isOperator() &&
|
||||
!function.isAnnotatedAsOperator()) {
|
||||
|
||||
val nameIdentifier = function.nameIdentifier ?: return
|
||||
val functionDescriptor = function.resolveToDescriptor() as? FunctionDescriptor ?: return
|
||||
if (!functionDescriptor.isOperator && OperatorChecks.canBeOperator(functionDescriptor)) {
|
||||
holder.registerProblem(nameIdentifier, "Function defines an operator but isn't annotated as such",
|
||||
AddModifierLocalQuickFix())
|
||||
AddModifierLocalQuickFix())
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private fun JetNamedFunction.isOperator(): Boolean {
|
||||
val name = nameAsName ?: return false
|
||||
val arity = valueParameters.size()
|
||||
if (arity == 0 &&
|
||||
(name in OperatorConventions.UNARY_OPERATION_NAMES.values() ||
|
||||
name == OperatorNameConventions.PLUS || name == OperatorNameConventions.MINUS || // temporary
|
||||
name == OperatorNameConventions.ITERATOR ||
|
||||
isComponentLike(name) ||
|
||||
name == OperatorNameConventions.NEXT ||
|
||||
(name == OperatorNameConventions.HAS_NEXT && isBooleanReturnType()))) {
|
||||
return true
|
||||
}
|
||||
if (arity == 1 && (name in OperatorConventions.BINARY_OPERATION_NAMES.values() ||
|
||||
name in OperatorConventions.ASSIGNMENT_OPERATIONS.values () ||
|
||||
(name == OperatorNameConventions.CONTAINS && isBooleanReturnType()) ||
|
||||
(name == OperatorNameConventions.COMPARE_TO && isIntReturnType()))) {
|
||||
return true
|
||||
}
|
||||
if (name == OperatorNameConventions.INVOKE) {
|
||||
return true
|
||||
}
|
||||
if (arity >= 1 && name == OperatorNameConventions.GET) {
|
||||
return true
|
||||
}
|
||||
if (arity >= 2 && name == OperatorNameConventions.SET) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun JetNamedFunction.isAnnotatedAsOperator(): Boolean {
|
||||
if (hasModifier(JetTokens.OPERATOR_KEYWORD)) return true
|
||||
val descriptor = descriptor as? CallableMemberDescriptor ?: return false
|
||||
return OverrideResolver.getOverriddenDeclarations(descriptor).any {
|
||||
(it as? FunctionDescriptor)?.isOperator == true
|
||||
}
|
||||
}
|
||||
|
||||
private fun JetNamedFunction.isMemberOrExtension(): Boolean =
|
||||
receiverTypeReference != null || getStrictParentOfType<JetClassOrObject>() != null
|
||||
|
||||
private fun JetNamedFunction.isIntReturnType(): Boolean {
|
||||
val returnType = (descriptor as? FunctionDescriptor)?.returnType ?: return false
|
||||
return KotlinBuiltIns.isInt(returnType)
|
||||
}
|
||||
|
||||
private fun JetNamedFunction.isBooleanReturnType(): Boolean {
|
||||
val returnType = (descriptor as? FunctionDescriptor)?.returnType ?: return false
|
||||
return KotlinBuiltIns.isBoolean(returnType)
|
||||
}
|
||||
}
|
||||
|
||||
private class AddModifierLocalQuickFix() : LocalQuickFix {
|
||||
|
||||
Reference in New Issue
Block a user