Don't suggest "return type is..." inspections for anonymous functions

#KT-29290 Fixed
This commit is contained in:
Mikhail Glukhikh
2019-01-18 10:00:44 +03:00
parent 4f9e844735
commit 04bd5139d5
13 changed files with 34 additions and 63 deletions
@@ -27,37 +27,35 @@ abstract class AbstractIsResultInspection(
private val simplify: (KtExpression) -> Unit = {}
) : AbstractKotlinInspection() {
protected fun analyzeFunction(function: KtFunction, toReport: PsiElement, holder: ProblemsHolder) {
protected fun analyzeFunction(function: KtNamedFunction, toReport: PsiElement, holder: ProblemsHolder) {
if (function is KtConstructor<*>) return
val returnTypeText = function.getReturnTypeReference()?.text
if (returnTypeText != null && typeShortName !in returnTypeText) return
val name = (function as? KtNamedFunction)?.nameAsName?.asString()
if (name in allowedNames) return
if (function is KtNamedFunction) {
val receiverTypeReference = function.receiverTypeReference
// Filter given type extensions
if (receiverTypeReference != null && typeShortName in receiverTypeReference.text) return
}
if (function is KtFunctionLiteral || returnTypeText == null) {
val name = function.nameAsName?.asString()
if (name == null || name in allowedNames) return
val receiverTypeReference = function.receiverTypeReference
// Filter given type extensions
if (receiverTypeReference != null && typeShortName in receiverTypeReference.text) return
if (returnTypeText == null) {
// Heuristics to save performance: check if something creates given type in function text
val text = function.bodyExpression?.text
if (text != null && allowedNames.none { it in text } && typeShortName !in text && allowedSuffix !in text) return
}
val descriptor = function.resolveToDescriptorIfAny() as? FunctionDescriptor ?: return
val descriptor = function.resolveToDescriptorIfAny() ?: return
val returnType = descriptor.returnType ?: return
val returnTypeClass = returnType.constructor.declarationDescriptor as? ClassDescriptor ?: return
if (returnTypeClass.fqNameSafe.asString() != typeFullName) return
if (name != null && name.endsWith(allowedSuffix)) {
if (name.endsWith(allowedSuffix)) {
analyzeFunctionWithAllowedSuffix(name, descriptor, toReport, holder)
} else {
holder.registerProblem(
toReport,
"Function returning $typeShortName with a name that does not end with $allowedSuffix",
ProblemHighlightType.GENERIC_ERROR_OR_WARNING,
*listOfNotNull(
name?.let { RenameToFix("$it$allowedSuffix") },
*listOf(
RenameToFix("$name$allowedSuffix"),
AddCallOrUnwrapTypeFix(
withBody = function.hasBody(),
functionName = suggestedFunctionNameToCall,
@@ -75,10 +73,6 @@ abstract class AbstractIsResultInspection(
override fun visitNamedFunction(function: KtNamedFunction) {
analyzeFunction(function, function.nameIdentifier ?: function.funKeyword ?: function, holder)
}
override fun visitLambdaExpression(lambdaExpression: KtLambdaExpression) {
analyzeFunction(lambdaExpression.functionLiteral, lambdaExpression.functionLiteral.lBrace, holder)
}
}
}
@@ -71,24 +71,6 @@
<problem_class severity="WEAK WARNING" attribute_key="INFO_ATTRIBUTES">Function returning Result directly</problem_class>
<description>Function returning Result with a name that does not end with Catching</description>
</problem>
<problem>
<file>test.kt</file>
<line>38</line>
<module>light_idea_test_case</module>
<package>&lt;default&gt;</package>
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
<problem_class severity="WEAK WARNING" attribute_key="INFO_ATTRIBUTES">Function returning Result directly</problem_class>
<description>Function returning Result with a name that does not end with Catching</description>
</problem>
<problem>
<file>test.kt</file>
<line>40</line>
<module>light_idea_test_case</module>
<package>&lt;default&gt;</package>
<entry_point TYPE="file" FQNAME="temp:///src/test.kt" />
<problem_class severity="WEAK WARNING" attribute_key="INFO_ATTRIBUTES">Function returning Result directly</problem_class>
<description>Function returning Result with a name that does not end with Catching</description>
</problem>
<problem>
<file>test.kt</file>
<line>60</line>
@@ -34,9 +34,9 @@ class Container {
fun test() {
// YES
fun localGetSuccess() = Result("123")
// YES
// NO (no name)
val anonymous = fun() = Result(45)
// YES
// NO (no name)
val lambda = { Result(true) }
// NO yet (we do not report local *catching functions)
fun localCatching() = Result(2.72)
@@ -0,0 +1,12 @@
// WITH_RUNTIME
// PROBLEM: none
package kotlinx.coroutines
suspend fun barAsync(): Deferred<String>? {
return null
}
suspend fun foo() {
" ".let <caret>{ barAsync() }
}
@@ -1,3 +1,4 @@
// PROBLEM: none
package kotlin
fun test() {
@@ -1,5 +0,0 @@
package kotlin
fun test() {
val x = fun() = Result("123").getOrThrow()
}
@@ -1,3 +1,4 @@
// PROBLEM: none
package kotlin
fun test() {
@@ -1,5 +0,0 @@
package kotlin
fun test() {
val x = { Result(true).getOrThrow() }
}
@@ -1,3 +1,4 @@
// PROBLEM: none
package kotlin
fun test(arg: Boolean) {
@@ -1,11 +0,0 @@
package kotlin
fun test(arg: Boolean) {
val x = foo@{
(if (!arg) {
return@foo Result(true).getOrThrow()
} else {
Result(false)
}).getOrThrow()
}
}
@@ -1,3 +1,4 @@
// PROBLEM: none
package kotlin
fun test() {
@@ -1,5 +0,0 @@
package kotlin
fun test() {
val x = foo@<caret>{ return@foo Result(true).getOrThrow() }
}
@@ -2160,6 +2160,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
runTest("idea/testData/inspectionsLocal/coroutines/deferredIsResult/complex.kt");
}
@TestMetadata("lambda.kt")
public void testLambda() throws Exception {
runTest("idea/testData/inspectionsLocal/coroutines/deferredIsResult/lambda.kt");
}
@TestMetadata("rename.kt")
public void testRename() throws Exception {
runTest("idea/testData/inspectionsLocal/coroutines/deferredIsResult/rename.kt");