Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend CanBeNonNullable rule to check function params #4431

Merged
merged 24 commits into from Jan 12, 2022
Merged
Show file tree
Hide file tree
Changes from 23 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
47e858e
Expanded CanBeNonNullable rule to check for function parameters that …
severn-everett Dec 30, 2021
7abf6ae
Added code comment
severn-everett Dec 30, 2021
9197f1b
Addressing Detekt issue
severn-everett Dec 30, 2021
7a50a9a
Reworked CanBeNonNullable check for params based on PR discussion
severn-everett Jan 1, 2022
0992e7d
Merge branch 'master' into function_parameters_non_nullable
severn-everett Jan 1, 2022
b642aa9
Address Detekt issues
severn-everett Jan 1, 2022
e5ecb4a
Added check to ignore override function; Added tests to improve code …
severn-everett Jan 1, 2022
b0a3cda
Enabled nullable params to be passed through to non-local variables a…
severn-everett Jan 1, 2022
82f5f85
Addressing Detekt issue
severn-everett Jan 1, 2022
2d48819
Fixed Detekt issue
severn-everett Jan 1, 2022
6a2bdc8
Reworked CanBeNonNullable so that it only calls on a specific heurist…
severn-everett Jan 3, 2022
408e7ec
Merge branch 'master' into function_parameters_non_nullable
severn-everett Jan 3, 2022
a260193
Fixed merge conflict
severn-everett Jan 3, 2022
8a381b5
CanBeNonNullable will only flag a param that has been checked for non…
severn-everett Jan 3, 2022
d8aef95
Added check for when a single-expression function finishes on a null-…
severn-everett Jan 3, 2022
e95d7ab
Addressing Detekt issues in SplitPattern.kt
severn-everett Jan 3, 2022
73790f1
Single expression check now recursively evaluates lambdas
severn-everett Jan 3, 2022
b3445d9
Address Detekt issues
severn-everett Jan 3, 2022
9d22662
CanBeNonNullable will now ignore params that are involved in an elvis…
severn-everett Jan 3, 2022
c69f3c4
CanBeNonNullable will now ignore single expression calls where the re…
severn-everett Jan 3, 2022
f9e938e
Simplified checks for single-expression functions; Consolidated param…
severn-everett Jan 4, 2022
08bc3fe
Address Detekt issues
severn-everett Jan 4, 2022
9f07ecc
Clean up CanBeNonNullableSpec tests
severn-everett Jan 4, 2022
9875284
Addressing PR comments
severn-everett Jan 4, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -21,6 +21,7 @@ interface Context {
* An alias set can be given to additionally check if an alias was used when suppressing.
* Additionally suppression by rule set id is supported.
*/
@Suppress("CanBeNonNullable")
fun report(finding: Finding, aliases: Set<String> = emptySet(), ruleSetId: RuleSetId? = null) {
// no-op
}
Expand Down
Expand Up @@ -27,12 +27,16 @@ open class SplitPattern(
/**
* Does any part contain given [value]?
*/
fun contains(value: String?): Boolean = excludes.any { value?.contains(it, ignoreCase = true) == true }
fun contains(value: String?): Boolean {
return if (value != null) excludes.any { value.contains(it, ignoreCase = true) } else false
}

/**
* Is there any element which matches the given [value]?
*/
fun any(value: String?): Boolean = excludes.any { value?.equals(it, ignoreCase = true) == true }
fun any(value: String?): Boolean {
return if (value != null) excludes.any { value.equals(it, ignoreCase = true) } else false
}

/**
* Tests if none of the parts contain the given [value].
Expand All @@ -47,7 +51,9 @@ open class SplitPattern(
/**
* Tests if any part starts with the given [value]
*/
fun startWith(value: String?): Boolean = excludes.any { value?.startsWith(it) ?: false }
fun startWith(value: String?): Boolean {
return if (value != null) excludes.any(value::startsWith) else false
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that this code is better (we don't need to loop the collection). But was the previous code flagged by CanBeNonNullable? I don't think it should.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is code from an older iteration and can probably be reverted.


/**
* Transforms all parts by given [transform] function.
Expand Down
Expand Up @@ -66,8 +66,7 @@ internal class DefaultCliInvoker(
}
}

private fun isBuildFailure(msg: String?) =
msg != null && "Build failed with" in msg && "issues" in msg
private fun isBuildFailure(msg: String) = "Build failed with" in msg && "issues" in msg
}

private class DryRunInvoker(private val logger: Logger) : DetektInvoker {
Expand Down
Expand Up @@ -78,24 +78,26 @@ class UselessPostfixExpression(config: Config = Config.empty) : Rule(config) {
report(postfixExpression)
}

getPostfixExpressionChildren(expression.returnedExpression)
?.forEach { report(it) }
expression.returnedExpression
?.let(this::getPostfixExpressionChildren)
?.forEach(this::report)
}

override fun visitBinaryExpression(expression: KtBinaryExpression) {
val postfixExpression = expression.right?.asPostFixExpression()
val leftIdentifierText = expression.left?.text
checkPostfixExpression(postfixExpression, leftIdentifierText)
getPostfixExpressionChildren(expression.right)
postfixExpression?.let { checkPostfixExpression(it, leftIdentifierText) }
expression.right
?.let(this::getPostfixExpressionChildren)
?.forEach { checkPostfixExpression(it, leftIdentifierText) }
}

private fun KtExpression.asPostFixExpression() = if (this is KtPostfixExpression &&
(operationToken === PLUSPLUS || operationToken === MINUSMINUS)
) this else null

private fun checkPostfixExpression(postfixExpression: KtPostfixExpression?, leftIdentifierText: String?) {
if (postfixExpression != null && leftIdentifierText == postfixExpression.firstChild?.text) {
private fun checkPostfixExpression(postfixExpression: KtPostfixExpression, leftIdentifierText: String?) {
if (leftIdentifierText == postfixExpression.firstChild?.text) {
report(postfixExpression)
}
}
Expand All @@ -118,7 +120,7 @@ class UselessPostfixExpression(config: Config = Config.empty) : Rule(config) {
)
}

private fun getPostfixExpressionChildren(expression: KtExpression?) =
expression?.getChildrenOfType<KtPostfixExpression>()
?.filter { it.operationToken === PLUSPLUS || it.operationToken === MINUSMINUS }
private fun getPostfixExpressionChildren(expression: KtExpression) =
expression.getChildrenOfType<KtPostfixExpression>()
.filter { it.operationToken === PLUSPLUS || it.operationToken === MINUSMINUS }
}
Expand Up @@ -65,5 +65,5 @@ class ExceptionRaisedInUnexpectedLocation(config: Config = Config.empty) : Rule(
private fun isPotentialMethod(function: KtNamedFunction) = methodNames.any { function.name == it }

private fun hasThrowExpression(declaration: KtExpression?) =
declaration?.anyDescendantOfType<KtThrowExpression>() == true
declaration?.anyDescendantOfType<KtThrowExpression>() ?: false
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this change needed? Both do the same and I don't see why one should be promoted over the other

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably code from an older iteration and should be reverted.

}
Expand Up @@ -64,7 +64,7 @@ class TooGenericExceptionCaught(config: Config) : Rule(config) {
}

private fun isTooGenericException(typeReference: KtTypeReference?): Boolean {
return typeReference?.text in exceptionNames
return typeReference?.let { it.text in exceptionNames } ?: false
}

companion object {
Expand Down
Expand Up @@ -65,15 +65,14 @@ class ArrayPrimitive(config: Config = Config.empty) : Rule(config) {
override fun visitNamedDeclaration(declaration: KtNamedDeclaration) {
super.visitNamedDeclaration(declaration)
if (declaration is KtCallableDeclaration) {
reportArrayPrimitives(declaration.typeReference)
reportArrayPrimitives(declaration.receiverTypeReference)
declaration.typeReference?.let(this::reportArrayPrimitives)
declaration.receiverTypeReference?.let(this::reportArrayPrimitives)
}
}

private fun reportArrayPrimitives(typeReference: KtTypeReference?) {
typeReference
?.collectDescendantsOfType<KtTypeReference> { isArrayPrimitive(it) }
?.forEach { report(CodeSmell(issue, Entity.from(it), issue.description)) }
private fun reportArrayPrimitives(typeReference: KtTypeReference) {
typeReference.collectDescendantsOfType<KtTypeReference> { isArrayPrimitive(it) }
.forEach { report(CodeSmell(issue, Entity.from(it), issue.description)) }
}

private fun isArrayPrimitive(descriptor: CallableDescriptor): Boolean {
Expand Down