pi-lens 3.8.73 → 3.8.74

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/CHANGELOG.md +1116 -0
  2. package/README.md +37 -21
  3. package/dist/clients/atomic-write.js +3 -3
  4. package/dist/clients/bus-events-logger.js +5 -1
  5. package/dist/clients/cache/rule-cache.js +43 -2
  6. package/dist/clients/cache-observability.js +211 -0
  7. package/dist/clients/call-graph.js +20 -0
  8. package/dist/clients/cascade-logger.js +5 -1
  9. package/dist/clients/complexity-client.js +4 -7
  10. package/dist/clients/dependency-checker.js +151 -20
  11. package/dist/clients/diagnostic-dispositions.js +22 -2
  12. package/dist/clients/dispatch/auxiliary-lsp.js +34 -0
  13. package/dist/clients/dispatch/dispatcher.js +16 -1
  14. package/dist/clients/dispatch/fact-store.js +11 -0
  15. package/dist/clients/dispatch/facts/function-facts.js +14 -0
  16. package/dist/clients/dispatch/facts/import-facts.js +100 -101
  17. package/dist/clients/dispatch/facts/tree-sitter-facts.js +5 -8
  18. package/dist/clients/dispatch/facts/try-catch-facts.js +13 -0
  19. package/dist/clients/dispatch/integration.js +94 -15
  20. package/dist/clients/dispatch/rules/async-noise.js +1 -0
  21. package/dist/clients/dispatch/rules/unsafe-boundary.js +7 -0
  22. package/dist/clients/dispatch/runners/ast-grep-napi.js +24 -1
  23. package/dist/clients/dispatch/runners/psscriptanalyzer.js +10 -1
  24. package/dist/clients/dispatch/runners/tree-sitter.js +153 -166
  25. package/dist/clients/dispatch/runners/utils/runner-helpers.js +17 -18
  26. package/dist/clients/feature-hints.js +53 -7
  27. package/dist/clients/file-kinds.js +86 -31
  28. package/dist/clients/fix-worklog.js +14 -2
  29. package/dist/clients/generated-artifacts.js +21 -0
  30. package/dist/clients/gzip-stage-write.js +84 -0
  31. package/dist/clients/installer/index.js +358 -129
  32. package/dist/clients/knip-client.js +64 -1
  33. package/dist/clients/language-profile.js +61 -72
  34. package/dist/clients/latency-logger.js +6 -16
  35. package/dist/clients/lens-config.js +128 -165
  36. package/dist/clients/lens-engine.js +39 -5
  37. package/dist/clients/lens-flag-registry.js +285 -0
  38. package/dist/clients/lens-map.js +2 -7
  39. package/dist/clients/log-cleanup.js +6 -17
  40. package/dist/clients/lsp/cascade-tier.js +22 -2
  41. package/dist/clients/lsp/client.js +74 -10
  42. package/dist/clients/lsp/config.js +62 -9
  43. package/dist/clients/lsp/index.js +34 -24
  44. package/dist/clients/lsp/language.js +4 -1
  45. package/dist/clients/lsp/launch.js +8 -6
  46. package/dist/clients/lsp/server.js +84 -29
  47. package/dist/clients/lsp-document-symbols.js +112 -0
  48. package/dist/clients/mcp/analyze.js +5 -4
  49. package/dist/clients/mcp/review.js +36 -3
  50. package/dist/clients/module-report.js +100 -80
  51. package/dist/clients/ndjson-logger.js +51 -21
  52. package/dist/clients/path-keyed-map.js +76 -0
  53. package/dist/clients/path-utils.js +35 -0
  54. package/dist/clients/performance-report.js +327 -0
  55. package/dist/clients/pipeline.js +7 -0
  56. package/dist/clients/project-changes.js +77 -4
  57. package/dist/clients/project-diagnostics/extractors.js +26 -115
  58. package/dist/clients/project-diagnostics/fresh-fetch.js +149 -19
  59. package/dist/clients/project-diagnostics/runner-adapters/call-graph-impact.js +109 -0
  60. package/dist/clients/project-diagnostics/runner-adapters/runner-findings.js +37 -5
  61. package/dist/clients/project-diagnostics/scanner.js +247 -127
  62. package/dist/clients/project-lens-config.js +53 -26
  63. package/dist/clients/project-report.js +39 -14
  64. package/dist/clients/project-scale.js +8 -10
  65. package/dist/clients/project-snapshot-persist-worker.js +6 -0
  66. package/dist/clients/project-snapshot.js +611 -7
  67. package/dist/clients/quiet-window.js +9 -1
  68. package/dist/clients/read-expansion.js +22 -12
  69. package/dist/clients/read-guard.js +78 -0
  70. package/dist/clients/redact/secrets.js +449 -0
  71. package/dist/clients/resource-sampler.js +133 -14
  72. package/dist/clients/reverse-deps.js +48 -0
  73. package/dist/clients/review-graph/builder.js +1522 -179
  74. package/dist/clients/review-graph/persist-worker.js +10 -0
  75. package/dist/clients/review-graph/query.js +5 -0
  76. package/dist/clients/review-graph/shared-extraction-ir.js +90 -0
  77. package/dist/clients/review-graph-logger.js +24 -0
  78. package/dist/clients/runtime-agent-end.js +4 -2
  79. package/dist/clients/runtime-coordinator.js +2 -2
  80. package/dist/clients/runtime-session.js +433 -59
  81. package/dist/clients/runtime-tool-call.js +46 -14
  82. package/dist/clients/runtime-turn.js +97 -26
  83. package/dist/clients/safe-spawn.js +102 -15
  84. package/dist/clients/session-start-observability.js +15 -0
  85. package/dist/clients/session-state-store.js +2 -1
  86. package/dist/clients/sessionstart-logger.js +18 -0
  87. package/dist/clients/sg-runner.js +48 -33
  88. package/dist/clients/source-filter.js +49 -25
  89. package/dist/clients/startup-marker.js +6 -0
  90. package/dist/clients/startup-timing.js +9 -0
  91. package/dist/clients/todo-scanner.js +30 -3
  92. package/dist/clients/tree-sitter-cache.js +147 -139
  93. package/dist/clients/tree-sitter-client.js +1340 -67
  94. package/dist/clients/tree-sitter-logger.js +43 -1
  95. package/dist/clients/tree-sitter-query-loader.js +110 -11
  96. package/dist/clients/tree-sitter-shared.js +43 -19
  97. package/dist/clients/tree-sitter-symbol-extractor.js +71 -4
  98. package/dist/clients/widget-state.js +50 -14
  99. package/dist/clients/word-index-logger.js +44 -0
  100. package/dist/clients/word-index.js +252 -35
  101. package/dist/clients/workspace-topology.js +11 -1
  102. package/dist/index.js +45544 -39255
  103. package/dist/mcp/analyze-cli.js +3 -0
  104. package/dist/mcp/cli.js +110 -0
  105. package/dist/mcp/server.js +63 -8
  106. package/dist/tools/lens-diagnostics.js +47 -5
  107. package/dist/tools/lsp-navigation.js +5 -28
  108. package/dist/tools/symbol-search.js +21 -2
  109. package/docs/agent-guide.md +247 -0
  110. package/docs/astplayground.md +3 -4
  111. package/docs/audit1.md +5 -5
  112. package/docs/environment-variables.md +153 -11
  113. package/docs/features.md +4 -3
  114. package/docs/globalconfig.md +56 -4
  115. package/docs/language-coverage.md +2 -2
  116. package/docs/mcp.md +17 -16
  117. package/docs/servercapabilities.md +5 -2
  118. package/docs/settings.md +181 -0
  119. package/docs/tools.md +14 -0
  120. package/docs/tree-sitter_rules_catalog.md +11 -31
  121. package/docs/usage.md +13 -0
  122. package/package.json +139 -138
  123. package/rules/ast-grep-rules/rule-tests/hardcoded-url-js-test.yml +1 -0
  124. package/rules/ast-grep-rules/rule-tests/hardcoded-url-test.yml +2 -0
  125. package/rules/ast-grep-rules/rule-tests/no-case-declarations-js-test.yml +10 -0
  126. package/rules/ast-grep-rules/rule-tests/no-case-declarations-test.yml +10 -0
  127. package/rules/ast-grep-rules/rule-tests/no-javascript-url-js-test.yml +10 -0
  128. package/rules/ast-grep-rules/rule-tests/no-javascript-url-test.yml +10 -0
  129. package/rules/ast-grep-rules/rule-tests/strict-equality-js-test.yml +3 -0
  130. package/rules/ast-grep-rules/rule-tests/strict-equality-test.yml +3 -0
  131. package/rules/ast-grep-rules/rule-tests/strict-inequality-js-test.yml +3 -0
  132. package/rules/ast-grep-rules/rule-tests/strict-inequality-test.yml +4 -0
  133. package/rules/ast-grep-rules/rules/hardcoded-url-js.yml +22 -4
  134. package/rules/ast-grep-rules/rules/hardcoded-url.yml +22 -4
  135. package/rules/ast-grep-rules/rules/no-case-declarations-js.yml +4 -3
  136. package/rules/ast-grep-rules/rules/no-case-declarations.yml +4 -3
  137. package/rules/ast-grep-rules/rules/no-console-except-error-js.yml +10 -0
  138. package/rules/ast-grep-rules/rules/no-console-except-error.yml +10 -0
  139. package/rules/ast-grep-rules/rules/no-javascript-url-js.yml +42 -6
  140. package/rules/ast-grep-rules/rules/no-javascript-url.yml +42 -6
  141. package/rules/ast-grep-rules/rules/strict-equality-js.yml +14 -1
  142. package/rules/ast-grep-rules/rules/strict-equality.yml +14 -1
  143. package/rules/ast-grep-rules/rules/strict-inequality-js.yml +14 -1
  144. package/rules/ast-grep-rules/rules/strict-inequality.yml +14 -1
  145. package/rules/tree-sitter-queries/cpp/no-memset-sensitive-data.yml +9 -3
  146. package/rules/tree-sitter-queries/cpp/no-scoped-lock-without-args.yml +6 -6
  147. package/rules/tree-sitter-queries/css/calc-spacing.yml +8 -6
  148. package/rules/tree-sitter-queries/go/go-mutex-copy.yml +21 -18
  149. package/rules/tree-sitter-queries/go/go-shared-map-write-goroutine.yml +3 -3
  150. package/rules/tree-sitter-queries/java/infinite-loop-java.yml +3 -3
  151. package/rules/tree-sitter-queries/java/junit-call-super.yml +6 -4
  152. package/rules/tree-sitter-queries/java/no-double-checked-locking.yml +10 -8
  153. package/rules/tree-sitter-queries/java/no-field-shadowing.yml +1 -1
  154. package/rules/tree-sitter-queries/java/prepared-statement-valid-indices.yml +2 -3
  155. package/rules/tree-sitter-queries/java/resources-closed.yml +2 -2
  156. package/rules/tree-sitter-queries/java/springboot-default-package.yml +6 -3
  157. package/rules/tree-sitter-queries/java/switch-fall-through.yml +6 -4
  158. package/rules/tree-sitter-queries/java/switch-non-case-labels.yml +4 -3
  159. package/rules/tree-sitter-queries/java/tests-include-assertions.yml +6 -5
  160. package/rules/tree-sitter-queries/javascript/switch-case-termination-js.yml +5 -8
  161. package/rules/tree-sitter-queries/javascript/switch-non-case-labels.yml +3 -2
  162. package/rules/tree-sitter-queries/kotlin/prepared-statement-indices.yml +9 -5
  163. package/rules/tree-sitter-queries/php/this-in-static-context.yml +5 -5
  164. package/rules/tree-sitter-queries/python/exit-signature-check.yml +2 -9
  165. package/rules/tree-sitter-queries/python/in-operator-unsupported.yml +3 -4
  166. package/rules/tree-sitter-queries/python/no-super-torchscript.yml +4 -8
  167. package/rules/tree-sitter-queries/python/notimplemented-boolean-context.yml +1 -5
  168. package/rules/tree-sitter-queries/python/python-empty-except.yml +1 -1
  169. package/rules/tree-sitter-queries/python/return-in-init.yml +0 -2
  170. package/rules/tree-sitter-queries/python/yield-return-outside-function.yml +0 -3
  171. package/rules/tree-sitter-queries/ruby/ruby-command-injection.yml +1 -12
  172. package/rules/tree-sitter-queries/ruby/ruby-eval.yml +1 -1
  173. package/rules/tree-sitter-queries/ruby/ruby-insecure-deserialization.yml +4 -4
  174. package/rules/tree-sitter-queries/ruby/ruby-insecure-random.yml +4 -11
  175. package/rules/tree-sitter-queries/ruby/ruby-open-struct.yml +1 -1
  176. package/rules/tree-sitter-queries/ruby/ruby-string-eval.yml +2 -3
  177. package/rules/tree-sitter-queries/ruby/ruby-weak-hash.yml +4 -4
  178. package/rules/tree-sitter-queries/rust/rust-lock-held-across-await.yml +4 -3
  179. package/rules/tree-sitter-queries/typescript/console-statement.yml +11 -0
  180. package/rules/tree-sitter-queries/typescript/duplicate-function-arg.yml +4 -9
  181. package/rules/tree-sitter-queries/typescript/empty-switch-case.yml +13 -9
  182. package/rules/tree-sitter-queries/typescript/infinite-loop.yml +2 -2
  183. package/rules/tree-sitter-queries/typescript/mixed-async-styles.yml +10 -1
  184. package/rules/tree-sitter-queries/typescript/switch-case-termination.yml +5 -8
  185. package/rules/tree-sitter-queries/typescript/ts-insecure-random.yml +7 -10
  186. package/rules/tree-sitter-queries/typescript/unsafe-regex.yml +4 -2
  187. package/rules/typos/_typos.toml +17 -0
  188. package/skills/pi-lens-write-tree-sitter-rule/SKILL.md +5 -0
  189. package/dist/clients/config-enabled-shape.js +0 -39
  190. package/docs/env_variables.md +0 -10
  191. package/rules/tree-sitter-queries/abap-disabled/delete-where.yml +0 -46
  192. package/rules/tree-sitter-queries/cpp/no-confused-move-forward.yml +0 -59
  193. package/rules/tree-sitter-queries/cpp/noexcept-functions.yml +0 -58
  194. package/rules/tree-sitter-queries/java/mockito-initialized.yml +0 -66
  195. package/rules/tree-sitter-queries/java/no-wait-notify-on-thread.yml +0 -58
  196. package/rules/tree-sitter-queries/java/short-circuit-logic.yml +0 -57
  197. package/rules/tree-sitter-queries/java/spring-session-attributes-setcomplete.yml +0 -75
  198. package/rules/tree-sitter-queries/plsql-disabled/delete-update-where.yml +0 -56
  199. package/rules/tree-sitter-queries/plsql-disabled/end-loop-semicolon.yml +0 -51
  200. package/rules/tree-sitter-queries/plsql-disabled/fetch-bulk-collect-limit.yml +0 -47
  201. package/rules/tree-sitter-queries/plsql-disabled/forallsave-exceptions.yml +0 -51
  202. package/rules/tree-sitter-queries/plsql-disabled/nchar-nvarchar2-bytes.yml +0 -54
  203. package/rules/tree-sitter-queries/plsql-disabled/not-null-initialization.yml +0 -59
  204. package/rules/tree-sitter-queries/plsql-disabled/raise-application-error-codes.yml +0 -50
  205. package/rules/tree-sitter-queries/typescript-disabled/ts-path-traversal.yml +0 -71
@@ -15,13 +15,49 @@ note: |
15
15
  `.only`/`.skip`/`.each` variants): a test asserting that a guard REJECTS a
16
16
  `javascript:` URL — e.g. `expect(openBrowser("javascript:...")).toBe(false)`
17
17
  — is the adversarial input the code is meant to reject, not a real sink.
18
+
19
+ Also excludes literals used as the needle in a defensive string check —
20
+ `url.startsWith("javascript:")`, `.endsWith(...)`, `.includes(...)`,
21
+ `.indexOf(...)`, `.search(...)`, `.match(...)` — or as one side of an
22
+ equality/inequality comparison (`url === "javascript:..."`). These are the
23
+ code detecting/rejecting a javascript: URL, not introducing one (refs
24
+ #533). Deliberately NOT excluded: `.replace(...)`/`.replaceAll(...)`,
25
+ since the literal there could be the replacement (second) argument —
26
+ i.e. the malicious payload being substituted IN — and excluding the
27
+ whole call would hide that true positive.
28
+
29
+ IMPORTANT: unlike the expect/it/test/describe exclusion above, these two
30
+ new exclusions deliberately do NOT use `stopBy: end`. `inside` without
31
+ `stopBy` only checks the immediate parent, so the literal must be a
32
+ DIRECT argument/operand of the defensive call/comparison — not merely
33
+ somewhere in its subtree. Without this constraint, a real sink smuggled
34
+ inside the call/comparison would go unflagged, e.g.
35
+ `candidates.includes(link.href = "javascript:alert(1)")` (assignment
36
+ nested in `.includes()`'s argument), `arr.includes((a.href =
37
+ "javascript:...", true))` (comma operator), or `(a.href =
38
+ "javascript:...") === expected` (assignment nested in a `===` operand) —
39
+ in all three the literal's immediate parent is the assignment
40
+ expression, not the `arguments`/`binary_expression` node, so it stays
41
+ flagged.
18
42
  rule:
19
43
  kind: string
20
44
  regex: '^"javascript:'
21
45
  not:
22
- inside:
23
- stopBy: end
24
- kind: call_expression
25
- has:
26
- field: function
27
- regex: "^(expect|it|test|describe)(\\.\\w+)?$"
46
+ any:
47
+ - inside:
48
+ stopBy: end
49
+ kind: call_expression
50
+ has:
51
+ field: function
52
+ regex: "^(expect|it|test|describe)(\\.\\w+)?$"
53
+ - inside:
54
+ kind: arguments
55
+ inside:
56
+ kind: call_expression
57
+ has:
58
+ field: function
59
+ regex: "\\.(startsWith|endsWith|includes|indexOf|search|match)$"
60
+ - inside:
61
+ kind: binary_expression
62
+ has:
63
+ regex: "^(===|!==|==|!=)$"
@@ -5,6 +5,19 @@ severity: warning
5
5
  note: |
6
6
  == performs type coercion which leads to unexpected comparisons.
7
7
  Use === for strict equality checks.
8
+ EXCEPT `$X == null` / `$X == undefined` (and the reversed operand order):
9
+ `== null` is the canonical JS/TS idiom for "is null or undefined" —
10
+ rewriting it to `===` changes behavior by dropping the other nullish
11
+ case, which is a real bug, not a style fix (#966).
8
12
  rule:
9
- pattern: $X == $Y
13
+ all:
14
+ - pattern: $X == $Y
15
+ - not:
16
+ any:
17
+ - has:
18
+ field: right
19
+ regex: "^(null|undefined)$"
20
+ - has:
21
+ field: left
22
+ regex: "^(null|undefined)$"
10
23
  fix: $X === $Y
@@ -5,6 +5,19 @@ severity: warning
5
5
  note: |
6
6
  == performs type coercion which leads to unexpected comparisons.
7
7
  Use === for strict equality checks.
8
+ EXCEPT `$X == null` / `$X == undefined` (and the reversed operand order):
9
+ `== null` is the canonical JS/TS idiom for "is null or undefined" —
10
+ rewriting it to `===` changes behavior by dropping the other nullish
11
+ case, which is a real bug, not a style fix (#966).
8
12
  rule:
9
- pattern: $X == $Y
13
+ all:
14
+ - pattern: $X == $Y
15
+ - not:
16
+ any:
17
+ - has:
18
+ field: right
19
+ regex: "^(null|undefined)$"
20
+ - has:
21
+ field: left
22
+ regex: "^(null|undefined)$"
10
23
  fix: $X === $Y
@@ -5,6 +5,19 @@ severity: warning
5
5
  note: |
6
6
  != performs type coercion which leads to unexpected comparisons.
7
7
  Use !== for strict inequality checks.
8
+ EXCEPT `$X != null` / `$X != undefined` (and the reversed operand order):
9
+ `!= null` is the canonical JS/TS idiom for "is not null or undefined" —
10
+ rewriting it to `!==` changes behavior by dropping the other nullish
11
+ case, which is a real bug, not a style fix (#966).
8
12
  rule:
9
- pattern: $X != $Y
13
+ all:
14
+ - pattern: $X != $Y
15
+ - not:
16
+ any:
17
+ - has:
18
+ field: right
19
+ regex: "^(null|undefined)$"
20
+ - has:
21
+ field: left
22
+ regex: "^(null|undefined)$"
10
23
  fix: $X !== $Y
@@ -5,6 +5,19 @@ severity: warning
5
5
  note: |
6
6
  != performs type coercion which leads to unexpected comparisons.
7
7
  Use !== for strict inequality checks.
8
+ EXCEPT `$X != null` / `$X != undefined` (and the reversed operand order):
9
+ `!= null` is the canonical JS/TS idiom for "is not null or undefined" —
10
+ rewriting it to `!==` changes behavior by dropping the other nullish
11
+ case, which is a real bug, not a style fix (#966).
8
12
  rule:
9
- pattern: $X != $Y
13
+ all:
14
+ - pattern: $X != $Y
15
+ - not:
16
+ any:
17
+ - has:
18
+ field: right
19
+ regex: "^(null|undefined)$"
20
+ - has:
21
+ field: left
22
+ regex: "^(null|undefined)$"
10
23
  fix: $X !== $Y
@@ -2,10 +2,10 @@
2
2
  # Detects memset used to clear sensitive data
3
3
  id: no-memset-sensitive-data
4
4
  name: memset Should Not Be Used to Delete Sensitive Data
5
- severity: error
5
+ severity: warning
6
6
  category: security
7
7
  defect_class: security
8
- inline_tier: blocking
8
+ inline_tier: warning
9
9
  language: cpp
10
10
 
11
11
  message: "memset should not be used to delete sensitive data — use SecureZeroMemory or explicit_bzero"
@@ -28,10 +28,16 @@ description: |
28
28
  query: |
29
29
  (call_expression
30
30
  function: (identifier) @FUNC (#eq? @FUNC "memset")
31
- arguments: (argument_list) @ARGS)
31
+ arguments: (argument_list
32
+ (_) @DEST
33
+ (_) @VALUE
34
+ (_) @SIZE) @ARGS)
32
35
 
33
36
  metavars:
34
37
  - FUNC
38
+ - DEST
39
+ - VALUE
40
+ - SIZE
35
41
  - ARGS
36
42
 
37
43
  post_filter: memset_for_sensitive_data
@@ -22,15 +22,15 @@ description: |
22
22
  ```
23
23
 
24
24
  query: |
25
- (declaration
26
- type: (template_type
27
- name: (type_identifier) @TYPE (#eq? @TYPE "scoped_lock"))
28
- declarator: (init_declarator
29
- initializer: (argument_list) @ARGS))
25
+ ((declaration
26
+ type: (qualified_identifier
27
+ name: (type_identifier) @TYPE)
28
+ declarator: (identifier) @DECL)
29
+ (#eq? @TYPE "scoped_lock"))
30
30
 
31
31
  metavars:
32
32
  - TYPE
33
- - ARGS
33
+ - DECL
34
34
 
35
35
  post_filter: scoped_lock_empty_args
36
36
 
@@ -21,15 +21,17 @@ description: |
21
21
  ```
22
22
 
23
23
  query: |
24
- (call_expression
25
- function: (function_name) @FUNC (#eq? @FUNC "calc")
26
- arguments: (arguments
27
- (binary_expression
28
- operator: ("+" | "-") @OP) @EXPR))
24
+ ((call_expression
25
+ (function_name) @FUNC
26
+ (arguments
27
+ (_) @LEFT
28
+ (_) @RIGHT) @EXPR)
29
+ (#eq? @FUNC "calc"))
29
30
 
30
31
  metavars:
31
32
  - FUNC
32
- - OP
33
+ - LEFT
34
+ - RIGHT
33
35
  - EXPR
34
36
 
35
37
  post_filter: calc_missing_spaces
@@ -6,33 +6,34 @@ defect_class: correctness
6
6
  inline_tier: blocking
7
7
  language: go
8
8
 
9
- message: "sync.Mutex copied by value — copy breaks the lock; use a pointer receiver or embed via pointer"
9
+ message: "sync.Mutex parameter taken by value — the callee locks a copy; take *sync.Mutex instead"
10
10
 
11
11
  description: |
12
12
  A sync.Mutex must never be copied after first use. Copying a mutex copies
13
13
  its internal state, so both copies appear unlocked even if the original
14
14
  was locked — leading to data races and deadlocks.
15
15
 
16
- This fires when a struct containing a Mutex is assigned by value or passed
17
- by value to a function.
16
+ This fires on a parameter declared as a bare `sync.Mutex`/`sync.RWMutex`
17
+ value: the call copies the lock, so the callee locks its own copy. Copies
18
+ through a struct that embeds a mutex (a value receiver, or a struct-typed
19
+ parameter) are NOT detected — that needs the struct definition, which this
20
+ single-file query cannot resolve.
18
21
 
19
- ✅ FIX: pass structs containing mutexes by pointer, or use *sync.Mutex.
22
+ ✅ FIX: take the mutex as *sync.Mutex, or reach it through a pointer receiver.
20
23
 
21
24
  ❌ NEVER:
22
- type S struct { mu sync.Mutex }
23
- func work(s S) { s.mu.Lock() } // copies the mutex!
25
+ func work(mu sync.Mutex) { mu.Lock() } // locks a copy!
24
26
 
25
27
  ✅ SAFE:
26
- func work(s *S) { s.mu.Lock() }
28
+ func work(mu *sync.Mutex) { mu.Lock() }
27
29
 
28
30
  query: |
29
- (short_var_declaration
30
- right: (call_expression
31
- function: (selector_expression
32
- operand: (identifier) @PKG
33
- field: (field_identifier) @FN)
34
- (#eq? @PKG "sync")
35
- (#match? @FN "^(Mutex|RWMutex)$"))) @DECL
31
+ (parameter_declaration
32
+ type: (qualified_type
33
+ package: (package_identifier) @PKG
34
+ name: (type_identifier) @FN)
35
+ (#eq? @PKG "sync")
36
+ (#match? @FN "^(Mutex|RWMutex)$")) @DECL
36
37
 
37
38
  metavars:
38
39
  - PKG
@@ -49,9 +50,11 @@ tags:
49
50
 
50
51
  examples:
51
52
  bad: |
52
- mu := sync.Mutex{} // value copy if passed to function
53
- doWork(mu) // race condition
53
+ func doWork(mu sync.Mutex) { // BAD - mu is a copy
54
+ mu.Lock()
55
+ }
54
56
 
55
57
  good: |
56
- mu := &sync.Mutex{}
57
- doWork(mu)
58
+ func doWork(mu *sync.Mutex) {
59
+ mu.Lock()
60
+ }
@@ -17,12 +17,12 @@ description: |
17
17
 
18
18
  query: |
19
19
  (go_statement
20
- expression: (call_expression
20
+ (call_expression
21
21
  function: (func_literal
22
22
  body: (block
23
23
  (assignment_statement
24
- left: (index_expression) @MAPWRITE
25
- right: (_) @VALUE)))
24
+ left: (expression_list (index_expression) @MAPWRITE)
25
+ right: (expression_list (_) @VALUE))))
26
26
  arguments: (argument_list) @ARGS))
27
27
 
28
28
  metavars:
@@ -25,11 +25,11 @@ description: |
25
25
 
26
26
  query: |
27
27
  (while_statement
28
- condition: (true) @COND
28
+ condition: (condition (true) @COND)
29
29
  body: (block) @BODY)
30
30
  (for_statement
31
- condition: (null)
32
- body: (block) @BODY)
31
+ !condition
32
+ (block) @BODY)
33
33
 
34
34
  metavars:
35
35
  - COND
@@ -28,10 +28,12 @@ description: |
28
28
  query: |
29
29
  (method_declaration
30
30
  (modifiers
31
- (annotation
32
- name: (identifier) @OVERRIDE (#eq? @OVERRIDE "Override")))
33
- name: (identifier) @METHOD (#match? @METHOD "^(setUp|tearDown|setUpBeforeClass|tearDownAfterClass)$")
34
- body: (block) @BODY)
31
+ (marker_annotation
32
+ name: (identifier) @OVERRIDE))
33
+ name: (identifier) @METHOD
34
+ body: (block) @BODY
35
+ (#eq? @OVERRIDE "Override")
36
+ (#match? @METHOD "^(setUp|tearDown|setUpBeforeClass|tearDownAfterClass)$"))
35
37
 
36
38
  metavars:
37
39
  - OVERRIDE
@@ -28,18 +28,20 @@ description: |
28
28
 
29
29
  query: |
30
30
  (if_statement
31
- condition: (binary_expression
32
- left: (identifier) @FIELD
33
- operator: ("==")
34
- right: ("null"))
31
+ condition: (condition
32
+ (binary_expression
33
+ left: (identifier) @FIELD
34
+ "=="
35
+ (null_literal) @NULL))
35
36
  consequence: (block
36
37
  (synchronized_statement
37
38
  body: (block
38
39
  (if_statement
39
- condition: (binary_expression
40
- left: (identifier) @FIELD2
41
- operator: ("==")
42
- right: ("null")))))))
40
+ condition: (condition
41
+ (binary_expression
42
+ left: (identifier) @FIELD2
43
+ "=="
44
+ (null_literal) @NULL2)))))))
43
45
 
44
46
  metavars:
45
47
  - FIELD
@@ -27,7 +27,7 @@ description: |
27
27
 
28
28
  query: |
29
29
  (class_declaration
30
- (extends_clause
30
+ superclass: (superclass
31
31
  (type_identifier) @PARENT)
32
32
  body: (class_body
33
33
  (field_declaration
@@ -26,15 +26,14 @@ query: |
26
26
  (method_invocation
27
27
  name: (identifier) @METHOD (#match? @METHOD "^(setString|setInt|setLong|setDouble|setBoolean|getString|getInt|getLong|getDouble|getBoolean)$")
28
28
  arguments: (argument_list
29
- (decimal_integer_literal) @INDEX) @ARGS)
29
+ (decimal_integer_literal) @INDEX
30
+ (#match? @INDEX "^0+$")) @ARGS)
30
31
 
31
32
  metavars:
32
33
  - METHOD
33
34
  - INDEX
34
35
  - ARGS
35
36
 
36
- post_filter: invalid_statement_index
37
-
38
37
  tags:
39
38
  - reliability
40
39
  - java
@@ -2,10 +2,10 @@
2
2
  # Detects resources that should be closed (pre-Java 7 style)
3
3
  id: resources-closed
4
4
  name: Resources Should Be Closed
5
- severity: error
5
+ severity: warning
6
6
  category: reliability
7
7
  defect_class: correctness
8
- inline_tier: blocking
8
+ inline_tier: warning
9
9
  language: java
10
10
 
11
11
  message: "Resource '{{RESOURCE}}' should be closed in finally block"
@@ -30,9 +30,12 @@ description: |
30
30
  query: |
31
31
  (class_declaration
32
32
  (modifiers
33
- (annotation
34
- name: (identifier) @ANNOT (#match? @ANNOT "^(SpringBootApplication|ComponentScan)$")))
35
- name: (_) @CLASS)
33
+ [(marker_annotation
34
+ name: (identifier) @ANNOT)
35
+ (annotation
36
+ name: (identifier) @ANNOT)])
37
+ name: (_) @CLASS
38
+ (#match? @ANNOT "^(SpringBootApplication|ComponentScan)$"))
36
39
 
37
40
  metavars:
38
41
  - ANNOT
@@ -29,11 +29,13 @@ description: |
29
29
  ```
30
30
 
31
31
  query: |
32
- (switch_statement
32
+ (switch_expression
33
33
  body: (switch_block
34
- (switch_label) @LABEL
35
- (expression_statement)*
36
- (switch_label) @NEXT_LABEL))
34
+ (switch_block_statement_group
35
+ (switch_label) @LABEL
36
+ (expression_statement)+)
37
+ (switch_block_statement_group
38
+ (switch_label) @NEXT_LABEL)))
37
39
 
38
40
  metavars:
39
41
  - LABEL
@@ -27,10 +27,11 @@ description: |
27
27
  ```
28
28
 
29
29
  query: |
30
- (switch_statement
30
+ (switch_expression
31
31
  body: (switch_block
32
- (labeled_statement
33
- (identifier) @LABEL) @LABELED_STMT))
32
+ (switch_block_statement_group
33
+ (labeled_statement
34
+ (identifier) @LABEL) @LABELED_STMT)))
34
35
 
35
36
  metavars:
36
37
  - LABEL
@@ -2,10 +2,10 @@
2
2
  # Detects JUnit tests without assertions
3
3
  id: tests-include-assertions
4
4
  name: Tests Should Include Assertions
5
- severity: error
5
+ severity: warning
6
6
  category: maintainability
7
7
  defect_class: correctness
8
- inline_tier: blocking
8
+ inline_tier: warning
9
9
  language: java
10
10
 
11
11
  message: "Test method should include at least one assertion"
@@ -26,10 +26,11 @@ description: |
26
26
  query: |
27
27
  (method_declaration
28
28
  (modifiers
29
- (annotation
30
- name: (identifier) @TEST (#match? @TEST "^(Test|ParameterizedTest|RepeatedTest)$")))
29
+ (marker_annotation
30
+ name: (identifier) @TEST))
31
31
  name: (identifier) @NAME
32
- body: (block) @BODY)
32
+ body: (block) @BODY
33
+ (#match? @TEST "^(Test|ParameterizedTest|RepeatedTest)$"))
33
34
 
34
35
  metavars:
35
36
  - TEST
@@ -26,16 +26,13 @@ description: |
26
26
  ```
27
27
 
28
28
  query: |
29
- (switch_statement
30
- body: (switch_body
31
- (switch_case
32
- consequence: (statement_block
33
- (expression_statement) @LAST))
34
- (switch_case) @NEXT))
29
+ (switch_body
30
+ (switch_case) @CASE
31
+ .
32
+ [(switch_case) (switch_default)])
35
33
 
36
34
  metavars:
37
- - LAST
38
- - NEXT
35
+ - CASE
39
36
 
40
37
  post_filter: no_terminating_statement
41
38
 
@@ -19,8 +19,9 @@ description: |
19
19
  query: |
20
20
  (switch_statement
21
21
  body: (switch_body
22
- (labeled_statement
23
- (statement_identifier) @LABEL) @LABELED))
22
+ (switch_case
23
+ (labeled_statement
24
+ (statement_identifier) @LABEL) @LABELED)))
24
25
 
25
26
  metavars:
26
27
  - LABEL
@@ -21,17 +21,21 @@ description: |
21
21
 
22
22
  query: |
23
23
  (call_expression
24
- (simple_identifier) @METHOD (#match? @METHOD "^(setString|setInt|setLong|getString|getInt|getLong)$")
25
- (value_arguments
26
- (integer_literal) @INDEX) @ARGS)
24
+ (navigation_expression
25
+ (simple_identifier)
26
+ (navigation_suffix
27
+ (simple_identifier) @METHOD))
28
+ (call_suffix
29
+ (value_arguments
30
+ (value_argument (integer_literal) @INDEX) @ARGS))
31
+ (#match? @METHOD "^(setString|setInt|setLong|getString|getInt|getLong)$")
32
+ (#eq? @INDEX "0"))
27
33
 
28
34
  metavars:
29
35
  - METHOD
30
36
  - INDEX
31
37
  - ARGS
32
38
 
33
- post_filter: invalid_jdbc_index
34
-
35
39
  tags:
36
40
  - reliability
37
41
  - kotlin
@@ -33,15 +33,15 @@ description: |
33
33
 
34
34
  query: |
35
35
  (method_declaration
36
- (modifiers
37
- "static")
36
+ (static_modifier)
38
37
  body: (compound_statement
39
- ((variable_name) @THIS
40
- (#eq? @THIS "$this"))))
38
+ (return_statement
39
+ (member_access_expression
40
+ object: ((variable_name) @THIS
41
+ (#eq? @THIS "$this"))))) )
41
42
 
42
43
  metavars:
43
44
  - THIS
44
- - VAR
45
45
 
46
46
  tags:
47
47
  - reliability
@@ -28,18 +28,11 @@ description: |
28
28
  query: |
29
29
  (function_definition
30
30
  name: (identifier) @NAME (#eq? @NAME "__exit__")
31
- parameters: (parameters
32
- (_) @SELF
33
- . (_) @PARAM1?
34
- . (_) @PARAM2?
35
- . (_) @PARAM3?))
31
+ parameters: (parameters) @PARAMS)
36
32
 
37
33
  metavars:
38
34
  - NAME
39
- - SELF
40
- - PARAM1
41
- - PARAM2
42
- - PARAM3
35
+ - PARAMS
43
36
 
44
37
  post_filter: exit_params_insufficient
45
38
 
@@ -25,12 +25,11 @@ query: |
25
25
  (comparison_operator
26
26
  (identifier) @OBJ
27
27
  "in"
28
- (identifier) @TARGET)
28
+ (_) @TARGET)
29
29
  (comparison_operator
30
30
  (identifier) @OBJ
31
- "not"
32
- "in"
33
- (identifier) @TARGET)
31
+ "not in"
32
+ (_) @TARGET)
34
33
 
35
34
  metavars:
36
35
  - OBJ
@@ -17,19 +17,15 @@ description: |
17
17
  ✅ FIX: Use composition or avoid TorchScript for this class
18
18
 
19
19
  query: |
20
- (function_definition
21
- (decorator
22
- (call
23
- function: (identifier) @DEC (#match? @DEC "^(torch\.jit\.script|jit\.script)$")))
24
- body: (block
25
- (call
26
- function: (identifier) @FUNC (#eq? @FUNC "super")) @CALL))
20
+ (call
21
+ function: (identifier) @FUNC (#eq? @FUNC "super")) @CALL
27
22
 
28
23
  metavars:
29
- - DEC
30
24
  - FUNC
31
25
  - CALL
32
26
 
27
+ post_filter: torchscript_super_call
28
+
33
29
  tags:
34
30
  - reliability
35
31
  - python
@@ -28,13 +28,9 @@ query: |
28
28
  condition: (identifier) @COND (#eq? @COND "NotImplemented"))
29
29
  (while_statement
30
30
  condition: (identifier) @COND (#eq? @COND "NotImplemented"))
31
- (binary_operator
32
- (identifier) @COND (#eq? @COND "NotImplemented")
33
- ("and" | "or"))
34
31
  (boolean_operator
35
32
  (identifier) @COND (#eq? @COND "NotImplemented"))
36
- (unary_operator
37
- operator: ("not")
33
+ (not_operator
38
34
  argument: (identifier) @COND (#eq? @COND "NotImplemented"))
39
35
 
40
36
  metavars: