SlideShare a Scribd company logo
1 of 115
Download to read offline
©2023, SonarSource S.A, Switzerland.
Static Kotlin bug hunting
12.10.2023
Margarita Nedzelska
Software Engineer
Conferences speaker & organizer
Java/Kotlin/Scala/TS/...
@jMargaritaN
©2023, SonarSource S.A, Switzerland.
https://www.freepik.com/vectors/ukraine-war
Ukraine war vector created by starline - www.freepik.com
©2023, SonarSource S.A, Switzerland.
©2023, SonarSource S.A, Switzerland.
Agenda
● History
● Why Kotlin?
● sonar-kotlin 2.0
● Feedback
● Achievements
● Takeaways
5
©2023, SonarSource S.A, Switzerland.
SonarQube 8.9 (previous LTS)
6
©2023, SonarSource S.A, Switzerland.
SonarQube 9.9 (LTS)
7
©2023, SonarSource S.A, Switzerland.
What happened?
©2023, SonarSource S.A, Switzerland.
©2023, SonarSource S.A, Switzerland.
Static
Analysis
©2023, SonarSource S.A, Switzerland.
class HelloWorld {
fun f() {
println("Hello, World!")
}
}
©2023, SonarSource S.A, Switzerland.
©2023, SonarSource S.A, Switzerland.
©2023, SonarSource S.A, Switzerland.
©2023, SonarSource S.A, Switzerland.
class HelloWorld {
fun f() {
println("Hello, World!")
}
}
©2023, SonarSource S.A, Switzerland.
©2023, SonarSource S.A, Switzerland.
class HelloWorld {
fun f() {
println("Hello, World!")
}
}
©2023, SonarSource S.A, Switzerland.
class HelloWorld {
fun f() {
println("Hello, World!")
}
}
©2023, SonarSource S.A, Switzerland.
SLang
AST
Kotlin Scala
Go Ruby
PROs
● 1 rule - many languages
● Fast new languages
adoption
● Maintenance
● Rules precision
● Language specific rules
● Testing
● Semantic
● …
CONs
©2023, SonarSource S.A, Switzerland.
Semantic
Model
21
©2023, SonarSource S.A, Switzerland.
class HelloWorld {
fun f() {
println("Hello, World!")
}
}
fun g(x: HelloWorld) {
x.f()
}
©2023, SonarSource S.A, Switzerland.
class HelloWorld {
fun f() {
println("Hello, World!")
}
}
fun g(x: HelloWorld) {
x.f()
}
©2023, SonarSource S.A, Switzerland.
class HelloWorld {
fun f() {
println("Hello, World!")
}
}
fun g(x: HelloWorld) {
x.f()
}
©2023, SonarSource S.A, Switzerland.
©2023, SonarSource S.A, Switzerland.
Why Kotlin?
©2023, SonarSource S.A, Switzerland.
Why
● Growing popularity of Kotlin
● User feedback
● We wanted to use Kotlin
● Android and Security
● SLang is limited
27
©2023, SonarSource S.A, Switzerland.
sonar-kotlin 2.0
©2023, SonarSource S.A, Switzerland.
class HelloWorld {
fun f() {
println("Hello, World!")
}
}
We had
©2023, SonarSource S.A, Switzerland.
class HelloWorld {
fun f() {
println("Hello, World!")
}
}
We wanted
©2023, SonarSource S.A, Switzerland.
class HelloWorld {
fun f() {
println("Hello, World!")
}
}
We implemented
©2023, SonarSource S.A, Switzerland.
class HelloWorld {
fun f() {
println("Hello, World!")
}
}
Technical debt
©2023, SonarSource S.A, Switzerland.
class HelloWorld {
fun f() {
println("Hello, World!")
}
}
Technical debt
©2023, SonarSource S.A, Switzerland.
What’s wrong with Kotlin AST
34
©2023, SonarSource S.A, Switzerland.
What’s wrong with Kotlin AST
● Nullability hell
35
©2023, SonarSource S.A, Switzerland.
36
override fun visitBinaryExpression(expression: KtBinaryExpression, ...) {
val rightExpression = expression. right // Nullable
val leftExpression = expression. left // Nullable
...
}
©2023, SonarSource S.A, Switzerland.
37
override fun visitBinaryExpression(expression: KtBinaryExpression,...) {
val rightExpression = expression. right?.let {
val leftExpression = expression. left?.let {
...
}
}
...
}
©2023, SonarSource S.A, Switzerland.
38
override fun visitBinaryExpression(expression: KtBinaryExpression,...) {
val rightExpression = expression. right ?: return
val leftExpression = expression. left ?: return
...
}
©2023, SonarSource S.A, Switzerland.
39
override fun visitBinaryExpression(expression: KtBinaryExpression,...) {
val rightExpression = expression. right!!
val leftExpression = expression. left!!
...
}
©2023, SonarSource S.A, Switzerland.
40
override fun visitBinaryExpression(expression: KtBinaryExpression,...) {
// Valid KtBinaryExpression should always have right & left
val rightExpression = expression. right!!
val leftExpression = expression. left!!
...
}
©2023, SonarSource S.A, Switzerland.
What’s wrong with Kotlin AST
● Nullability hell
● Lack of Documentation & naming
41
©2023, SonarSource S.A, Switzerland.
What is
KtNamedFunction?
©2023, SonarSource S.A, Switzerland.
Bad Function Name rule
43
fun visitNamedFunction
(f: KtNamedFunction, …){
// Named functions always have name
val name = f.name!!
if (!name.matches(formatRegex)) {
reportIssue(
f.nameIdentifier!!,
"Message"
)
}
}
©2023, SonarSource S.A, Switzerland.
Bad Function Name rule
fun visitNamedFunction
(f: KtNamedFunction, …){
// Named functions always have name
val name = f.name!!
if (!name.matches(formatRegex)) {
reportIssue(
f.nameIdentifier!!,
"Message"
)
}
}
44
val function = fun() {}
©2023, SonarSource S.A, Switzerland.
Bad Function Name rule
45
val function = fun() {}
java.lang.NullPointerException
fun visitNamedFunction
(f: KtNamedFunction, …){
// Named functions always have name
val name = f.name!!
if (!name.matches(formatRegex)) {
reportIssue(
f.nameIdentifier!!,
"Message"
)
}
}
©2023, SonarSource S.A, Switzerland.
Bad Function Name rule
46
val function = fun() {}
java.lang.NullPointerException
fun visitNamedFunction(f: KtNamedFunction
, …){
// Named functions always have name
val name = f.name!!
if (!name.matches(formatRegex)) {
reportIssue(
f.nameIdentifier!!,
"Message"
)
}
}
©2023, SonarSource S.A, Switzerland.
Bad Function Name rule
47
val function = fun() {}
java.lang.NullPointerException
fun visitNamedFunction(f: KtNamedFunction
, …){
// Named functions always have name
val name = f.name!!
if (!name.matches(formatRegex)) {
reportIssue(
f.nameIdentifier!!,
"Message"
)
}
}
KtNamedFunction
is
declared with
“fun”
©2023, SonarSource S.A, Switzerland.
What’s wrong with Kotlin AST
● Nullability hell
● Lack of Documentation & naming
● Compiler diagnostics
48
©2023, SonarSource S.A, Switzerland.
Deprecated Code Used Rule
49
©2023, SonarSource S.A, Switzerland.
Deprecated Code Used Rule
50
fun visitKtFile(file: KtFile, ctx: Context) {
ctx.diagnostics
.filter {
it.factory == Errors.DEPRECATION
}.forEach {
ctx.reportIssue(
it.psiElement,"Message"
)
}
}
©2023, SonarSource S.A, Switzerland.
Deprecated Code Used Rule
51
fun visitKtFile(file: KtFile, ctx: Context) {
ctx.diagnostics
.filter {
it.factory == Errors.DEPRECATION
}.forEach {
ctx.reportIssue(
it.psiElement,"Message"
)
}
}
@Deprecated("Some text")
enum class
MyEnum(val s:String) {
ENTRY1(""),
}
©2023, SonarSource S.A, Switzerland.
Deprecated Code Used Rule
52
fun visitKtFile(file: KtFile, ctx: Context) {
ctx.diagnostics
.filter {
it.factory == Errors.DEPRECATION
}.forEach {
ctx.reportIssue(
it.psiElement,"Message"
)
}
}
@Deprecated("Some text")
enum class
MyEnum(val s:String) {
ENTRY1(""),
}
java.lang.IndexOutOfBoundsException: (5:11,5:10)
©2023, SonarSource S.A, Switzerland.
Deprecated Code Used Rule
53
fun visitKtFile(file: KtFile, ctx: Context) {
ctx.diagnostics
.filter {
it.factory == Errors.DEPRECATION
}.forEach {
ctx.reportIssue(
it.psiElement,"Message"
)
}
}
@Deprecated("Some text")
enum class
MyEnum(val s:String) {
ENTRY1(""),
}
java.lang.IndexOutOfBoundsException: (5:11,5:10)
©2023, SonarSource S.A, Switzerland.
Deprecated Code Used Rule
54
fun visitKtFile(file: KtFile
, ctx: Context) {
ctx.diagnostics
.filter {
it.factory == Errors.
DEPRECATION
}.forEach {
ctx.reportIssue(
it.psiElement,"Message"
)
}
}
@Deprecated("Some text")
enum class
MyEnum(val s:String) {
ENTRY1[MyEnum](""),
}
java.lang.IndexOutOfBoundsException: (5:11,5:10)
©2023, SonarSource S.A, Switzerland.
Deprecated Code Used Rule
55
fun visitKtFile(file: KtFile
, ctx: Context) {
ctx.diagnostics
.filter {
it.factory == Errors.
DEPRECATION
}.forEach {
ctx.reportIssue(
it.psiElement,"Message"
)
}
}
@Deprecated("Some text")
enum class
MyEnum(val s:String) {
ENTRY1[MyEnum](""),
}
java.lang.IndexOutOfBoundsException: (5:11,5:10)
Let’s fix it
©2023, SonarSource S.A, Switzerland.
Deprecated Code Used Rule
56
fun visitKtFile(file: KtFile
, ctx: Context) {
ctx.diagnostics
.filter {
it.factory == Errors.
DEPRECATION
}.forEach {
ctx.reportIssue(
adjust(it.psiElement),"Message"
)
}
}
@Deprecated("Some text")
enum class
MyEnum(val s:String) {
ENTRY1(""),
}
©2023, SonarSource S.A, Switzerland.
sonar-kotlin 2.0 released (24.06.2021)
● Improved 42 existing rules
● 10 new rules
● Semantic
● Detekt, AndroidLint, Ktlint rules sets
57
©2023, SonarSource S.A, Switzerland.
Feedback
©2023, SonarSource S.A, Switzerland.
Expectations
©2023, SonarSource S.A, Switzerland.
Reality
©2023, SonarSource S.A, Switzerland.
©2023, SonarSource S.A, Switzerland.
Commented out code
check
©2023, SonarSource S.A, Switzerland.
64
import java.util.Random
import kotlin.random.Random as KotlinRandom
fun f(x: Long) {
val random = Random()
// val javaRandom = java.util.Random()
val kotlinRandom = kotlin.random. Random(0)
// Named import is used here
val kotlinRandom1 = KotlinRandom(1000L)
// x - parameter, no constraints
val kotlinRandomLong = kotlin.random. Random(x)
/*
val xx = 0L
val kotlinRandomLongZero = kotlin.random.Random(xx)
*/
}
©2023, SonarSource S.A, Switzerland.
65
import java.util.Random
import kotlin.random.Random as KotlinRandom
fun f(x: Long) {
val random = Random()
// val javaRandom = java.util.Random()
val kotlinRandom = kotlin.random. Random(0)
// Named import is used here
val kotlinRandom1 = KotlinRandom(1000L)
// x - parameter, no constraints
val kotlinRandomLong = kotlin.random. Random(x)
/*
val xx = 0L
val kotlinRandomLongZero = kotlin.random.Random(xx)
*/
}
©2023, SonarSource S.A, Switzerland.
Before 2.0
©2023, SonarSource S.A, Switzerland.
foreach { comment ->
when (comment.parse()) {
is Success -> reportIssue()
is Error -> doNothing()
}
}
Commented out code rule
67
©2023, SonarSource S.A, Switzerland.
// Hello World here
Commented out code rule
68
foreach { comment ->
when (comment.parse()) {
is Success -> reportIssue()
is Error -> doNothing()
}
}
©2023, SonarSource S.A, Switzerland.
“World” could be an infix function
Commented out code rule
69
foreach { comment ->
when (comment.parse()) {
is Success -> reportIssue()
is Error -> doNothing()
}
}
// Hello World here
©2023, SonarSource S.A, Switzerland.
After 2.0
©2023, SonarSource S.A, Switzerland.
foreach { comment ->
when (comment.parseAndSemantic()) {
is Success -> reportIssue()
is Error -> doNothing()
}
}
Commented out code rule
71
©2023, SonarSource S.A, Switzerland.
foreach { comment ->
when (comment.parseAndSemantic()) {
is Success -> reportIssue()
is Error -> doNothing()
}
}
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣦⠀⢀⠀⠀
⠀⠀⠀⠀⠀⠀⢀⣤⣶⣶⣿⣿⣷⣶⣦⣄⠀⠀⠀⠀⠀⠀⢰⡟⠈⠁⣰⣿⡗⠀
⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⢸⡇⠀⢠⡟⠀⠀⠀
⠀⠀⠀⣰⣿⣿⣿⣿⠟⠋⣉⣉⣉⠙⠻⣿⣿⣿⣷⡀⠀⠀⢸⡇⠀⢸⠃⠀⠀⠀
⠀⠀⢀⣿⣿⣿⣿⡇⢠⣿⣿⣿⢿⣿⣆⠘⣿⣿⣿⣷⡀⠀⢸⣧⠀⢸⡇⠀⠀⠀
⠀⠀⢸⣿⣿⣿⣿⡇⠸⣿⣿⣿⠆⣿⣿⡄⢸⣿⣿⣿⣧⠀⣼⣿⣿⣿⣇⠀⠀⠀
⠀⠀⠀⣿⣿⣿⣿⣿⣦⣈⣉⣁⣴⣿⣿⠁⣼⣿⣿⣿⣿⠀⣿⣿⣿⣿⣿⠀⠀⠀
⠀⠀⠀⠸⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⣰⣿⣿⣿⣿⡿⠀⣿⣿⣿⣿⡿⠀⠀⠀
⠀⠀⠀⠀⠈⠻⠿⣿⣿⣿⠿⠟⠋⠀⠾⢿⣿⣿⠿⠟⢁⣼⣿⣿⣿⣿⡇⠀⠀⠀
⠀⠀⠀⠀⣀⣤⣤⣤⣤⣤⣤⣶⣿⣷⣦⣤⣤⣤⣴⣾⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀
⠀⢀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠋⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
Commented out code rule
72
©2023, SonarSource S.A, Switzerland.
Problems
● Compiler bugs
● Code with mistakes
● Code not in Kotlin
● Semantic - VERY SLOW
73
©2023, SonarSource S.A, Switzerland.
©2023, SonarSource S.A, Switzerland.
0
Complaints
©2023, SonarSource S.A, Switzerland.
©2023, SonarSource S.A, Switzerland.
1
Complaint
©2023, SonarSource S.A, Switzerland.
1. Probably not a KDoc?
2. Heuristics: does it look like code?
- Keywords
- if(, for(, catch(, when(, apply{, …
- ++, ||, &&, +=, …
- Contains lambdas, var/val declarations, …
- camelCase, ends with } or {, …
3. Try to parse
Commented out code rule
78
©2023, SonarSource S.A, Switzerland.
What is the most
reported rule?
©2023, SonarSource S.A, Switzerland.
1. Collect potential refs
2. Group by importable name
3. Filter out referenced in KDocs
4. Filter out referenced in code
5. Filter out array access imports
6. Remaining imports are unused
Unnecessary Imports Rule
80
©2023, SonarSource S.A, Switzerland.
1. Collect potential refs
2. Group by importable name
3. Filter out referenced in KDocs
4. Filter out referenced in code
5. FIlter out array access imports
6. Remaining imports are unused
Unnecessary Imports Rule
81
Companion
object
©2023, SonarSource S.A, Switzerland.
1. Collect potential refs
2. Group by importable name
3. Filter out referenced in KDocs
4. Filter out referenced in code
5. FIlter out array access imports
6. Remaining imports are unused
import pkg.MyClass
fun foo() {
val c = MyClass.MY_CONSTANT
}
Unnecessary Imports Rule
82
©2023, SonarSource S.A, Switzerland.
1. Collect potential refs
2. Group by importable name
3. Filter out referenced in KDocs
4. Filter out referenced in code
5. FIlter out array access imports
6. Remaining imports are unused
import pkg.MyClass
fun foo() {
val c = MyClass.MY_CONSTANT
}
Unnecessary Imports Rule
83
False positive!
©2023, SonarSource S.A, Switzerland.
relevantImports.filter {
it.importedFqName != refName && !(
refName.shortName().asString() == "Companion"
&& it.importedFqName == refName.parent()
)
}
import pkg.MyClass
fun foo() {
val c = MyClass.MY_CONSTANT
}
Unnecessary Imports Rule
84
True negative
©2023, SonarSource S.A, Switzerland.
relevantImports.filter {
it.importedFqName != refName && !(
refName.shortName().asString() == "Companion"
&& it.importedFqName == refName.parent()
)
}
import pkg.MyClass
fun foo() {
val c = MyClass.MY_CONSTANT
}
Unnecessary Imports Rule
85
True negative
Named
Companion
object
©2023, SonarSource S.A, Switzerland.
relevantImports.filter {
it.importedFqName != refName && !(
refName.shortName().asString() == "Companion"
&& it.importedFqName == refName.parent()
)
}
class MyClass {
companion object Named {
fun myFun(): String {}
}
}
Unnecessary Imports Rule
86
©2023, SonarSource S.A, Switzerland.
import pkg.MyClass
fun foo() {
val c = MyClass.myFun()
}
False positive!
relevantImports.filter {
it.importedFqName != refName && !(
refName.shortName().asString() == "Companion"
&& it.importedFqName == refName.parent()
)
}
Unnecessary Imports Rule
87
©2023, SonarSource S.A, Switzerland.
import pkg.MyClass
fun foo() {
val c = MyClass.myFun()
}
True negative
relevantImports.filter {
it.importedFqName != refName && !(
refDescriptor.isCompanionObject()
&& it.importedFqName == refName.parent()
)
}
Unnecessary Imports Rule
88
©2023, SonarSource S.A, Switzerland.
import pkg.MyClass
fun foo() {
val c = MyClass.myFun()
}
True negative
relevantImports.filter {
it.importedFqName != refName && !(
refDescriptor.isCompanionObject()
&& it.importedFqName == refName.parent()
)
}
Unnecessary Imports Rule
89
Unresolved
imports
©2023, SonarSource S.A, Switzerland.
1. Collect potential refs
2. Group by importable name
3. Filter out referenced in KDocs
4. Filter out referenced in code
5. FIlter out array access imports
6. Remaining imports are unused
import pkg.MyClass
fun foo() {
val c = MyClass.myFun()
}
Unnecessary Imports Rule
90
©2023, SonarSource S.A, Switzerland.
1. Collect potential refs
2. Group by importable name
3. Filter out referenced in KDocs
4. Filter out referenced in code
5. FIlter out array access imports
6. Remaining imports are unused
import pkg.MyClass
fun foo() {
val c = MyClass.myFun()
}
Unnecessary Imports Rule
91
pkg.MyClass not found
©2023, SonarSource S.A, Switzerland.
1. Filter out unresolved imports
2. Collect potential refs
3. Group by importable name
4. Filter out referenced in KDocs
5. Filter out referenced in code
6. FIlter out array access imports
7. Remaining imports are unused
import pkg.MyClass
fun foo() {
val c = MyClass.myFun()
}
Unnecessary Imports Rule
92
True negative
©2023, SonarSource S.A, Switzerland.
1. Filter out unresolved imports
2. Collect potential refs
3. Group by importable name
4. Filter out referenced in KDocs
5. Filter out referenced in code
6. FIlter out array access imports
7. Remaining imports are unused
import pkg.MyClass
fun foo() {
val c = MyClass.myFun()
}
Unnecessary Imports Rule
93
True negative
Delegates
©2023, SonarSource S.A, Switzerland.
import operators.getValue
class My (delegate: D) {
val p by delegate
}
Unnecessary Imports Rule
94
©2023, SonarSource S.A, Switzerland.
import operators.getValue
class My (delegate: D) {
val p by delegate
}
False positive!
Unnecessary Imports Rule
95
©2023, SonarSource S.A, Switzerland.
if (noSemantic)
skip "getValue", "setValue", "provideDelegate"
else
val delegateRefs =
delegates.flatMap(::importableNames)
if (import in delegateRefs) skip
import operators.getValue
class My (delegate: D) {
val p by delegate
}
False positive!
Unnecessary Imports Rule
96
©2023, SonarSource S.A, Switzerland.
if (noSemantic)
skip "getValue", "setValue", "provideDelegate"
else
val delegateImports =
delegates.flatMap(::importableNames)
if (import in delegateImports) skip
import operators.getValue
class My (delegate: D) {
val p by delegate
}
False positive!
Unnecessary Imports Rule
97
Overloaded
operators
©2023, SonarSource S.A, Switzerland.
import operators.contains
import operators.invoke
class My (list: MyList) {
1 in list
2 !in list
list(0)
}
Unnecessary Imports Rule
98
©2023, SonarSource S.A, Switzerland.
package operators
operator fun MyList.contains(i:
Int) = true
operator fun MyList.invoke(i:
Int) = this
Unnecessary Imports Rule
99
©2023, SonarSource S.A, Switzerland.
import operators.contains
import operators.invoke
class My (list: MyList) {
1 in list
2 !in list
list(0)
}
Unnecessary Imports Rule
100
False positive!
©2023, SonarSource S.A, Switzerland.
import operators.contains
import operators.invoke
class My (list: MyList) {
1 in list
2 !in list
list(0)
}
Unnecessary Imports Rule
101
False positive!
val opRefs = map { operation ->
operation.getReferencedName()
}
imports.filter { import !in opRefs }
©2023, SonarSource S.A, Switzerland.
import operators.contains
import operators.invoke
class My (list: MyList) {
1 in list
2 !in list
list(0)
}
Unnecessary Imports Rule
102
True negative!
val calls by lazy { collectAllCalls() }
imports.filter { import ->
import.simpleName == “invoke”
}.foreach { import ->
if ( import in calls) skip
}
©2023, SonarSource S.A, Switzerland.
import operators.contains
import operators.invoke
class My (list: MyList) {
1 in list
2 !in list
list(0)
}
Unnecessary Imports Rule
103
True negative!
val calls by lazy { collectAllCalls() }
imports.filter { import ->
import.simpleName == “invoke”
}.foreach { import ->
if ( import in calls) skip
}
Java 16+
©2023, SonarSource S.A, Switzerland.
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.streams.toList
fun f(x: String): List<Path> {
return Files.list(x).toList()
}
Unnecessary Imports Rule
104
False positive!
©2023, SonarSource S.A, Switzerland.
@SinceKotlin ("1.2")
public fun <T> Stream<T>.toList(): List<T> = ...
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.streams.toList
fun f(x: String): List<Path> {
return Files.list(x).toList()
}
Unnecessary Imports Rule
105
False positive!
©2023, SonarSource S.A, Switzerland.
@SinceKotlin ("1.2")
public fun <T> Stream<T>.toList(): List<T> = ...
// Since Java 16
public interface Stream<T> {
default List<T> toList() {...}
}
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.streams.toList
fun f(x: String): List<Path> {
return Files.list(x).toList()
}
Unnecessary Imports Rule
106
False positive!
©2023, SonarSource S.A, Switzerland.
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.Paths
import kotlin.streams.toList
fun f(x: String): List<Path> {
return Files.list(x).toList()
}
Unnecessary Imports Rule
107
False positive!
©2023, SonarSource S.A, Switzerland.
©2023, SonarSource S.A, Switzerland.
Achievements
● Improved precision
● 133 rules
● 18 releases
● Rules for regex, security, coroutines
● Rules for Kotlin Gradle DSL
● Up-to-date external linters’ mappings
● Fast community handling
109
©2023, SonarSource S.A, Switzerland.
Takeaways
● Sonar supports Kotlin
● Static analysis for Kotlin is fun
● Be active community member
● Rewrite if needed
110
©2023, SonarSource S.A, Switzerland.
Special
Thanks
©2023, SonarSource S.A, Switzerland.
Initial Kotlin squad
Evgeny
Mandrikov
Johann Beleits
©2023, SonarSource S.A, Switzerland.
©2023, SonarSource S.A, Switzerland.
Thank you
©2023, SonarSource S.A, Switzerland.
Questions?
@jMargaritaN

More Related Content

Similar to Static Kotlin bug hunting Devoxx Morocco.pdf

Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)
Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)
Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)
Agile Lietuva
 
Java 5 6 Generics, Concurrency, Garbage Collection, Tuning
Java 5 6 Generics, Concurrency, Garbage Collection, TuningJava 5 6 Generics, Concurrency, Garbage Collection, Tuning
Java 5 6 Generics, Concurrency, Garbage Collection, Tuning
Carol McDonald
 
CodeFest 2014. Axel Rauschmayer — JavaScript’s variables: scopes, environment...
CodeFest 2014. Axel Rauschmayer — JavaScript’s variables: scopes, environment...CodeFest 2014. Axel Rauschmayer — JavaScript’s variables: scopes, environment...
CodeFest 2014. Axel Rauschmayer — JavaScript’s variables: scopes, environment...
CodeFest
 
Csw2016 gawlik bypassing_differentdefenseschemes
Csw2016 gawlik bypassing_differentdefenseschemesCsw2016 gawlik bypassing_differentdefenseschemes
Csw2016 gawlik bypassing_differentdefenseschemes
CanSecWest
 
Introduction to the Java bytecode - So@t - 20130924
Introduction to the Java bytecode - So@t - 20130924Introduction to the Java bytecode - So@t - 20130924
Introduction to the Java bytecode - So@t - 20130924
yohanbeschi
 

Similar to Static Kotlin bug hunting Devoxx Morocco.pdf (20)

Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)
Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)
Tieto tdd from-dreams_to_reality_s.narkevicius_v.pozdniakov_2013 (1)
 
Kotlin: maybe it's the right time
Kotlin: maybe it's the right timeKotlin: maybe it's the right time
Kotlin: maybe it's the right time
 
Hello, Is That FreeSWITCH? Then We're Coming to Check You!
Hello, Is That FreeSWITCH? Then We're Coming to Check You!Hello, Is That FreeSWITCH? Then We're Coming to Check You!
Hello, Is That FreeSWITCH? Then We're Coming to Check You!
 
Java 5 6 Generics, Concurrency, Garbage Collection, Tuning
Java 5 6 Generics, Concurrency, Garbage Collection, TuningJava 5 6 Generics, Concurrency, Garbage Collection, Tuning
Java 5 6 Generics, Concurrency, Garbage Collection, Tuning
 
Functional Design Explained (David Sankel CppCon 2015)
Functional Design Explained (David Sankel CppCon 2015)Functional Design Explained (David Sankel CppCon 2015)
Functional Design Explained (David Sankel CppCon 2015)
 
Effective Java with Groovy & Kotlin - How Languages Influence Adoption of Goo...
Effective Java with Groovy & Kotlin - How Languages Influence Adoption of Goo...Effective Java with Groovy & Kotlin - How Languages Influence Adoption of Goo...
Effective Java with Groovy & Kotlin - How Languages Influence Adoption of Goo...
 
CodeFest 2014. Axel Rauschmayer — JavaScript’s variables: scopes, environment...
CodeFest 2014. Axel Rauschmayer — JavaScript’s variables: scopes, environment...CodeFest 2014. Axel Rauschmayer — JavaScript’s variables: scopes, environment...
CodeFest 2014. Axel Rauschmayer — JavaScript’s variables: scopes, environment...
 
Csw2016 gawlik bypassing_differentdefenseschemes
Csw2016 gawlik bypassing_differentdefenseschemesCsw2016 gawlik bypassing_differentdefenseschemes
Csw2016 gawlik bypassing_differentdefenseschemes
 
Twig Templating
Twig TemplatingTwig Templating
Twig Templating
 
(Even more) Rapid App Development with RubyMotion
(Even more) Rapid App Development with RubyMotion(Even more) Rapid App Development with RubyMotion
(Even more) Rapid App Development with RubyMotion
 
Progressive transpilation and the road to ES2015 in production
Progressive transpilation and the road to ES2015 in productionProgressive transpilation and the road to ES2015 in production
Progressive transpilation and the road to ES2015 in production
 
Introduction to the Java bytecode - So@t - 20130924
Introduction to the Java bytecode - So@t - 20130924Introduction to the Java bytecode - So@t - 20130924
Introduction to the Java bytecode - So@t - 20130924
 
Android RenderScript on LLVM
Android RenderScript on LLVMAndroid RenderScript on LLVM
Android RenderScript on LLVM
 
iOSNeXT.ro - 10 reasons you'll love Swift - Paul Ardeleanu
iOSNeXT.ro - 10 reasons you'll love Swift - Paul ArdeleanuiOSNeXT.ro - 10 reasons you'll love Swift - Paul Ardeleanu
iOSNeXT.ro - 10 reasons you'll love Swift - Paul Ardeleanu
 
Modern Java Workshop
Modern Java WorkshopModern Java Workshop
Modern Java Workshop
 
The Joy of ServerSide Swift Development
The Joy  of ServerSide Swift DevelopmentThe Joy  of ServerSide Swift Development
The Joy of ServerSide Swift Development
 
The Joy of Server Side Swift Development
The Joy  of Server Side Swift DevelopmentThe Joy  of Server Side Swift Development
The Joy of Server Side Swift Development
 
The Joy Of Server Side Swift Development
The Joy Of Server Side Swift DevelopmentThe Joy Of Server Side Swift Development
The Joy Of Server Side Swift Development
 
Spring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFuSpring Boot Revisited with KoFu and JaFu
Spring Boot Revisited with KoFu and JaFu
 
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaOne 2017 - The hitchhiker’s guide to Java class reloadingJavaOne 2017 - The hitchhiker’s guide to Java class reloading
JavaOne 2017 - The hitchhiker’s guide to Java class reloading
 

Recently uploaded

Jax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined DeckJax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined Deck
Marc Lester
 
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Lisi Hocke
 

Recently uploaded (20)

Workshop - Architecting Innovative Graph Applications- GraphSummit Milan
Workshop -  Architecting Innovative Graph Applications- GraphSummit MilanWorkshop -  Architecting Innovative Graph Applications- GraphSummit Milan
Workshop - Architecting Innovative Graph Applications- GraphSummit Milan
 
Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...
Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...
Abortion Clinic In Johannesburg ](+27832195400*)[ 🏥 Safe Abortion Pills in Jo...
 
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-CloudAlluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
Alluxio Monthly Webinar | Simplify Data Access for AI in Multi-Cloud
 
Test Automation Design Patterns_ A Comprehensive Guide.pdf
Test Automation Design Patterns_ A Comprehensive Guide.pdfTest Automation Design Patterns_ A Comprehensive Guide.pdf
Test Automation Design Patterns_ A Comprehensive Guide.pdf
 
Evolving Data Governance for the Real-time Streaming and AI Era
Evolving Data Governance for the Real-time Streaming and AI EraEvolving Data Governance for the Real-time Streaming and AI Era
Evolving Data Governance for the Real-time Streaming and AI Era
 
Software Engineering - Introduction + Process Models + Requirements Engineering
Software Engineering - Introduction + Process Models + Requirements EngineeringSoftware Engineering - Introduction + Process Models + Requirements Engineering
Software Engineering - Introduction + Process Models + Requirements Engineering
 
A Deep Dive into Secure Product Development Frameworks.pdf
A Deep Dive into Secure Product Development Frameworks.pdfA Deep Dive into Secure Product Development Frameworks.pdf
A Deep Dive into Secure Product Development Frameworks.pdf
 
Jax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined DeckJax, FL Admin Community Group 05.14.2024 Combined Deck
Jax, FL Admin Community Group 05.14.2024 Combined Deck
 
Community is Just as Important as Code by Andrea Goulet
Community is Just as Important as Code by Andrea GouletCommunity is Just as Important as Code by Andrea Goulet
Community is Just as Important as Code by Andrea Goulet
 
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdfThe Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
The Evolution of Web App Testing_ An Ultimate Guide to Future Trends.pdf
 
Prompt Engineering - an Art, a Science, or your next Job Title?
Prompt Engineering - an Art, a Science, or your next Job Title?Prompt Engineering - an Art, a Science, or your next Job Title?
Prompt Engineering - an Art, a Science, or your next Job Title?
 
Modern binary build systems - PyCon 2024
Modern binary build systems - PyCon 2024Modern binary build systems - PyCon 2024
Modern binary build systems - PyCon 2024
 
architecting-ai-in-the-enterprise-apis-and-applications.pdf
architecting-ai-in-the-enterprise-apis-and-applications.pdfarchitecting-ai-in-the-enterprise-apis-and-applications.pdf
architecting-ai-in-the-enterprise-apis-and-applications.pdf
 
Auto Affiliate AI Earns First Commission in 3 Hours..pdf
Auto Affiliate  AI Earns First Commission in 3 Hours..pdfAuto Affiliate  AI Earns First Commission in 3 Hours..pdf
Auto Affiliate AI Earns First Commission in 3 Hours..pdf
 
Weeding your micro service landscape.pdf
Weeding your micro service landscape.pdfWeeding your micro service landscape.pdf
Weeding your micro service landscape.pdf
 
Transformer Neural Network Use Cases with Links
Transformer Neural Network Use Cases with LinksTransformer Neural Network Use Cases with Links
Transformer Neural Network Use Cases with Links
 
Spring into AI presented by Dan Vega 5/14
Spring into AI presented by Dan Vega 5/14Spring into AI presented by Dan Vega 5/14
Spring into AI presented by Dan Vega 5/14
 
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
Team Transformation Tactics for Holistic Testing and Quality (NewCrafts Paris...
 
GraphSummit Milan - Visione e roadmap del prodotto Neo4j
GraphSummit Milan - Visione e roadmap del prodotto Neo4jGraphSummit Milan - Visione e roadmap del prodotto Neo4j
GraphSummit Milan - Visione e roadmap del prodotto Neo4j
 
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
COMPUTER AND ITS COMPONENTS PPT.by naitik sharma Class 9th A mittal internati...
 

Static Kotlin bug hunting Devoxx Morocco.pdf

  • 1. ©2023, SonarSource S.A, Switzerland. Static Kotlin bug hunting 12.10.2023
  • 2. Margarita Nedzelska Software Engineer Conferences speaker & organizer Java/Kotlin/Scala/TS/... @jMargaritaN
  • 3. ©2023, SonarSource S.A, Switzerland. https://www.freepik.com/vectors/ukraine-war Ukraine war vector created by starline - www.freepik.com
  • 5. ©2023, SonarSource S.A, Switzerland. Agenda ● History ● Why Kotlin? ● sonar-kotlin 2.0 ● Feedback ● Achievements ● Takeaways 5
  • 6. ©2023, SonarSource S.A, Switzerland. SonarQube 8.9 (previous LTS) 6
  • 7. ©2023, SonarSource S.A, Switzerland. SonarQube 9.9 (LTS) 7
  • 8. ©2023, SonarSource S.A, Switzerland. What happened?
  • 10. ©2023, SonarSource S.A, Switzerland. Static Analysis
  • 11. ©2023, SonarSource S.A, Switzerland. class HelloWorld { fun f() { println("Hello, World!") } }
  • 12. ©2023, SonarSource S.A, Switzerland.
  • 13. ©2023, SonarSource S.A, Switzerland.
  • 14. ©2023, SonarSource S.A, Switzerland.
  • 15. ©2023, SonarSource S.A, Switzerland. class HelloWorld { fun f() { println("Hello, World!") } }
  • 16. ©2023, SonarSource S.A, Switzerland.
  • 17. ©2023, SonarSource S.A, Switzerland. class HelloWorld { fun f() { println("Hello, World!") } }
  • 18. ©2023, SonarSource S.A, Switzerland. class HelloWorld { fun f() { println("Hello, World!") } }
  • 19. ©2023, SonarSource S.A, Switzerland. SLang AST Kotlin Scala Go Ruby
  • 20. PROs ● 1 rule - many languages ● Fast new languages adoption ● Maintenance ● Rules precision ● Language specific rules ● Testing ● Semantic ● … CONs
  • 21. ©2023, SonarSource S.A, Switzerland. Semantic Model 21
  • 22. ©2023, SonarSource S.A, Switzerland. class HelloWorld { fun f() { println("Hello, World!") } } fun g(x: HelloWorld) { x.f() }
  • 23. ©2023, SonarSource S.A, Switzerland. class HelloWorld { fun f() { println("Hello, World!") } } fun g(x: HelloWorld) { x.f() }
  • 24. ©2023, SonarSource S.A, Switzerland. class HelloWorld { fun f() { println("Hello, World!") } } fun g(x: HelloWorld) { x.f() }
  • 25. ©2023, SonarSource S.A, Switzerland.
  • 26. ©2023, SonarSource S.A, Switzerland. Why Kotlin?
  • 27. ©2023, SonarSource S.A, Switzerland. Why ● Growing popularity of Kotlin ● User feedback ● We wanted to use Kotlin ● Android and Security ● SLang is limited 27
  • 28. ©2023, SonarSource S.A, Switzerland. sonar-kotlin 2.0
  • 29. ©2023, SonarSource S.A, Switzerland. class HelloWorld { fun f() { println("Hello, World!") } } We had
  • 30. ©2023, SonarSource S.A, Switzerland. class HelloWorld { fun f() { println("Hello, World!") } } We wanted
  • 31. ©2023, SonarSource S.A, Switzerland. class HelloWorld { fun f() { println("Hello, World!") } } We implemented
  • 32. ©2023, SonarSource S.A, Switzerland. class HelloWorld { fun f() { println("Hello, World!") } } Technical debt
  • 33. ©2023, SonarSource S.A, Switzerland. class HelloWorld { fun f() { println("Hello, World!") } } Technical debt
  • 34. ©2023, SonarSource S.A, Switzerland. What’s wrong with Kotlin AST 34
  • 35. ©2023, SonarSource S.A, Switzerland. What’s wrong with Kotlin AST ● Nullability hell 35
  • 36. ©2023, SonarSource S.A, Switzerland. 36 override fun visitBinaryExpression(expression: KtBinaryExpression, ...) { val rightExpression = expression. right // Nullable val leftExpression = expression. left // Nullable ... }
  • 37. ©2023, SonarSource S.A, Switzerland. 37 override fun visitBinaryExpression(expression: KtBinaryExpression,...) { val rightExpression = expression. right?.let { val leftExpression = expression. left?.let { ... } } ... }
  • 38. ©2023, SonarSource S.A, Switzerland. 38 override fun visitBinaryExpression(expression: KtBinaryExpression,...) { val rightExpression = expression. right ?: return val leftExpression = expression. left ?: return ... }
  • 39. ©2023, SonarSource S.A, Switzerland. 39 override fun visitBinaryExpression(expression: KtBinaryExpression,...) { val rightExpression = expression. right!! val leftExpression = expression. left!! ... }
  • 40. ©2023, SonarSource S.A, Switzerland. 40 override fun visitBinaryExpression(expression: KtBinaryExpression,...) { // Valid KtBinaryExpression should always have right & left val rightExpression = expression. right!! val leftExpression = expression. left!! ... }
  • 41. ©2023, SonarSource S.A, Switzerland. What’s wrong with Kotlin AST ● Nullability hell ● Lack of Documentation & naming 41
  • 42. ©2023, SonarSource S.A, Switzerland. What is KtNamedFunction?
  • 43. ©2023, SonarSource S.A, Switzerland. Bad Function Name rule 43 fun visitNamedFunction (f: KtNamedFunction, …){ // Named functions always have name val name = f.name!! if (!name.matches(formatRegex)) { reportIssue( f.nameIdentifier!!, "Message" ) } }
  • 44. ©2023, SonarSource S.A, Switzerland. Bad Function Name rule fun visitNamedFunction (f: KtNamedFunction, …){ // Named functions always have name val name = f.name!! if (!name.matches(formatRegex)) { reportIssue( f.nameIdentifier!!, "Message" ) } } 44 val function = fun() {}
  • 45. ©2023, SonarSource S.A, Switzerland. Bad Function Name rule 45 val function = fun() {} java.lang.NullPointerException fun visitNamedFunction (f: KtNamedFunction, …){ // Named functions always have name val name = f.name!! if (!name.matches(formatRegex)) { reportIssue( f.nameIdentifier!!, "Message" ) } }
  • 46. ©2023, SonarSource S.A, Switzerland. Bad Function Name rule 46 val function = fun() {} java.lang.NullPointerException fun visitNamedFunction(f: KtNamedFunction , …){ // Named functions always have name val name = f.name!! if (!name.matches(formatRegex)) { reportIssue( f.nameIdentifier!!, "Message" ) } }
  • 47. ©2023, SonarSource S.A, Switzerland. Bad Function Name rule 47 val function = fun() {} java.lang.NullPointerException fun visitNamedFunction(f: KtNamedFunction , …){ // Named functions always have name val name = f.name!! if (!name.matches(formatRegex)) { reportIssue( f.nameIdentifier!!, "Message" ) } } KtNamedFunction is declared with “fun”
  • 48. ©2023, SonarSource S.A, Switzerland. What’s wrong with Kotlin AST ● Nullability hell ● Lack of Documentation & naming ● Compiler diagnostics 48
  • 49. ©2023, SonarSource S.A, Switzerland. Deprecated Code Used Rule 49
  • 50. ©2023, SonarSource S.A, Switzerland. Deprecated Code Used Rule 50 fun visitKtFile(file: KtFile, ctx: Context) { ctx.diagnostics .filter { it.factory == Errors.DEPRECATION }.forEach { ctx.reportIssue( it.psiElement,"Message" ) } }
  • 51. ©2023, SonarSource S.A, Switzerland. Deprecated Code Used Rule 51 fun visitKtFile(file: KtFile, ctx: Context) { ctx.diagnostics .filter { it.factory == Errors.DEPRECATION }.forEach { ctx.reportIssue( it.psiElement,"Message" ) } } @Deprecated("Some text") enum class MyEnum(val s:String) { ENTRY1(""), }
  • 52. ©2023, SonarSource S.A, Switzerland. Deprecated Code Used Rule 52 fun visitKtFile(file: KtFile, ctx: Context) { ctx.diagnostics .filter { it.factory == Errors.DEPRECATION }.forEach { ctx.reportIssue( it.psiElement,"Message" ) } } @Deprecated("Some text") enum class MyEnum(val s:String) { ENTRY1(""), } java.lang.IndexOutOfBoundsException: (5:11,5:10)
  • 53. ©2023, SonarSource S.A, Switzerland. Deprecated Code Used Rule 53 fun visitKtFile(file: KtFile, ctx: Context) { ctx.diagnostics .filter { it.factory == Errors.DEPRECATION }.forEach { ctx.reportIssue( it.psiElement,"Message" ) } } @Deprecated("Some text") enum class MyEnum(val s:String) { ENTRY1(""), } java.lang.IndexOutOfBoundsException: (5:11,5:10)
  • 54. ©2023, SonarSource S.A, Switzerland. Deprecated Code Used Rule 54 fun visitKtFile(file: KtFile , ctx: Context) { ctx.diagnostics .filter { it.factory == Errors. DEPRECATION }.forEach { ctx.reportIssue( it.psiElement,"Message" ) } } @Deprecated("Some text") enum class MyEnum(val s:String) { ENTRY1[MyEnum](""), } java.lang.IndexOutOfBoundsException: (5:11,5:10)
  • 55. ©2023, SonarSource S.A, Switzerland. Deprecated Code Used Rule 55 fun visitKtFile(file: KtFile , ctx: Context) { ctx.diagnostics .filter { it.factory == Errors. DEPRECATION }.forEach { ctx.reportIssue( it.psiElement,"Message" ) } } @Deprecated("Some text") enum class MyEnum(val s:String) { ENTRY1[MyEnum](""), } java.lang.IndexOutOfBoundsException: (5:11,5:10) Let’s fix it
  • 56. ©2023, SonarSource S.A, Switzerland. Deprecated Code Used Rule 56 fun visitKtFile(file: KtFile , ctx: Context) { ctx.diagnostics .filter { it.factory == Errors. DEPRECATION }.forEach { ctx.reportIssue( adjust(it.psiElement),"Message" ) } } @Deprecated("Some text") enum class MyEnum(val s:String) { ENTRY1(""), }
  • 57. ©2023, SonarSource S.A, Switzerland. sonar-kotlin 2.0 released (24.06.2021) ● Improved 42 existing rules ● 10 new rules ● Semantic ● Detekt, AndroidLint, Ktlint rules sets 57
  • 58. ©2023, SonarSource S.A, Switzerland. Feedback
  • 59. ©2023, SonarSource S.A, Switzerland. Expectations
  • 60. ©2023, SonarSource S.A, Switzerland. Reality
  • 61. ©2023, SonarSource S.A, Switzerland.
  • 62.
  • 63. ©2023, SonarSource S.A, Switzerland. Commented out code check
  • 64. ©2023, SonarSource S.A, Switzerland. 64 import java.util.Random import kotlin.random.Random as KotlinRandom fun f(x: Long) { val random = Random() // val javaRandom = java.util.Random() val kotlinRandom = kotlin.random. Random(0) // Named import is used here val kotlinRandom1 = KotlinRandom(1000L) // x - parameter, no constraints val kotlinRandomLong = kotlin.random. Random(x) /* val xx = 0L val kotlinRandomLongZero = kotlin.random.Random(xx) */ }
  • 65. ©2023, SonarSource S.A, Switzerland. 65 import java.util.Random import kotlin.random.Random as KotlinRandom fun f(x: Long) { val random = Random() // val javaRandom = java.util.Random() val kotlinRandom = kotlin.random. Random(0) // Named import is used here val kotlinRandom1 = KotlinRandom(1000L) // x - parameter, no constraints val kotlinRandomLong = kotlin.random. Random(x) /* val xx = 0L val kotlinRandomLongZero = kotlin.random.Random(xx) */ }
  • 66. ©2023, SonarSource S.A, Switzerland. Before 2.0
  • 67. ©2023, SonarSource S.A, Switzerland. foreach { comment -> when (comment.parse()) { is Success -> reportIssue() is Error -> doNothing() } } Commented out code rule 67
  • 68. ©2023, SonarSource S.A, Switzerland. // Hello World here Commented out code rule 68 foreach { comment -> when (comment.parse()) { is Success -> reportIssue() is Error -> doNothing() } }
  • 69. ©2023, SonarSource S.A, Switzerland. “World” could be an infix function Commented out code rule 69 foreach { comment -> when (comment.parse()) { is Success -> reportIssue() is Error -> doNothing() } } // Hello World here
  • 70. ©2023, SonarSource S.A, Switzerland. After 2.0
  • 71. ©2023, SonarSource S.A, Switzerland. foreach { comment -> when (comment.parseAndSemantic()) { is Success -> reportIssue() is Error -> doNothing() } } Commented out code rule 71
  • 72. ©2023, SonarSource S.A, Switzerland. foreach { comment -> when (comment.parseAndSemantic()) { is Success -> reportIssue() is Error -> doNothing() } } ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣠⣾⣦⠀⢀⠀⠀ ⠀⠀⠀⠀⠀⠀⢀⣤⣶⣶⣿⣿⣷⣶⣦⣄⠀⠀⠀⠀⠀⠀⢰⡟⠈⠁⣰⣿⡗⠀ ⠀⠀⠀⠀⣠⣾⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡀⠀⠀⠀⢸⡇⠀⢠⡟⠀⠀⠀ ⠀⠀⠀⣰⣿⣿⣿⣿⠟⠋⣉⣉⣉⠙⠻⣿⣿⣿⣷⡀⠀⠀⢸⡇⠀⢸⠃⠀⠀⠀ ⠀⠀⢀⣿⣿⣿⣿⡇⢠⣿⣿⣿⢿⣿⣆⠘⣿⣿⣿⣷⡀⠀⢸⣧⠀⢸⡇⠀⠀⠀ ⠀⠀⢸⣿⣿⣿⣿⡇⠸⣿⣿⣿⠆⣿⣿⡄⢸⣿⣿⣿⣧⠀⣼⣿⣿⣿⣇⠀⠀⠀ ⠀⠀⠀⣿⣿⣿⣿⣿⣦⣈⣉⣁⣴⣿⣿⠁⣼⣿⣿⣿⣿⠀⣿⣿⣿⣿⣿⠀⠀⠀ ⠀⠀⠀⠸⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⣰⣿⣿⣿⣿⡿⠀⣿⣿⣿⣿⡿⠀⠀⠀ ⠀⠀⠀⠀⠈⠻⠿⣿⣿⣿⠿⠟⠋⠀⠾⢿⣿⣿⠿⠟⢁⣼⣿⣿⣿⣿⡇⠀⠀⠀ ⠀⠀⠀⠀⣀⣤⣤⣤⣤⣤⣤⣶⣿⣷⣦⣤⣤⣤⣴⣾⣿⣿⣿⣿⣿⡿⠀⠀⠀⠀ ⠀⢀⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠋⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀ Commented out code rule 72
  • 73. ©2023, SonarSource S.A, Switzerland. Problems ● Compiler bugs ● Code with mistakes ● Code not in Kotlin ● Semantic - VERY SLOW 73
  • 74. ©2023, SonarSource S.A, Switzerland.
  • 75. ©2023, SonarSource S.A, Switzerland. 0 Complaints
  • 76. ©2023, SonarSource S.A, Switzerland.
  • 77. ©2023, SonarSource S.A, Switzerland. 1 Complaint
  • 78. ©2023, SonarSource S.A, Switzerland. 1. Probably not a KDoc? 2. Heuristics: does it look like code? - Keywords - if(, for(, catch(, when(, apply{, … - ++, ||, &&, +=, … - Contains lambdas, var/val declarations, … - camelCase, ends with } or {, … 3. Try to parse Commented out code rule 78
  • 79. ©2023, SonarSource S.A, Switzerland. What is the most reported rule?
  • 80. ©2023, SonarSource S.A, Switzerland. 1. Collect potential refs 2. Group by importable name 3. Filter out referenced in KDocs 4. Filter out referenced in code 5. Filter out array access imports 6. Remaining imports are unused Unnecessary Imports Rule 80
  • 81. ©2023, SonarSource S.A, Switzerland. 1. Collect potential refs 2. Group by importable name 3. Filter out referenced in KDocs 4. Filter out referenced in code 5. FIlter out array access imports 6. Remaining imports are unused Unnecessary Imports Rule 81 Companion object
  • 82. ©2023, SonarSource S.A, Switzerland. 1. Collect potential refs 2. Group by importable name 3. Filter out referenced in KDocs 4. Filter out referenced in code 5. FIlter out array access imports 6. Remaining imports are unused import pkg.MyClass fun foo() { val c = MyClass.MY_CONSTANT } Unnecessary Imports Rule 82
  • 83. ©2023, SonarSource S.A, Switzerland. 1. Collect potential refs 2. Group by importable name 3. Filter out referenced in KDocs 4. Filter out referenced in code 5. FIlter out array access imports 6. Remaining imports are unused import pkg.MyClass fun foo() { val c = MyClass.MY_CONSTANT } Unnecessary Imports Rule 83 False positive!
  • 84. ©2023, SonarSource S.A, Switzerland. relevantImports.filter { it.importedFqName != refName && !( refName.shortName().asString() == "Companion" && it.importedFqName == refName.parent() ) } import pkg.MyClass fun foo() { val c = MyClass.MY_CONSTANT } Unnecessary Imports Rule 84 True negative
  • 85. ©2023, SonarSource S.A, Switzerland. relevantImports.filter { it.importedFqName != refName && !( refName.shortName().asString() == "Companion" && it.importedFqName == refName.parent() ) } import pkg.MyClass fun foo() { val c = MyClass.MY_CONSTANT } Unnecessary Imports Rule 85 True negative Named Companion object
  • 86. ©2023, SonarSource S.A, Switzerland. relevantImports.filter { it.importedFqName != refName && !( refName.shortName().asString() == "Companion" && it.importedFqName == refName.parent() ) } class MyClass { companion object Named { fun myFun(): String {} } } Unnecessary Imports Rule 86
  • 87. ©2023, SonarSource S.A, Switzerland. import pkg.MyClass fun foo() { val c = MyClass.myFun() } False positive! relevantImports.filter { it.importedFqName != refName && !( refName.shortName().asString() == "Companion" && it.importedFqName == refName.parent() ) } Unnecessary Imports Rule 87
  • 88. ©2023, SonarSource S.A, Switzerland. import pkg.MyClass fun foo() { val c = MyClass.myFun() } True negative relevantImports.filter { it.importedFqName != refName && !( refDescriptor.isCompanionObject() && it.importedFqName == refName.parent() ) } Unnecessary Imports Rule 88
  • 89. ©2023, SonarSource S.A, Switzerland. import pkg.MyClass fun foo() { val c = MyClass.myFun() } True negative relevantImports.filter { it.importedFqName != refName && !( refDescriptor.isCompanionObject() && it.importedFqName == refName.parent() ) } Unnecessary Imports Rule 89 Unresolved imports
  • 90. ©2023, SonarSource S.A, Switzerland. 1. Collect potential refs 2. Group by importable name 3. Filter out referenced in KDocs 4. Filter out referenced in code 5. FIlter out array access imports 6. Remaining imports are unused import pkg.MyClass fun foo() { val c = MyClass.myFun() } Unnecessary Imports Rule 90
  • 91. ©2023, SonarSource S.A, Switzerland. 1. Collect potential refs 2. Group by importable name 3. Filter out referenced in KDocs 4. Filter out referenced in code 5. FIlter out array access imports 6. Remaining imports are unused import pkg.MyClass fun foo() { val c = MyClass.myFun() } Unnecessary Imports Rule 91 pkg.MyClass not found
  • 92. ©2023, SonarSource S.A, Switzerland. 1. Filter out unresolved imports 2. Collect potential refs 3. Group by importable name 4. Filter out referenced in KDocs 5. Filter out referenced in code 6. FIlter out array access imports 7. Remaining imports are unused import pkg.MyClass fun foo() { val c = MyClass.myFun() } Unnecessary Imports Rule 92 True negative
  • 93. ©2023, SonarSource S.A, Switzerland. 1. Filter out unresolved imports 2. Collect potential refs 3. Group by importable name 4. Filter out referenced in KDocs 5. Filter out referenced in code 6. FIlter out array access imports 7. Remaining imports are unused import pkg.MyClass fun foo() { val c = MyClass.myFun() } Unnecessary Imports Rule 93 True negative Delegates
  • 94. ©2023, SonarSource S.A, Switzerland. import operators.getValue class My (delegate: D) { val p by delegate } Unnecessary Imports Rule 94
  • 95. ©2023, SonarSource S.A, Switzerland. import operators.getValue class My (delegate: D) { val p by delegate } False positive! Unnecessary Imports Rule 95
  • 96. ©2023, SonarSource S.A, Switzerland. if (noSemantic) skip "getValue", "setValue", "provideDelegate" else val delegateRefs = delegates.flatMap(::importableNames) if (import in delegateRefs) skip import operators.getValue class My (delegate: D) { val p by delegate } False positive! Unnecessary Imports Rule 96
  • 97. ©2023, SonarSource S.A, Switzerland. if (noSemantic) skip "getValue", "setValue", "provideDelegate" else val delegateImports = delegates.flatMap(::importableNames) if (import in delegateImports) skip import operators.getValue class My (delegate: D) { val p by delegate } False positive! Unnecessary Imports Rule 97 Overloaded operators
  • 98. ©2023, SonarSource S.A, Switzerland. import operators.contains import operators.invoke class My (list: MyList) { 1 in list 2 !in list list(0) } Unnecessary Imports Rule 98
  • 99. ©2023, SonarSource S.A, Switzerland. package operators operator fun MyList.contains(i: Int) = true operator fun MyList.invoke(i: Int) = this Unnecessary Imports Rule 99
  • 100. ©2023, SonarSource S.A, Switzerland. import operators.contains import operators.invoke class My (list: MyList) { 1 in list 2 !in list list(0) } Unnecessary Imports Rule 100 False positive!
  • 101. ©2023, SonarSource S.A, Switzerland. import operators.contains import operators.invoke class My (list: MyList) { 1 in list 2 !in list list(0) } Unnecessary Imports Rule 101 False positive! val opRefs = map { operation -> operation.getReferencedName() } imports.filter { import !in opRefs }
  • 102. ©2023, SonarSource S.A, Switzerland. import operators.contains import operators.invoke class My (list: MyList) { 1 in list 2 !in list list(0) } Unnecessary Imports Rule 102 True negative! val calls by lazy { collectAllCalls() } imports.filter { import -> import.simpleName == “invoke” }.foreach { import -> if ( import in calls) skip }
  • 103. ©2023, SonarSource S.A, Switzerland. import operators.contains import operators.invoke class My (list: MyList) { 1 in list 2 !in list list(0) } Unnecessary Imports Rule 103 True negative! val calls by lazy { collectAllCalls() } imports.filter { import -> import.simpleName == “invoke” }.foreach { import -> if ( import in calls) skip } Java 16+
  • 104. ©2023, SonarSource S.A, Switzerland. import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths import kotlin.streams.toList fun f(x: String): List<Path> { return Files.list(x).toList() } Unnecessary Imports Rule 104 False positive!
  • 105. ©2023, SonarSource S.A, Switzerland. @SinceKotlin ("1.2") public fun <T> Stream<T>.toList(): List<T> = ... import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths import kotlin.streams.toList fun f(x: String): List<Path> { return Files.list(x).toList() } Unnecessary Imports Rule 105 False positive!
  • 106. ©2023, SonarSource S.A, Switzerland. @SinceKotlin ("1.2") public fun <T> Stream<T>.toList(): List<T> = ... // Since Java 16 public interface Stream<T> { default List<T> toList() {...} } import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths import kotlin.streams.toList fun f(x: String): List<Path> { return Files.list(x).toList() } Unnecessary Imports Rule 106 False positive!
  • 107. ©2023, SonarSource S.A, Switzerland. import java.nio.file.Files import java.nio.file.Path import java.nio.file.Paths import kotlin.streams.toList fun f(x: String): List<Path> { return Files.list(x).toList() } Unnecessary Imports Rule 107 False positive!
  • 108. ©2023, SonarSource S.A, Switzerland.
  • 109. ©2023, SonarSource S.A, Switzerland. Achievements ● Improved precision ● 133 rules ● 18 releases ● Rules for regex, security, coroutines ● Rules for Kotlin Gradle DSL ● Up-to-date external linters’ mappings ● Fast community handling 109
  • 110. ©2023, SonarSource S.A, Switzerland. Takeaways ● Sonar supports Kotlin ● Static analysis for Kotlin is fun ● Be active community member ● Rewrite if needed 110
  • 111. ©2023, SonarSource S.A, Switzerland. Special Thanks
  • 112. ©2023, SonarSource S.A, Switzerland. Initial Kotlin squad Evgeny Mandrikov Johann Beleits
  • 113. ©2023, SonarSource S.A, Switzerland.
  • 114. ©2023, SonarSource S.A, Switzerland. Thank you
  • 115. ©2023, SonarSource S.A, Switzerland. Questions? @jMargaritaN