UNPKG

@sun-asterisk/sunlint

Version:

☀️ SunLint - Multi-language static analysis tool for code quality and security | Sun* Engineering Standards

453 lines (385 loc) 18.1 kB
# 📘 Kotlin Mobile Specific Coding Rules ### 📘 Rule K001 – Use Named Arguments when functions have more than 3 parameters - **Objective**: Improve readability, avoid errors from parameter order confusion, and make function calls clearer. - **Details**: - For functions or constructors with more than 3 parameters, use named arguments to clearly express the meaning of each argument. - Avoid confusion when parameters have the same data type and are positioned close to each other. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`NamedArguments`) - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K002 – Limit function complexity (Cyclomatic Complexity) - **Objective**: Reduce logic complexity and branching to improve readability, testability, and maintainability. - **Details**: - Warn if a function has more than **15 logical branches**. - Includes structures like: `if`, `when`, `&&`, `||`, `for`, `catch`, `?:`, `let`, `run`, `apply`, etc. - Encourage breaking functions into smaller parts, following the SRP principle. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`CognitiveComplexMethod`, `CyclomaticComplexMethod`), SonarQube - **Principles**: CODE_QUALITY, MAINTAINABILITY - **Version**: 1.0 - **Status**: activated - **Severity**: critical ### 📘 Rule K003 – Avoid overly complex conditions - **Objective**: Write clear, readable conditions that are easy to control and understand. - **Details**: - Warn if conditional expressions contain **more than 4 logical operators** (`&&`, `||`, etc.). - Encourage using intermediate variables with descriptive names to improve readability. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`ComplexCondition`), SonarQube - **Principles**: CODE_QUALITY, MAINTAINABILITY - **Version**: 1.0 - **Status**: activated - **Severity**: critical ### 📘 Rule K004 – Avoid nesting code more than 4 levels deep in functions - **Objective**: Simplify logic to improve testability and maintainability. - **Details**: - Warn if a function has nesting depth > 4 levels. - Makes logic difficult to follow when there are many `if`, `when`, `for`, `try-catch` statements. - Encourage breaking into separate functions following the SRP (Single Responsibility Principle). - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`NestedBlockDepth`) - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: critical ### 📘 Rule K005 – Do not use `GlobalScope` - **Objective**: Avoid coroutines that exist beyond their intended lifecycle. - **Details**: - `GlobalScope.launch` is not tied to lifecycle → easily causes resource leaks. - Use `CoroutineScope`, `viewModelScope`, or `lifecycleScope` appropriate to the context. - Reference: [Kotlin Coroutine Docs – GlobalScope](https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-global-scope/) - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`GlobalCoroutineUsage`) - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: critical ### 📘 Rule K006 – Avoid using `suspend` when not necessary - **Objective**: Avoid creating the misconception that a function contains asynchronous logic when it actually doesn't need it. - **Details**: - Only use `suspend` if the function calls other `suspend` functions. - Avoid adding `suspend` to functions that only have simple or synchronous logic. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`RedundantSuspendModifier`) - **Principles**: CODE_QUALITY, PERFORMANCE - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K007 – Use `delay()` instead of `sleep()` in coroutines - **Objective**: Optimize concurrency, avoid unnecessarily blocking threads. - **Details**: - `Thread.sleep()` will block the entire current thread, affecting other coroutines running. - `delay()` is non-blocking and fits well with Kotlin's coroutine architecture. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`SleepInsteadOfDelay`) - **Principles**: CODE_QUALITY, PERFORMANCE - **Version**: 1.0 - **Status**: activated - **Severity**: critical ### 📘 Rule K008 – Do not swallow `CancellationException` in coroutines - **Objective**: Ensure coroutine cancellation is properly propagated to avoid leaks or logic errors. - **Details**: - Must not swallow `CancellationException` inside `runCatching`, `catch`, or `try-catch` without rethrowing. - If swallowed, the coroutine will not be cancelled, causing memory leaks or incorrect logic. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`SuspendFunSwallowedCancellation`) - **Principles**: CODE_QUALITY, PERFORMANCE - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K009 – Do not use `suspend` for functions returning `Flow` - **Objective**: Avoid unnecessary asynchronous declarations, keep code clean. - **Details**: - `Flow` is a cold stream that already supports async, so no need to add `suspend`. - Helps make code clearer and more maintainable. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`SuspendFunWithFlowReturnType`) - **Principles**: CODE_QUALITY, PERFORMANCE - **Version**: 1.0 - **Status**: activated - **Severity**: critical ### 📘 Rule K010 – Do not check/cast exceptions in `catch` blocks - **Objective**: Handle errors clearly, readably, and with the correct error type. - **Details**: - Avoid `if (e is...)`, `e as...` in `catch` blocks. - Prefer writing multiple `catch` blocks for each specific exception type. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`InstanceOfCheckForException`) - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K011 – Use `class` instead of `object` when extending `Throwable` - **Objective**: Avoid using global singletons for exceptions, ensure exceptions carry separate information. - **Details**: - Exceptions usually contain specific information per occurrence → should not be reused. - Use `class` to create new instances for each separate error. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`ObjectExtendsThrowable`) - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K012 – Do not `return` or `throw` in `finally` - **Objective**: Do not lose main logic when handling errors, avoid overriding original exceptions. - **Details**: - `return` or `throw` in `finally` will override or swallow the real exception from `try`. - Makes tracing and debugging difficult when errors occur. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`ReturnFromFinally`, `ThrowingExceptionFromFinally`) - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: critical ### 📘 Rule K013 – Do not wrap and rethrow the same exception type - **Objective**: Preserve the original error cause and stack trace. - **Details**: - Avoid wrapping an exception and rethrowing the same type. - Instead, wrap into a custom or meaningful different exception. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`ThrowingNewInstanceOfSameException`) - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K014 – Use `ArrayPrimitive` instead of `Array<Primitive>` - **Objective**: Improve performance, avoid unnecessary boxing/unboxing. - **Details**: - Use `IntArray`, `FloatArray`, etc. instead of `Array<Int>`, `Array<Float>`, etc. - Avoid redundant memory allocation and reduce overhead. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`ArrayPrimitive`) - **Principles**: PERFORMANCE - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K015 – Use `for` instead of `forEach` on ranges - **Objective**: Avoid creating unnecessary lambdas, improve runtime performance. - **Details**: - `forEach` on ranges is slower than regular `for` loops. - `for` loops are clearer and lighter for range iteration. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`ForEachOnRange`) - **Principles**: PERFORMANCE - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K016 – Do not use `else` in `when` with `enum` or `sealed` classes - **Objective**: Ensure all cases are handled explicitly and are easy to control. - **Details**: - With `enum` or `sealed class`, all cases should be listed exhaustively. - Avoid falling back to `else`, which may lead to missing logic when extending. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`ElseCaseInsteadOfExhaustiveWhen`) - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K017 – Do not directly call Garbage Collector (GC) - **Objective**: Avoid poor performance or unpredictable behavior. - **Details**: - Do not manually call `System.gc()`, `Runtime.getRuntime().gc()`, or `System.runFinalization()`. - JVM already manages GC efficiently; manual intervention can easily cause system overload. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`ExplicitGarbageCollectionCall`) - **Principles**: CODE_QUALITY, PERFORMANCE - **Version**: 1.0 - **Status**: activated - **Severity**: critical ### 📘 Rule K018 – Do not ignore function return values - **Objective**: Avoid losing useful information, handle function results properly. - **Details**: - Should not call functions that return values and ignore the result. - If the result is not needed, the function should return `Unit`. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`IgnoredReturnValue`) - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K019 – Avoid using not-null assertion (!!) to get values from Map - **Objective**: Avoid `NullPointerException` when accessing Map. - **Details**: - Should not use `!!` when getting values from `Map`. - Instead, use safe methods like: `getOrElse`, `getOrDefault`, `getValue`. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`MapGetWithNotNullAssertionOperator`) - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K020 – Do not call `toString()` on nullable objects - **Objective**: Avoid displaying unwanted `"null"` strings. - **Details**: - Use `?.toString()` or `?:` for safe fallback. - Avoid calling `toString()` directly on objects that may be null. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`NullableToStringCall`) - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K021 – Avoid unreachable catch blocks - **Objective**: Remove redundant logic and unreachable code. - **Details**: - Avoid placing `Exception` catch before specific exceptions like `IOException`. - Subsequent `catch` blocks will never be executed. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`UnreachableCatchBlock`) - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K022 – Avoid unsafe casting - **Objective**: Avoid `ClassCastException` and unnecessary runtime errors. - **Details**: - Avoid using `as` if not certain about the data type. - Prefer `as?` and check for null. - Avoid down-casting from immutable collections to mutable ones. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`UnsafeCast`, `DontDowncastCollectionTypes`) - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K023 – Do not use properties before declaration - **Objective**: Avoid logic errors from using uninitialized variables. - **Details**: - Should not use variables in property `get()` if those variables are declared later. - Can easily cause incorrect behavior and is hard to detect. - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`PropertyUsedBeforeDeclaration`) - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K024 – Ensure proper modifier order - **Objective**: Improve consistency and readability in the codebase. - **Details**: - Modifiers should follow the standard order according to Kotlin Convention. - Suggested order: `public/protected/private/internal`, `expect/actual`, `final/open/abstract/sealed/const`, `external`, `override`, `lateinit`, `tailrec`, `vararg`, `suspend`, `inner`, `enum/annotation`, `companion`, `inline`, `infix`, `operator`, `data`, `inner`, `fun/val/var`. - Reference: [Kotlin Coding Convention](https://kotlinlang.org/docs/coding-conventions.html#modifiers-order) - **Applies to**: Kotlin/Android - **Tools**: `detekt` (`ModifierOrder`) - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K025 – Ensure proper parameter order in Composable functions - **Objective**: Ensure usability, memorability, and extensibility of Composable APIs. - **Details**: - According to [Compose Component Guidelines](https://android.googlesource.com/platform/frameworks/support/+/androidx-main/compose/docs/compose-component-api-guidelines.md#component-parameters), parameter order should be: - Required parameters - `modifier` - Optional parameters - Optional Slot (`@Composable`) lambda - **Applies to**: Kotlin/Android - **Tools**: Custom rule, Manual Review - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K026 – Each component should serve a single purpose - **Objective**: Ensure components are easy to maintain, understand, and test. - **Details**: - Each component should perform only one function. - Avoid combining multiple responsibilities such as control, display, and state management. - Follow the Single Responsibility Principle (SRP). - **Applies to**: Kotlin/Android - **Tools**: Code Review, Custom Lint - **Principles**: CODE_QUALITY, DESIGN_PATTERNS - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K027 – Composables returning Unit should use PascalCase and be nouns - **Objective**: Follow naming conventions for Composables in Compose. - **Details**: - Composable functions that create UI should be treated as UI components. - Name them using PascalCase in noun form. - Avoid using verbs or camelCase which might be confused with actions. - **Applies to**: Kotlin/Android - **Tools**: Custom rule, Code Review - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K028 – `@Composable` factory functions that return values should use camelCase - **Objective**: Follow standard Kotlin function naming conventions. - **Details**: - Composables that return values (e.g., `Style`, `Color`, `TextStyle`) should use `camelCase`. - Name them similar to factory or getter functions. - **Applies to**: Kotlin/Android - **Tools**: Custom rule, Code Review - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K029 – Prefer Stateless `@Composable` functions - **Objective**: Increase reusability, reduce complexity and side effects. - **Details**: - `@Composable` should receive `state` from outside rather than managing it internally. - Helps callers control the entire state and makes testing logic easier. - **Applies to**: Kotlin/Android - **Tools**: Custom rule, Code Review - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K030 – Enhance extensibility by declaring state using interfaces - **Objective**: Improve extensibility, reduce coupling with specific implementations. - **Details**: - Use the `interface + factory + private impl` pattern to better control state hoisting. - Limit direct dependencies on implementation classes. - **Applies to**: Kotlin/Android - **Tools**: Code Review - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K031 – Create different components instead of multiple style classes - **Objective**: Increase maintainability and reusability. - **Details**: - Don't group multiple styles into one class. - Separate components according to their purpose. - **Applies to**: Kotlin/Android - **Tools**: Code Review - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K032 – Don't use `null` as default for nullable parameters - **Objective**: Avoid misleading default logic. - **Details**: - Avoid using `null` as default value in `@Composable` to mean "use default". - Provide clear default values instead of handling fallback logic. - **Applies to**: Kotlin/Android - **Tools**: Custom rule, Code Review - **Principles**: CODE_QUALITY, SECURITY - **Version**: 1.0 - **Status**: activated - **Severity**: major ### 📘 Rule K033 – Don't pass `MutableState<T>` to `@Composable` - **Objective**: Prevent unclear state ownership sharing. - **Details**: - Passing `MutableState` directly leads to difficulty controlling ownership. - Pass separated value with callback or use clear state wrapper instead. - **Applies to**: Kotlin/Android - **Tools**: Custom rule, Code Review - **Principles**: CODE_QUALITY, DESIGN_PATTERNS - **Version**: 1.0 - **Status**: activated - **Severity**: critical ### 📘 Rule K034 – Prefer `Slot` parameters for extensibility - **Objective**: Allow users to customize content flexibly. - **Details**: - Using `Slot API` helps extend UI components without changing component definition. - Single slots should be named `content`. - **Applies to**: Kotlin/Android - **Tools**: Custom rule, Code Review - **Principles**: CODE_QUALITY - **Version**: 1.0 - **Status**: activated - **Severity**: major