pi-lens 3.8.38 → 3.8.39
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.
- package/CHANGELOG.md +10 -0
- package/README.md +1 -1
- package/clients/cache-manager.ts +4 -1
- package/clients/dispatch/fact-scheduler.ts +2 -1
- package/clients/dispatch/fact-store.ts +4 -6
- package/clients/dispatch/integration.ts +2 -5
- package/clients/dispatch/rules/quality-rules.ts +10 -15
- package/clients/dispatch/runners/biome-check.ts +1 -1
- package/clients/dispatch/runners/eslint.ts +1 -1
- package/clients/dispatch/runners/lsp.ts +1 -5
- package/clients/dispatch/runners/psscriptanalyzer.ts +1 -1
- package/clients/dispatch/runners/similarity.ts +1 -4
- package/clients/dispatch/utils/lsp-diagnostics.ts +3 -9
- package/clients/formatters.ts +12 -7
- package/clients/lsp/index.ts +8 -10
- package/clients/lsp/launch.ts +5 -8
- package/clients/lsp/server.ts +1 -1
- package/clients/pipeline.ts +6 -11
- package/clients/read-guard.ts +5 -6
- package/clients/runtime-coordinator.ts +2 -2
- package/clients/runtime-tool-result.ts +1 -3
- package/clients/secrets-scanner.ts +1 -1
- package/clients/session-summary.ts +1 -1
- package/clients/tree-sitter-query-loader.ts +3 -2
- package/commands/booboo.ts +15 -14
- package/index.ts +5 -5
- package/package.json +1 -1
- package/rules/rule-catalog.json +52 -1
- package/rules/tree-sitter-queries/abap/delete-where.yml +46 -0
- package/rules/tree-sitter-queries/c/case-range-multiple-values.yml +65 -0
- package/rules/tree-sitter-queries/c/goto-into-block.yml +72 -0
- package/rules/tree-sitter-queries/c/goto-label-order.yml +65 -0
- package/rules/tree-sitter-queries/cobol/alter-statement.yml +39 -0
- package/rules/tree-sitter-queries/cpp/no-auto-ptr.yml +49 -0
- package/rules/tree-sitter-queries/cpp/no-confused-move-forward.yml +59 -0
- package/rules/tree-sitter-queries/cpp/no-memset-sensitive-data.yml +57 -0
- package/rules/tree-sitter-queries/cpp/no-scoped-lock-without-args.yml +52 -0
- package/rules/tree-sitter-queries/cpp/noexcept-functions.yml +58 -0
- package/rules/tree-sitter-queries/csharp/async-await-identifiers.yml +50 -0
- package/rules/tree-sitter-queries/csharp/is-with-this.yml +52 -0
- package/rules/tree-sitter-queries/csharp/no-dangerous-get-handle.yml +59 -0
- package/rules/tree-sitter-queries/csharp/no-operator-eq-reference.yml +60 -0
- package/rules/tree-sitter-queries/csharp/no-thread-resume-suspend.yml +60 -0
- package/rules/tree-sitter-queries/css/calc-spacing.yml +50 -0
- package/rules/tree-sitter-queries/java/junit-call-super.yml +63 -0
- package/rules/tree-sitter-queries/java/main-should-not-throw.yml +63 -0
- package/rules/tree-sitter-queries/java/no-clone-override.yml +60 -0
- package/rules/tree-sitter-queries/java/no-double-checked-locking.yml +74 -0
- package/rules/tree-sitter-queries/java/no-exit-methods.yml +50 -0
- package/rules/tree-sitter-queries/java/no-field-shadowing.yml +66 -0
- package/rules/tree-sitter-queries/java/no-future-keywords.yml +49 -0
- package/rules/tree-sitter-queries/java/no-threadgroup.yml +52 -0
- package/rules/tree-sitter-queries/java/no-threads-in-constructors.yml +73 -0
- package/rules/tree-sitter-queries/java/no-wait-notify-on-thread.yml +58 -0
- package/rules/tree-sitter-queries/java/prepared-statement-valid-indices.yml +55 -0
- package/rules/tree-sitter-queries/java/spring-session-attributes-setcomplete.yml +75 -0
- package/rules/tree-sitter-queries/java/springboot-default-package.yml +69 -0
- package/rules/tree-sitter-queries/java/switch-fall-through.yml +70 -0
- package/rules/tree-sitter-queries/java/switch-non-case-labels.yml +62 -0
- package/rules/tree-sitter-queries/javascript/switch-non-case-labels.yml +52 -0
- package/rules/tree-sitter-queries/kotlin/prepared-statement-indices.yml +49 -0
- package/rules/tree-sitter-queries/php/no-exit-die.yml +52 -0
- package/rules/tree-sitter-queries/php/this-in-static-context.yml +75 -0
- package/rules/tree-sitter-queries/plsql/delete-update-where.yml +56 -0
- package/rules/tree-sitter-queries/plsql/end-loop-semicolon.yml +51 -0
- package/rules/tree-sitter-queries/plsql/fetch-bulk-collect-limit.yml +47 -0
- package/rules/tree-sitter-queries/plsql/forallsave-exceptions.yml +51 -0
- package/rules/tree-sitter-queries/plsql/no-synchronize.yml +47 -0
- package/rules/tree-sitter-queries/plsql/not-null-initialization.yml +59 -0
- package/rules/tree-sitter-queries/plsql/raise-application-error-codes.yml +50 -0
- package/rules/tree-sitter-queries/python/exit-signature-check.yml +66 -0
- package/rules/tree-sitter-queries/python/in-operator-unsupported.yml +57 -0
- package/rules/tree-sitter-queries/python/iter-return-iterator.yml +59 -0
- package/rules/tree-sitter-queries/python/notimplemented-boolean-context.yml +67 -0
- package/rules/tree-sitter-queries/python/return-in-generator.yml +58 -0
- package/rules/tree-sitter-queries/python/return-in-init.yml +59 -0
- package/rules/tree-sitter-queries/python/send-file-mimetype.yml +53 -0
- package/rules/tree-sitter-queries/python/yield-return-outside-function.yml +57 -0
- package/tools/lsp-navigation.js +14 -16
- package/tools/lsp-navigation.ts +14 -18
package/rules/rule-catalog.json
CHANGED
|
@@ -59,6 +59,57 @@
|
|
|
59
59
|
{ "rule_id": "missed-concurrency", "engine": "ast-grep", "language": "typescript", "family": "concurrency", "scope": "function", "canonical_concept": "sequential-awaits-parallelizable", "severity_default": "warning", "confidence": "medium", "status": "active" },
|
|
60
60
|
{ "rule_id": "missed-concurrency-js", "engine": "ast-grep", "language": "javascript", "family": "concurrency", "scope": "function", "canonical_concept": "sequential-awaits-parallelizable", "severity_default": "warning", "confidence": "medium", "status": "active" },
|
|
61
61
|
{ "rule_id": "no-await-in-loop", "engine": "ast-grep", "language": "typescript", "family": "concurrency", "scope": "function", "canonical_concept": "await-inside-loop", "severity_default": "warning", "confidence": "medium", "status": "active" },
|
|
62
|
-
{ "rule_id": "no-await-in-loop-js", "engine": "ast-grep", "language": "javascript", "family": "concurrency", "scope": "function", "canonical_concept": "await-inside-loop", "severity_default": "warning", "confidence": "medium", "status": "active" }
|
|
62
|
+
{ "rule_id": "no-await-in-loop-js", "engine": "ast-grep", "language": "javascript", "family": "concurrency", "scope": "function", "canonical_concept": "await-inside-loop", "severity_default": "warning", "confidence": "medium", "status": "active" },
|
|
63
|
+
|
|
64
|
+
{ "rule_id": "return-in-init", "engine": "tree-sitter", "language": "python", "family": "reliability", "scope": "function", "canonical_concept": "return-in-init", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
65
|
+
{ "rule_id": "yield-return-outside-function", "engine": "tree-sitter", "language": "python", "family": "reliability", "scope": "file", "canonical_concept": "invalid-statement-context", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
66
|
+
{ "rule_id": "notimplemented-boolean-context", "engine": "tree-sitter", "language": "python", "family": "reliability", "scope": "function", "canonical_concept": "deprecated-boolean-usage", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
67
|
+
{ "rule_id": "exit-signature-check", "engine": "tree-sitter", "language": "python", "family": "reliability", "scope": "function", "canonical_concept": "context-manager-signature", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
68
|
+
{ "rule_id": "return-in-generator", "engine": "tree-sitter", "language": "python", "family": "reliability", "scope": "function", "canonical_concept": "return-in-generator", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
69
|
+
{ "rule_id": "iter-return-iterator", "engine": "tree-sitter", "language": "python", "family": "reliability", "scope": "function", "canonical_concept": "iter-protocol-violation", "severity_default": "warning", "confidence": "medium", "status": "active" },
|
|
70
|
+
{ "rule_id": "switch-non-case-labels", "engine": "tree-sitter", "language": "java", "family": "reliability", "scope": "function", "canonical_concept": "switch-label-violation", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
71
|
+
{ "rule_id": "no-clone-override", "engine": "tree-sitter", "language": "java", "family": "maintainability", "scope": "class", "canonical_concept": "clone-override", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
72
|
+
{ "rule_id": "main-should-not-throw", "engine": "tree-sitter", "language": "java", "family": "maintainability", "scope": "function", "canonical_concept": "main-throws-exception", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
73
|
+
{ "rule_id": "no-threadgroup", "engine": "tree-sitter", "language": "java", "family": "security", "scope": "file", "canonical_concept": "deprecated-api-usage", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
74
|
+
{ "rule_id": "this-in-static-context", "engine": "tree-sitter", "language": "php", "family": "reliability", "scope": "function", "canonical_concept": "this-in-static-context", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
75
|
+
{ "rule_id": "no-exit-die", "engine": "tree-sitter", "language": "php", "family": "reliability", "scope": "function", "canonical_concept": "abrupt-termination", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
76
|
+
{ "rule_id": "case-range-multiple-values", "engine": "tree-sitter", "language": "c", "family": "maintainability", "scope": "function", "canonical_concept": "case-range-single-value", "severity_default": "warning", "confidence": "medium", "status": "active" },
|
|
77
|
+
{ "rule_id": "goto-label-order", "engine": "tree-sitter", "language": "c", "family": "maintainability", "scope": "function", "canonical_concept": "backward-goto", "severity_default": "warning", "confidence": "medium", "status": "active" },
|
|
78
|
+
{ "rule_id": "goto-into-block", "engine": "tree-sitter", "language": "c", "family": "maintainability", "scope": "function", "canonical_concept": "goto-into-block", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
79
|
+
{ "rule_id": "no-auto-ptr", "engine": "tree-sitter", "language": "cpp", "family": "reliability", "scope": "file", "canonical_concept": "deprecated-auto-ptr", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
80
|
+
{ "rule_id": "no-memset-sensitive-data", "engine": "tree-sitter", "language": "cpp", "family": "security", "scope": "function", "canonical_concept": "insecure-memory-clear", "severity_default": "error", "confidence": "medium", "status": "active" },
|
|
81
|
+
{ "rule_id": "no-scoped-lock-without-args", "engine": "tree-sitter", "language": "cpp", "family": "reliability", "scope": "function", "canonical_concept": "scoped-lock-no-mutex", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
82
|
+
{ "rule_id": "no-confused-move-forward", "engine": "tree-sitter", "language": "cpp", "family": "reliability", "scope": "function", "canonical_concept": "move-forward-confusion", "severity_default": "error", "confidence": "medium", "status": "active" },
|
|
83
|
+
{ "rule_id": "is-with-this", "engine": "tree-sitter", "language": "csharp", "family": "maintainability", "scope": "function", "canonical_concept": "is-operator-with-this", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
84
|
+
{ "rule_id": "no-operator-eq-reference", "engine": "tree-sitter", "language": "csharp", "family": "maintainability", "scope": "class", "canonical_concept": "operator-eq-reference-type", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
85
|
+
{ "rule_id": "no-dangerous-get-handle", "engine": "tree-sitter", "language": "csharp", "family": "reliability", "scope": "function", "canonical_concept": "unsafe-handle-access", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
86
|
+
{ "rule_id": "no-thread-resume-suspend", "engine": "tree-sitter", "language": "csharp", "family": "reliability", "scope": "function", "canonical_concept": "deprecated-thread-api", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
87
|
+
{ "rule_id": "async-await-identifiers", "engine": "tree-sitter", "language": "csharp", "family": "maintainability", "scope": "file", "canonical_concept": "keyword-as-identifier", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
88
|
+
{ "rule_id": "in-operator-unsupported", "engine": "tree-sitter", "language": "python", "family": "reliability", "scope": "function", "canonical_concept": "in-operator-unsupported", "severity_default": "warning", "confidence": "medium", "status": "active" },
|
|
89
|
+
{ "rule_id": "spring-session-attributes-setcomplete", "engine": "tree-sitter", "language": "java", "family": "reliability", "scope": "class", "canonical_concept": "session-attributes-cleanup", "severity_default": "error", "confidence": "medium", "status": "active" },
|
|
90
|
+
{ "rule_id": "springboot-default-package", "engine": "tree-sitter", "language": "java", "family": "reliability", "scope": "file", "canonical_concept": "default-package-usage", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
91
|
+
{ "rule_id": "prepared-statement-valid-indices", "engine": "tree-sitter", "language": "java", "family": "reliability", "scope": "function", "canonical_concept": "jdbc-invalid-index", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
92
|
+
{ "rule_id": "delete-update-where", "engine": "tree-sitter", "language": "plsql", "family": "reliability", "scope": "function", "canonical_concept": "sql-missing-where", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
93
|
+
{ "rule_id": "fetch-bulk-collect-limit", "engine": "tree-sitter", "language": "plsql", "family": "reliability", "scope": "function", "canonical_concept": "fetch-no-limit", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
94
|
+
{ "rule_id": "prepared-statement-indices", "engine": "tree-sitter", "language": "kotlin", "family": "reliability", "scope": "function", "canonical_concept": "jdbc-invalid-index", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
95
|
+
{ "rule_id": "delete-where", "engine": "tree-sitter", "language": "abap", "family": "reliability", "scope": "function", "canonical_concept": "sql-missing-where", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
96
|
+
{ "rule_id": "alter-statement", "engine": "tree-sitter", "language": "cobol", "family": "maintainability", "scope": "file", "canonical_concept": "alter-statement-usage", "severity_default": "warning", "confidence": "high", "status": "active" },
|
|
97
|
+
{ "rule_id": "calc-spacing", "engine": "tree-sitter", "language": "css", "family": "reliability", "scope": "file", "canonical_concept": "calc-spacing-error", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
98
|
+
{ "rule_id": "switch-non-case-labels-js", "engine": "tree-sitter", "language": "javascript", "family": "reliability", "scope": "function", "canonical_concept": "switch-label-violation", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
99
|
+
{ "rule_id": "no-exit-methods", "engine": "tree-sitter", "language": "java", "family": "maintainability", "scope": "function", "canonical_concept": "abrupt-termination", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
100
|
+
{ "rule_id": "no-threads-in-constructors", "engine": "tree-sitter", "language": "java", "family": "maintainability", "scope": "constructor", "canonical_concept": "thread-in-constructor", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
101
|
+
{ "rule_id": "switch-fall-through", "engine": "tree-sitter", "language": "java", "family": "maintainability", "scope": "function", "canonical_concept": "switch-fall-through", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
102
|
+
{ "rule_id": "no-wait-notify-on-thread", "engine": "tree-sitter", "language": "java", "family": "reliability", "scope": "function", "canonical_concept": "wait-on-thread-instance", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
103
|
+
{ "rule_id": "no-double-checked-locking", "engine": "tree-sitter", "language": "java", "family": "reliability", "scope": "function", "canonical_concept": "double-checked-locking", "severity_default": "error", "confidence": "medium", "status": "active" },
|
|
104
|
+
{ "rule_id": "no-future-keywords", "engine": "tree-sitter", "language": "java", "family": "maintainability", "scope": "file", "canonical_concept": "future-keyword-usage", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
105
|
+
{ "rule_id": "no-field-shadowing", "engine": "tree-sitter", "language": "java", "family": "maintainability", "scope": "class", "canonical_concept": "field-shadowing", "severity_default": "error", "confidence": "medium", "status": "active" },
|
|
106
|
+
{ "rule_id": "junit-call-super", "engine": "tree-sitter", "language": "java", "family": "maintainability", "scope": "function", "canonical_concept": "missing-super-call", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
107
|
+
{ "rule_id": "forallsave-exceptions", "engine": "tree-sitter", "language": "plsql", "family": "reliability", "scope": "function", "canonical_concept": "forall-no-save-exceptions", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
108
|
+
{ "rule_id": "not-null-initialization", "engine": "tree-sitter", "language": "plsql", "family": "reliability", "scope": "function", "canonical_concept": "not-null-uninitialized", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
109
|
+
{ "rule_id": "end-loop-semicolon", "engine": "tree-sitter", "language": "plsql", "family": "reliability", "scope": "function", "canonical_concept": "missing-semicolon", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
110
|
+
{ "rule_id": "raise-application-error-codes", "engine": "tree-sitter", "language": "plsql", "family": "reliability", "scope": "function", "canonical_concept": "invalid-error-code", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
111
|
+
{ "rule_id": "no-synchronize", "engine": "tree-sitter", "language": "plsql", "family": "reliability", "scope": "function", "canonical_concept": "synchronize-usage", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
112
|
+
{ "rule_id": "send-file-mimetype", "engine": "tree-sitter", "language": "python", "family": "reliability", "scope": "function", "canonical_concept": "send-file-missing-mimetype", "severity_default": "error", "confidence": "high", "status": "active" },
|
|
113
|
+
{ "rule_id": "noexcept-functions", "engine": "tree-sitter", "language": "cpp", "family": "reliability", "scope": "function", "canonical_concept": "missing-noexcept", "severity_default": "error", "confidence": "medium", "status": "active" }
|
|
63
114
|
]
|
|
64
115
|
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# ABAP DELETE Without WHERE
|
|
2
|
+
# Detects DELETE statements without WHERE in ABAP
|
|
3
|
+
id: delete-where
|
|
4
|
+
name: DELETE FROM Should Have WHERE Clause
|
|
5
|
+
severity: error
|
|
6
|
+
category: reliability
|
|
7
|
+
defect_class: correctness
|
|
8
|
+
inline_tier: blocking
|
|
9
|
+
language: abap
|
|
10
|
+
|
|
11
|
+
message: "DELETE FROM statement should have a WHERE clause"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
DELETE FROM without WHERE deletes ALL rows. Almost always a bug.
|
|
15
|
+
|
|
16
|
+
✅ FIX: Add WHERE clause
|
|
17
|
+
|
|
18
|
+
```abap
|
|
19
|
+
DELETE FROM employees WHERE id = lv_id. " GOOD
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
query: |
|
|
23
|
+
(delete_statement
|
|
24
|
+
(delete) @DELETE
|
|
25
|
+
(from_clause)
|
|
26
|
+
(where_clause)? @WHERE)
|
|
27
|
+
|
|
28
|
+
metavars:
|
|
29
|
+
- DELETE
|
|
30
|
+
- WHERE
|
|
31
|
+
|
|
32
|
+
post_filter: missing_where
|
|
33
|
+
|
|
34
|
+
tags:
|
|
35
|
+
- reliability
|
|
36
|
+
- abap
|
|
37
|
+
- data-loss
|
|
38
|
+
|
|
39
|
+
examples:
|
|
40
|
+
bad: |
|
|
41
|
+
DELETE FROM employees. " BAD
|
|
42
|
+
|
|
43
|
+
good: |
|
|
44
|
+
DELETE FROM employees WHERE id = 123. " GOOD
|
|
45
|
+
|
|
46
|
+
has_fix: false
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Case Ranges Should Cover Multiple Values
|
|
2
|
+
# Detects case statements with ranges that only cover single values
|
|
3
|
+
id: case-range-multiple-values
|
|
4
|
+
name: Case Ranges Should Cover Multiple Values
|
|
5
|
+
severity: warning
|
|
6
|
+
category: maintainability
|
|
7
|
+
defect_class: correctness
|
|
8
|
+
inline_tier: warning
|
|
9
|
+
language: c
|
|
10
|
+
|
|
11
|
+
message: "Case range should cover multiple values"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
GCC case ranges (case 1..5:) should cover multiple values.
|
|
15
|
+
Using ranges for single values is confusing and unnecessary.
|
|
16
|
+
|
|
17
|
+
✅ FIX: Use regular case for single values, ranges for multiple
|
|
18
|
+
|
|
19
|
+
```c
|
|
20
|
+
switch (value) {
|
|
21
|
+
case 1: // Single value - use regular case
|
|
22
|
+
break;
|
|
23
|
+
case 10..20: // Range - multiple values
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
query: |
|
|
29
|
+
(switch_statement
|
|
30
|
+
body: (compound_statement
|
|
31
|
+
(case_statement
|
|
32
|
+
value: (range_expression
|
|
33
|
+
(number_literal) @START
|
|
34
|
+
(number_literal) @END) @RANGE)))
|
|
35
|
+
|
|
36
|
+
metavars:
|
|
37
|
+
- START
|
|
38
|
+
- END
|
|
39
|
+
- RANGE
|
|
40
|
+
|
|
41
|
+
post_filter: case_range_single_value
|
|
42
|
+
|
|
43
|
+
tags:
|
|
44
|
+
- maintainability
|
|
45
|
+
- c
|
|
46
|
+
- gnu
|
|
47
|
+
- switch
|
|
48
|
+
|
|
49
|
+
examples:
|
|
50
|
+
bad: |
|
|
51
|
+
switch (val) {
|
|
52
|
+
case 5..5: // BAD - range with single value
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
good: |
|
|
57
|
+
switch (val) {
|
|
58
|
+
case 5: // GOOD - single value
|
|
59
|
+
break;
|
|
60
|
+
case 10..20: // GOOD - actual range
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
has_fix: true
|
|
65
|
+
fix_action: simplify_single_case_range
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Goto Into Block
|
|
2
|
+
# Detects goto statements that jump into blocks
|
|
3
|
+
id: goto-into-block
|
|
4
|
+
name: Goto Should Not Jump Into Blocks
|
|
5
|
+
severity: warning
|
|
6
|
+
category: maintainability
|
|
7
|
+
defect_class: correctness
|
|
8
|
+
inline_tier: blocking
|
|
9
|
+
language: c
|
|
10
|
+
|
|
11
|
+
message: "goto statements should not be used to jump into blocks"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
Jumping into a block bypasses variable initialization and
|
|
15
|
+
is undefined behavior. This is a MISRA C requirement.
|
|
16
|
+
|
|
17
|
+
✅ FIX: Jump to the block's beginning or restructure code
|
|
18
|
+
|
|
19
|
+
```c
|
|
20
|
+
void process() {
|
|
21
|
+
if (error) {
|
|
22
|
+
goto cleanup;
|
|
23
|
+
}
|
|
24
|
+
// ... code ...
|
|
25
|
+
cleanup:
|
|
26
|
+
{ // Jump to block start
|
|
27
|
+
free_resources();
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
query: |
|
|
33
|
+
(function_definition
|
|
34
|
+
body: (compound_statement
|
|
35
|
+
(goto_statement
|
|
36
|
+
(statement_identifier) @TARGET) @GOTO))
|
|
37
|
+
|
|
38
|
+
metavars:
|
|
39
|
+
- TARGET
|
|
40
|
+
- GOTO
|
|
41
|
+
|
|
42
|
+
post_filter: goto_targets_inner_block
|
|
43
|
+
|
|
44
|
+
tags:
|
|
45
|
+
- maintainability
|
|
46
|
+
- c
|
|
47
|
+
- misra
|
|
48
|
+
- undefined-behavior
|
|
49
|
+
|
|
50
|
+
examples:
|
|
51
|
+
bad: |
|
|
52
|
+
void func() {
|
|
53
|
+
if (cond) {
|
|
54
|
+
goto inside; // BAD - jumps into block
|
|
55
|
+
}
|
|
56
|
+
{
|
|
57
|
+
inside:
|
|
58
|
+
x = 1; // Variable might not be initialized!
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
good: |
|
|
63
|
+
void func() {
|
|
64
|
+
if (cond) {
|
|
65
|
+
needsProcessing = true;
|
|
66
|
+
}
|
|
67
|
+
if (needsProcessing) { // GOOD - restructure
|
|
68
|
+
x = 1;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
has_fix: false
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Goto Label Order
|
|
2
|
+
# Detects goto statements that jump to labels declared earlier
|
|
3
|
+
id: goto-label-order
|
|
4
|
+
name: Goto Should Jump to Later Labels
|
|
5
|
+
severity: warning
|
|
6
|
+
category: maintainability
|
|
7
|
+
defect_class: correctness
|
|
8
|
+
inline_tier: warning
|
|
9
|
+
language: c
|
|
10
|
+
|
|
11
|
+
message: "goto should jump to labels declared later in the same function"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
Goto statements should only jump forward to labels declared later.
|
|
15
|
+
Backward jumps create spaghetti code and are harder to understand.
|
|
16
|
+
This is a MISRA C requirement.
|
|
17
|
+
|
|
18
|
+
✅ FIX: Restructure to use forward jumps only
|
|
19
|
+
|
|
20
|
+
```c
|
|
21
|
+
void process() {
|
|
22
|
+
if (error) {
|
|
23
|
+
goto cleanup; // Forward jump - OK
|
|
24
|
+
}
|
|
25
|
+
// ... code ...
|
|
26
|
+
cleanup:
|
|
27
|
+
free_resources();
|
|
28
|
+
}
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
query: |
|
|
32
|
+
(function_definition
|
|
33
|
+
body: (compound_statement
|
|
34
|
+
(goto_statement
|
|
35
|
+
(statement_identifier) @LABEL) @GOTO))
|
|
36
|
+
|
|
37
|
+
metavars:
|
|
38
|
+
- LABEL
|
|
39
|
+
- GOTO
|
|
40
|
+
|
|
41
|
+
post_filter: goto_jumps_backward
|
|
42
|
+
|
|
43
|
+
tags:
|
|
44
|
+
- maintainability
|
|
45
|
+
- c
|
|
46
|
+
- misra
|
|
47
|
+
- control-flow
|
|
48
|
+
|
|
49
|
+
examples:
|
|
50
|
+
bad: |
|
|
51
|
+
void func() {
|
|
52
|
+
loop:
|
|
53
|
+
if (done) return;
|
|
54
|
+
process();
|
|
55
|
+
goto loop; // BAD - backward jump
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
good: |
|
|
59
|
+
void func() {
|
|
60
|
+
while (!done) { // GOOD - use loop instead
|
|
61
|
+
process();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
has_fix: false
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# COBOL ALTER Statement
|
|
2
|
+
# Detects ALTER statement usage in COBOL
|
|
3
|
+
id: alter-statement
|
|
4
|
+
name: ALTER Should Not Be Used
|
|
5
|
+
severity: warning
|
|
6
|
+
category: maintainability
|
|
7
|
+
defect_class: correctness
|
|
8
|
+
inline_tier: warning
|
|
9
|
+
language: cobol
|
|
10
|
+
|
|
11
|
+
message: "ALTER should not be used - causes spaghetti code"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
ALTER changes paragraph/section execution flow at runtime.
|
|
15
|
+
This is deprecated and causes unmaintainable spaghetti code.
|
|
16
|
+
|
|
17
|
+
✅ FIX: Restructure to use PERFORM or other control flow
|
|
18
|
+
|
|
19
|
+
query: |
|
|
20
|
+
(alter_statement
|
|
21
|
+
(ALTER) @ALTER)
|
|
22
|
+
|
|
23
|
+
metavars:
|
|
24
|
+
- ALTER
|
|
25
|
+
|
|
26
|
+
tags:
|
|
27
|
+
- maintainability
|
|
28
|
+
- cobol
|
|
29
|
+
- brain-overload
|
|
30
|
+
- deprecated
|
|
31
|
+
|
|
32
|
+
examples:
|
|
33
|
+
bad: |
|
|
34
|
+
ALTER PARA-1 TO PROCEED TO PARA-2. -- BAD
|
|
35
|
+
|
|
36
|
+
good: |
|
|
37
|
+
PERFORM PARA-2. -- GOOD - explicit control flow
|
|
38
|
+
|
|
39
|
+
has_fix: false
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# No std::auto_ptr
|
|
2
|
+
# Detects usage of deprecated std::auto_ptr
|
|
3
|
+
id: no-auto-ptr
|
|
4
|
+
name: std::auto_ptr Should Not Be Used
|
|
5
|
+
severity: error
|
|
6
|
+
category: reliability
|
|
7
|
+
defect_class: correctness
|
|
8
|
+
inline_tier: blocking
|
|
9
|
+
language: cpp
|
|
10
|
+
|
|
11
|
+
message: "std::auto_ptr should not be used — use std::unique_ptr instead"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
std::auto_ptr is deprecated (since C++11) and removed in C++17.
|
|
15
|
+
It has dangerous copy semantics. Use std::unique_ptr instead.
|
|
16
|
+
|
|
17
|
+
✅ FIX: Replace with std::unique_ptr
|
|
18
|
+
|
|
19
|
+
```cpp
|
|
20
|
+
std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>(); // GOOD
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
query: |
|
|
24
|
+
(template_type
|
|
25
|
+
name: (type_identifier) @NAME (#eq? @NAME "auto_ptr")
|
|
26
|
+
arguments: (template_argument_list) @ARGS)
|
|
27
|
+
((type_identifier) @NAME
|
|
28
|
+
(#eq? @NAME "auto_ptr"))
|
|
29
|
+
|
|
30
|
+
metavars:
|
|
31
|
+
- NAME
|
|
32
|
+
- ARGS
|
|
33
|
+
|
|
34
|
+
tags:
|
|
35
|
+
- reliability
|
|
36
|
+
- cpp
|
|
37
|
+
- deprecated
|
|
38
|
+
- since-cpp11
|
|
39
|
+
- removed-cpp17
|
|
40
|
+
|
|
41
|
+
examples:
|
|
42
|
+
bad: |
|
|
43
|
+
std::auto_ptr<MyClass> ptr(new MyClass()); // BAD - deprecated
|
|
44
|
+
|
|
45
|
+
good: |
|
|
46
|
+
std::unique_ptr<MyClass> ptr = std::make_unique<MyClass>(); // GOOD
|
|
47
|
+
|
|
48
|
+
has_fix: true
|
|
49
|
+
fix_action: replace_auto_with_unique_ptr
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# No Confused std::move/std::forward
|
|
2
|
+
# Detects potential confusion between std::move and std::forward
|
|
3
|
+
id: no-confused-move-forward
|
|
4
|
+
name: std::move and std::forward Should Not Be Confused
|
|
5
|
+
severity: error
|
|
6
|
+
category: reliability
|
|
7
|
+
defect_class: correctness
|
|
8
|
+
inline_tier: blocking
|
|
9
|
+
language: cpp
|
|
10
|
+
|
|
11
|
+
message: "std::move and std::forward should not be confused"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
std::move unconditionally casts to rvalue, while std::forward
|
|
15
|
+
conditionally casts based on template parameter. Using the wrong
|
|
16
|
+
one can lead to subtle bugs and unexpected copies/moves.
|
|
17
|
+
|
|
18
|
+
✅ FIX: Use std::move for known objects, std::forward for templates
|
|
19
|
+
|
|
20
|
+
```cpp
|
|
21
|
+
template<typename T>
|
|
22
|
+
void process(T&& t) {
|
|
23
|
+
other(std::forward<T>(t)); // Correct - preserve value category
|
|
24
|
+
}
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
query: |
|
|
28
|
+
(call_expression
|
|
29
|
+
function: (qualified_identifier
|
|
30
|
+
name: (identifier) @FUNC
|
|
31
|
+
(#match? @FUNC "^(move|forward)$"))
|
|
32
|
+
arguments: (argument_list) @ARGS)
|
|
33
|
+
|
|
34
|
+
post_filter: confused_move_forward
|
|
35
|
+
|
|
36
|
+
metavars:
|
|
37
|
+
- FUNC
|
|
38
|
+
- ARGS
|
|
39
|
+
|
|
40
|
+
tags:
|
|
41
|
+
- reliability
|
|
42
|
+
- cpp
|
|
43
|
+
- move-semantics
|
|
44
|
+
- cppcoreguidelines
|
|
45
|
+
|
|
46
|
+
examples:
|
|
47
|
+
bad: |
|
|
48
|
+
template<typename T>
|
|
49
|
+
void wrapper(T&& t) {
|
|
50
|
+
return foo(std::move(t)); // BAD - breaks perfect forwarding
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
good: |
|
|
54
|
+
template<typename T>
|
|
55
|
+
void wrapper(T&& t) {
|
|
56
|
+
return foo(std::forward<T>(t)); // GOOD - preserves category
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
has_fix: false
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# No Memset For Sensitive Data
|
|
2
|
+
# Detects memset used to clear sensitive data
|
|
3
|
+
id: no-memset-sensitive-data
|
|
4
|
+
name: memset Should Not Be Used to Delete Sensitive Data
|
|
5
|
+
severity: error
|
|
6
|
+
category: security
|
|
7
|
+
defect_class: security
|
|
8
|
+
inline_tier: blocking
|
|
9
|
+
language: cpp
|
|
10
|
+
|
|
11
|
+
message: "memset should not be used to delete sensitive data — use SecureZeroMemory or explicit_bzero"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
memset can be optimized away by compilers, leaving sensitive data
|
|
15
|
+
in memory. Use SecureZeroMemory (Windows), explicit_bzero (Linux),
|
|
16
|
+
or std::fill with volatile for clearing passwords/keys.
|
|
17
|
+
|
|
18
|
+
✅ FIX: Use secure memory clearing functions
|
|
19
|
+
|
|
20
|
+
```cpp
|
|
21
|
+
#ifdef _WIN32
|
|
22
|
+
SecureZeroMemory(password, sizeof(password));
|
|
23
|
+
#else
|
|
24
|
+
explicit_bzero(password, sizeof(password));
|
|
25
|
+
#endif
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
query: |
|
|
29
|
+
(call_expression
|
|
30
|
+
function: (identifier) @FUNC (#eq? @FUNC "memset")
|
|
31
|
+
arguments: (argument_list) @ARGS)
|
|
32
|
+
|
|
33
|
+
metavars:
|
|
34
|
+
- FUNC
|
|
35
|
+
- ARGS
|
|
36
|
+
|
|
37
|
+
post_filter: memset_for_sensitive_data
|
|
38
|
+
|
|
39
|
+
tags:
|
|
40
|
+
- security
|
|
41
|
+
- cpp
|
|
42
|
+
- cwe
|
|
43
|
+
- cryptography
|
|
44
|
+
- memory
|
|
45
|
+
|
|
46
|
+
examples:
|
|
47
|
+
bad: |
|
|
48
|
+
char password[32];
|
|
49
|
+
// ... use password ...
|
|
50
|
+
memset(password, 0, sizeof(password)); // BAD - may be optimized away!
|
|
51
|
+
|
|
52
|
+
good: |
|
|
53
|
+
char password[32];
|
|
54
|
+
// ... use password ...
|
|
55
|
+
explicit_bzero(password, sizeof(password)); // GOOD - guaranteed clear
|
|
56
|
+
|
|
57
|
+
has_fix: false
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# std::scoped_lock With Constructor Args
|
|
2
|
+
# Detects std::scoped_lock created without constructor arguments
|
|
3
|
+
id: no-scoped-lock-without-args
|
|
4
|
+
name: std::scoped_lock Should Be Created With Constructor Arguments
|
|
5
|
+
severity: error
|
|
6
|
+
category: reliability
|
|
7
|
+
defect_class: correctness
|
|
8
|
+
inline_tier: blocking
|
|
9
|
+
language: cpp
|
|
10
|
+
|
|
11
|
+
message: "std::scoped_lock should be created with constructor arguments"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
std::scoped_lock is designed to lock multiple mutexes atomically.
|
|
15
|
+
Creating one without arguments serves no purpose and is likely a bug.
|
|
16
|
+
|
|
17
|
+
✅ FIX: Pass mutexes to the constructor
|
|
18
|
+
|
|
19
|
+
```cpp
|
|
20
|
+
std::mutex m1, m2;
|
|
21
|
+
std::scoped_lock lock(m1, m2); // GOOD - locks both
|
|
22
|
+
```
|
|
23
|
+
|
|
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))
|
|
30
|
+
|
|
31
|
+
metavars:
|
|
32
|
+
- TYPE
|
|
33
|
+
- ARGS
|
|
34
|
+
|
|
35
|
+
post_filter: scoped_lock_empty_args
|
|
36
|
+
|
|
37
|
+
tags:
|
|
38
|
+
- reliability
|
|
39
|
+
- cpp
|
|
40
|
+
- since-cpp17
|
|
41
|
+
- mutex
|
|
42
|
+
- concurrency
|
|
43
|
+
|
|
44
|
+
examples:
|
|
45
|
+
bad: |
|
|
46
|
+
std::scoped_lock lock; // BAD - no mutexes to lock!
|
|
47
|
+
|
|
48
|
+
good: |
|
|
49
|
+
std::mutex mtx;
|
|
50
|
+
std::scoped_lock lock(mtx); // GOOD - locks mutex
|
|
51
|
+
|
|
52
|
+
has_fix: false
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Noexcept Functions
|
|
2
|
+
# Detects functions that should be noexcept
|
|
3
|
+
id: noexcept-functions
|
|
4
|
+
name: Exception-Unfriendly Functions Should Be noexcept
|
|
5
|
+
severity: error
|
|
6
|
+
category: reliability
|
|
7
|
+
defect_class: correctness
|
|
8
|
+
inline_tier: blocking
|
|
9
|
+
language: cpp
|
|
10
|
+
|
|
11
|
+
message: "Function should be declared noexcept"
|
|
12
|
+
|
|
13
|
+
description: |
|
|
14
|
+
Functions that don't throw exceptions should be marked noexcept.
|
|
15
|
+
This enables compiler optimizations and better error handling.
|
|
16
|
+
This is a MISRA C++ 2023 rule.
|
|
17
|
+
|
|
18
|
+
✅ FIX: Add noexcept specifier
|
|
19
|
+
|
|
20
|
+
```cpp
|
|
21
|
+
int add(int a, int b) noexcept { // GOOD - noexcept
|
|
22
|
+
return a + b;
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
query: |
|
|
27
|
+
(function_definition
|
|
28
|
+
type: (primitive_type) @RET
|
|
29
|
+
(function_declarator
|
|
30
|
+
name: (identifier) @NAME)
|
|
31
|
+
body: (compound_statement) @BODY)
|
|
32
|
+
|
|
33
|
+
metavars:
|
|
34
|
+
- RET
|
|
35
|
+
- NAME
|
|
36
|
+
- BODY
|
|
37
|
+
|
|
38
|
+
post_filter: should_be_noexcept
|
|
39
|
+
|
|
40
|
+
tags:
|
|
41
|
+
- reliability
|
|
42
|
+
- cpp
|
|
43
|
+
- misra-cpp2023
|
|
44
|
+
- performance
|
|
45
|
+
|
|
46
|
+
examples:
|
|
47
|
+
bad: |
|
|
48
|
+
int add(int a, int b) { // BAD - missing noexcept
|
|
49
|
+
return a + b;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
good: |
|
|
53
|
+
int add(int a, int b) noexcept { // GOOD
|
|
54
|
+
return a + b;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
has_fix: true
|
|
58
|
+
fix_action: add_noexcept
|