-
Notifications
You must be signed in to change notification settings - Fork 85
RUM-16056 Add @HotMethod annotation and HotMethodIllegalCall detekt rule
#3558
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
base: develop
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,20 @@ | ||
| /* | ||
| * Unless explicitly stated otherwise all files in this repository are licensed under the Apache License Version 2.0. | ||
| * This product includes software developed at Datadog (https://www.datadoghq.com/). | ||
| * Copyright 2016-Present Datadog, Inc. | ||
| */ | ||
|
|
||
| package com.datadog.android.internal.lint | ||
|
|
||
| /** | ||
| * Marks a method as a hot path — one that can be invoked on every frame or touch event. | ||
| * | ||
| * Implementations must avoid heap allocations, blocking operations, and any work | ||
| * that introduces GC pressure. The IDE/Lint will highlight annotated methods as a | ||
| * reminder to reviewers. | ||
| * | ||
| * @property message A short description of why this method is hot (e.g. "called per frame by JankStats"). | ||
| */ | ||
| @Retention(AnnotationRetention.SOURCE) | ||
| @Target(AnnotationTarget.FUNCTION) | ||
| annotation class HotMethod(val message: String) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,201 @@ | ||
| build: | ||
| maxIssues: 0 | ||
|
|
||
| config: | ||
| validation: true | ||
| warningsAsErrors: true | ||
|
|
||
| comments: | ||
| active: true | ||
| AbsentOrWrongFileLicense: | ||
| active: true | ||
| licenseTemplateFile: 'license.template' | ||
| licenseTemplateIsRegex: false | ||
| excludes: | ||
| # Gradle build outputs and generated artifacts. | ||
| - '**/build/**' | ||
| # Auto-generated Kotlin model fixtures produced by the buildSrc JSON-to-Kotlin code generator. | ||
| - '**/buildSrc/src/test/kotlin/com/example/model/**' | ||
| # Fixture files for the NoOpFactory annotation processor tests, read as text data rather than compiled. | ||
| - '**/tools/noopfactory/src/test/resources/**' | ||
| # Vendored test files ported from the upstream dd-trace-java library. | ||
| - '**/features/dd-sdk-android-trace-internal/src/test/kotlin/com/datadog/trace/**' | ||
|
|
||
| complexity: | ||
| active: false | ||
|
|
||
| coroutines: | ||
| active: false | ||
|
|
||
| empty-blocks: | ||
| active: false | ||
|
|
||
| exceptions: | ||
| active: false | ||
|
|
||
| naming: | ||
| active: false | ||
|
|
||
| potential-bugs: | ||
| active: false | ||
|
|
||
| style: | ||
| active: false | ||
|
|
||
| datadog: | ||
| active: true | ||
| excludes: | ||
| - '**/build/**' | ||
| - '**/test/**' | ||
| - '**/testDebug/**' | ||
| - '**/testRelease/**' | ||
| - '**/androidTest/**' | ||
| - '**/testFixtures/**' | ||
| - '**/buildSrc/**' | ||
| - '**/*.kts' | ||
| - '**/instrumented/**' | ||
| - '**/reliability/**' | ||
| - '**/sample/**' | ||
| - '**/tools/**' | ||
| HotMethodIllegalCall: | ||
| active: true | ||
| # Lambda literals passed to functions in `allowedInlineFunctions` are inlined by the compiler | ||
| # and do not allocate — they are excluded from the lambda-allocation check. | ||
| # Add any project-specific `inline` functions here. | ||
| allowedInlineFunctions: | ||
|
satween marked this conversation as resolved.
|
||
| # Kotlin scope functions | ||
| - 'let' | ||
| - 'also' | ||
| - 'apply' | ||
| - 'run' | ||
| - 'with' | ||
| - 'takeIf' | ||
| - 'takeUnless' | ||
| # Standard utilities | ||
| - 'synchronized' | ||
| - 'use' | ||
| - 'repeat' | ||
| - 'measureNanoTime' | ||
| - 'measureTimeMillis' | ||
| # Kotlin stdlib collection operations — ALL are inline, lambdas are not allocated | ||
| - 'filter' | ||
| - 'filterNot' | ||
| - 'filterIsInstance' | ||
| - 'filterNotNull' | ||
| - 'map' | ||
| - 'mapNotNull' | ||
| - 'mapIndexed' | ||
| - 'flatMap' | ||
| - 'flatten' | ||
| - 'forEach' | ||
| - 'forEachIndexed' | ||
| - 'any' | ||
| - 'all' | ||
| - 'none' | ||
| - 'count' | ||
| - 'find' | ||
| - 'findLast' | ||
| - 'first' | ||
| - 'firstOrNull' | ||
| - 'last' | ||
| - 'lastOrNull' | ||
| - 'single' | ||
| - 'singleOrNull' | ||
| - 'reduce' | ||
| - 'fold' | ||
| - 'foldIndexed' | ||
| - 'sumOf' | ||
| - 'maxByOrNull' | ||
| - 'minByOrNull' | ||
| - 'maxOrNull' | ||
| - 'minOrNull' | ||
| - 'groupBy' | ||
| - 'associate' | ||
| - 'associateBy' | ||
| - 'partition' | ||
| - 'sortedBy' | ||
| - 'sortedWith' | ||
| - 'sorted' | ||
| - 'toList' | ||
| - 'toMutableList' | ||
| - 'toSet' | ||
| - 'toMutableSet' | ||
| - 'toMap' | ||
| # Builder functions — inline, so the lambda body is inlined (the builder itself still allocates) | ||
| - 'buildString' | ||
| - 'buildList' | ||
| - 'buildSet' | ||
| - 'buildMap' | ||
| # Both lists use `ContainerFQN.method` format (or `SimpleClass.method` as a suffix match). | ||
| # For top-level factory functions the container is the package (e.g. kotlin.collections). | ||
| # emptyList/emptySet/emptyMap are intentionally excluded — they return cached singletons. | ||
| forbiddenFactoryFunctions: | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
The factory list omits lower-case array factories like Useful? React with 👍 / 👎. |
||
| - 'kotlin.collections.listOf' | ||
| - 'kotlin.collections.mutableListOf' | ||
| - 'kotlin.collections.arrayListOf' | ||
| - 'kotlin.collections.setOf' | ||
| - 'kotlin.collections.mutableSetOf' | ||
| - 'kotlin.collections.hashSetOf' | ||
| - 'kotlin.collections.linkedSetOf' | ||
| - 'kotlin.collections.mapOf' | ||
| - 'kotlin.collections.mutableMapOf' | ||
| - 'kotlin.collections.hashMapOf' | ||
| - 'kotlin.collections.linkedMapOf' | ||
| - 'kotlin.collections.buildList' | ||
| - 'kotlin.collections.buildSet' | ||
| - 'kotlin.collections.buildMap' | ||
| - 'kotlin.text.buildString' | ||
| forbiddenCalls: | ||
| # Linear search | ||
| - 'kotlin.collections.List.find' | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
With the current List-only entries, a hot method using a Useful? React with 👍 / 👎. |
||
| - 'kotlin.collections.List.findLast' | ||
| - 'kotlin.collections.List.first' | ||
| - 'kotlin.collections.List.firstOrNull' | ||
| - 'kotlin.collections.List.last' | ||
| - 'kotlin.collections.List.lastOrNull' | ||
| - 'kotlin.collections.List.single' | ||
| - 'kotlin.collections.List.singleOrNull' | ||
| - 'kotlin.collections.List.indexOf' | ||
| - 'kotlin.collections.List.indexOfFirst' | ||
| - 'kotlin.collections.List.indexOfLast' | ||
| - 'kotlin.collections.List.lastIndexOf' | ||
| - 'kotlin.collections.List.any' | ||
| - 'kotlin.collections.List.all' | ||
| - 'kotlin.collections.List.none' | ||
| - 'kotlin.collections.List.count' | ||
| # Full iteration — allocates an iterator each call | ||
| - 'kotlin.collections.List.forEach' | ||
| - 'kotlin.collections.List.forEachIndexed' | ||
| - 'kotlin.collections.List.reduce' | ||
| - 'kotlin.collections.List.fold' | ||
| - 'kotlin.collections.List.foldIndexed' | ||
| - 'kotlin.collections.List.sumOf' | ||
| - 'kotlin.collections.List.maxOrNull' | ||
| - 'kotlin.collections.List.minOrNull' | ||
| - 'kotlin.collections.List.maxByOrNull' | ||
| - 'kotlin.collections.List.minByOrNull' | ||
| # Materialising — allocates a new collection each call | ||
| - 'kotlin.collections.List.filter' | ||
| - 'kotlin.collections.List.filterNot' | ||
| - 'kotlin.collections.List.filterIsInstance' | ||
| - 'kotlin.collections.List.filterNotNull' | ||
| - 'kotlin.collections.List.map' | ||
| - 'kotlin.collections.List.mapNotNull' | ||
| - 'kotlin.collections.List.mapIndexed' | ||
| - 'kotlin.collections.List.flatMap' | ||
| - 'kotlin.collections.List.flatten' | ||
| - 'kotlin.collections.List.toList' | ||
| - 'kotlin.collections.List.toMutableList' | ||
| - 'kotlin.collections.List.toSet' | ||
| - 'kotlin.collections.List.toMutableSet' | ||
| - 'kotlin.collections.List.toMap' | ||
| - 'kotlin.collections.List.groupBy' | ||
| - 'kotlin.collections.List.associate' | ||
| - 'kotlin.collections.List.associateBy' | ||
| - 'kotlin.collections.List.partition' | ||
| # Sorting — O(N log N) | ||
| - 'kotlin.collections.List.sorted' | ||
| - 'kotlin.collections.List.sortedBy' | ||
| - 'kotlin.collections.List.sortedWith' | ||
| datadog-test-pyramid: | ||
| active: false | ||
Uh oh!
There was an error while loading. Please reload this page.