Fix MetricsPixelNumericValueDetector for compiled Kotlin classes#7953
Merged
marcosholgado merged 3 commits intodevelopfrom Mar 13, 2026
Merged
Conversation
…s and skip REORDER_ARGUMENTS test mode
Contributor
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
Autofix Details
Bugbot Autofix prepared a fix for the issue found in the latest run.
- ✅ Fixed: Detected violation silently dropped when findArgExpr returns null
- I replaced the early return with a fallback to report on the call node so invalid non-numeric values are always reported even when argument UAST conversion fails.
Or push these changes by commenting:
@cursor push a7b2e2e2d8
Preview (a7b2e2e2d8)
diff --git a/lint-rules/src/main/java/com/duckduckgo/lint/MetricsPixelNumericValueDetector.kt b/lint-rules/src/main/java/com/duckduckgo/lint/MetricsPixelNumericValueDetector.kt
--- a/lint-rules/src/main/java/com/duckduckgo/lint/MetricsPixelNumericValueDetector.kt
+++ b/lint-rules/src/main/java/com/duckduckgo/lint/MetricsPixelNumericValueDetector.kt
@@ -72,8 +72,8 @@
val valueStr = valueText.removeSurrounding("\"")
if (valueStr.toIntOrNull() == null) {
- // Report on the value argument expression.
- val valueExpr = findArgExpr(node, "value") ?: return
+ // Prefer reporting on the value argument expression, but never drop the violation.
+ val valueExpr = findArgExpr(node, "value") ?: node
context.report(
NUMERIC_VALUE_REQUIRED,
valueExpr,
lint-rules/src/main/java/com/duckduckgo/lint/MetricsPixelNumericValueDetector.kt
Outdated
Show resolved
Hide resolved
Contributor
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 2 potential issues.
Bugbot Autofix prepared fixes for both issues found in the latest run.
- ✅ Fixed: Non-literal value expressions now trigger false positives
- The detector now evaluates the
valueargument as a compile-time constant string and skips non-constant expressions, restoring the previous false-positive-safe behavior.
- The detector now evaluates the
- ✅ Fixed: Out-of-order test duplicates existing test's argument order
- The out-of-order test now places
typebeforevalueso it genuinely validates named-argument lookup independent of argument position.
- The out-of-order test now places
Or push these changes by commenting:
@cursor push 55264103c7
Preview (55264103c7)
diff --git a/lint-rules/src/main/java/com/duckduckgo/lint/MetricsPixelNumericValueDetector.kt b/lint-rules/src/main/java/com/duckduckgo/lint/MetricsPixelNumericValueDetector.kt
--- a/lint-rules/src/main/java/com/duckduckgo/lint/MetricsPixelNumericValueDetector.kt
+++ b/lint-rules/src/main/java/com/duckduckgo/lint/MetricsPixelNumericValueDetector.kt
@@ -67,14 +67,10 @@
val typeText = findArgText(node, "type") ?: return
if (!typeText.contains("COUNT_WHEN_IN_WINDOW") && !typeText.contains("COUNT_ALWAYS")) return
- val valueText = findArgText(node, "value") ?: return
- // Strip surrounding quotes from a string literal so we can check if it's an integer.
- val valueStr = valueText.removeSurrounding("\"")
+ val valueExpr = findArgExpr(node, "value") ?: return
+ val valueStr = valueExpr.evaluate() as? String ?: return
if (valueStr.toIntOrNull() == null) {
- // Report on the value argument expression; fall back to the call site if the
- // expression can't be resolved (e.g. UastFacade.convertElement fails in Path 2).
- val valueExpr: UExpression = findArgExpr(node, "value") ?: node
context.report(
NUMERIC_VALUE_REQUIRED,
valueExpr,
diff --git a/lint-rules/src/test/java/com/duckduckgo/lint/MetricsPixelNumericValueDetectorTest.kt b/lint-rules/src/test/java/com/duckduckgo/lint/MetricsPixelNumericValueDetectorTest.kt
--- a/lint-rules/src/test/java/com/duckduckgo/lint/MetricsPixelNumericValueDetectorTest.kt
+++ b/lint-rules/src/test/java/com/duckduckgo/lint/MetricsPixelNumericValueDetectorTest.kt
@@ -169,10 +169,10 @@
fun doSomething(toggle: Any) {
MetricsPixel(
metric = "some_metric",
- value = "not_a_number",
+ type = MetricType.COUNT_ALWAYS,
toggle = toggle as com.duckduckgo.feature.toggles.api.Toggle,
conversionWindow = listOf(ConversionWindow(0, 1)),
- type = MetricType.COUNT_ALWAYS,
+ value = "not_a_number",
)
}
}
lint-rules/src/main/java/com/duckduckgo/lint/MetricsPixelNumericValueDetector.kt
Show resolved
Hide resolved
lint-rules/src/test/java/com/duckduckgo/lint/MetricsPixelNumericValueDetectorTest.kt
Show resolved
Hide resolved
anikiki
approved these changes
Mar 13, 2026
Contributor
anikiki
left a comment
There was a problem hiding this comment.
Looks good and works as expected! 🎉
This was referenced Mar 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Task/Issue URL: https://app.asana.com/1/137249556945/project/1202552961248957/task/1213634576464400
Description
The
MetricsPixelNumericValueDetectorlint rule was silently missing violations whenMetricsPixelwas used in modules where the class is loaded from a compiled dependency JAR — the constructorPsiMethodcan't be resolved in that case, sovisitConstructornever fired.This PR adds a fallback detection path via
getApplicableUastTypes/createUastHandlerthat triggers on allUCallExpressionnodes and uses source text matching + return type filtering to identifyMetricsPixelcalls. Named-argument lookup was also reworked to useUNamedExpressionwith a Kotlin PSI fallback, making it robust regardless of argument order. All tests now skipTestMode.REORDER_ARGUMENTSto suppress a known lint test infrastructure warning caused by overlapping edits when positional args are nested inside outer named args.Steps to test this PR
MetricsPixelNumericValueDetector
SearchMetricPixelsPluginso one of them has a value that's not a number, i.e. "test"./gradlew :feature-toggles-impl:lintUI changes
Note
Medium Risk
Medium risk because it changes lint detection logic to rely on UAST/PSI fallbacks and source-text matching, which could introduce false positives/negatives across Kotlin call shapes.
Overview
Fixes
MetricsPixelNumericValueDetectormissing violations whenMetricsPixelcomes from a compiled dependency by adding a fallback scan over allUCallExpressions and filtering toMetricsPixelcalls when the constructor can’t be resolved.Reworks argument extraction to be robust to named/out-of-order arguments by using
UNamedExpressionwith a Kotlin PSI fallback, and improves error location selection by reporting on thevalueexpression when possible.Updates tests to reflect the real
MetricsPixelsignature (defaulttype), adds coverage for out-of-order named arguments, and skipsTestMode.REORDER_ARGUMENTSto avoid test infra issues.Written by Cursor Bugbot for commit 693bca6. This will update automatically on new commits. Configure here.