pi-lens 3.8.37 → 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.
Files changed (83) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/README.md +2 -2
  3. package/banner.png +0 -0
  4. package/banner.svg +31 -16
  5. package/clients/cache/rule-cache.ts +2 -1
  6. package/clients/cache-manager.ts +4 -1
  7. package/clients/dispatch/fact-scheduler.ts +2 -1
  8. package/clients/dispatch/fact-store.ts +4 -6
  9. package/clients/dispatch/integration.ts +2 -5
  10. package/clients/dispatch/rules/quality-rules.ts +10 -15
  11. package/clients/dispatch/runners/biome-check.ts +1 -1
  12. package/clients/dispatch/runners/eslint.ts +1 -1
  13. package/clients/dispatch/runners/lsp.ts +1 -5
  14. package/clients/dispatch/runners/psscriptanalyzer.ts +1 -1
  15. package/clients/dispatch/runners/similarity.ts +1 -4
  16. package/clients/dispatch/utils/lsp-diagnostics.ts +3 -9
  17. package/clients/formatters.ts +12 -7
  18. package/clients/lsp/index.ts +8 -10
  19. package/clients/lsp/launch.ts +5 -8
  20. package/clients/lsp/server.ts +1 -1
  21. package/clients/pipeline.ts +6 -11
  22. package/clients/read-guard.ts +5 -6
  23. package/clients/runtime-coordinator.ts +2 -2
  24. package/clients/runtime-tool-result.ts +1 -3
  25. package/clients/secrets-scanner.ts +1 -1
  26. package/clients/session-summary.ts +1 -1
  27. package/clients/tree-sitter-query-loader.ts +3 -2
  28. package/commands/booboo.ts +15 -14
  29. package/index.ts +5 -5
  30. package/package.json +3 -2
  31. package/rules/rule-catalog.json +52 -1
  32. package/rules/tree-sitter-queries/abap/delete-where.yml +46 -0
  33. package/rules/tree-sitter-queries/c/case-range-multiple-values.yml +65 -0
  34. package/rules/tree-sitter-queries/c/goto-into-block.yml +72 -0
  35. package/rules/tree-sitter-queries/c/goto-label-order.yml +65 -0
  36. package/rules/tree-sitter-queries/cobol/alter-statement.yml +39 -0
  37. package/rules/tree-sitter-queries/cpp/no-auto-ptr.yml +49 -0
  38. package/rules/tree-sitter-queries/cpp/no-confused-move-forward.yml +59 -0
  39. package/rules/tree-sitter-queries/cpp/no-memset-sensitive-data.yml +57 -0
  40. package/rules/tree-sitter-queries/cpp/no-scoped-lock-without-args.yml +52 -0
  41. package/rules/tree-sitter-queries/cpp/noexcept-functions.yml +58 -0
  42. package/rules/tree-sitter-queries/csharp/async-await-identifiers.yml +50 -0
  43. package/rules/tree-sitter-queries/csharp/is-with-this.yml +52 -0
  44. package/rules/tree-sitter-queries/csharp/no-dangerous-get-handle.yml +59 -0
  45. package/rules/tree-sitter-queries/csharp/no-operator-eq-reference.yml +60 -0
  46. package/rules/tree-sitter-queries/csharp/no-thread-resume-suspend.yml +60 -0
  47. package/rules/tree-sitter-queries/css/calc-spacing.yml +50 -0
  48. package/rules/tree-sitter-queries/java/junit-call-super.yml +63 -0
  49. package/rules/tree-sitter-queries/java/main-should-not-throw.yml +63 -0
  50. package/rules/tree-sitter-queries/java/no-clone-override.yml +60 -0
  51. package/rules/tree-sitter-queries/java/no-double-checked-locking.yml +74 -0
  52. package/rules/tree-sitter-queries/java/no-exit-methods.yml +50 -0
  53. package/rules/tree-sitter-queries/java/no-field-shadowing.yml +66 -0
  54. package/rules/tree-sitter-queries/java/no-future-keywords.yml +49 -0
  55. package/rules/tree-sitter-queries/java/no-threadgroup.yml +52 -0
  56. package/rules/tree-sitter-queries/java/no-threads-in-constructors.yml +73 -0
  57. package/rules/tree-sitter-queries/java/no-wait-notify-on-thread.yml +58 -0
  58. package/rules/tree-sitter-queries/java/prepared-statement-valid-indices.yml +55 -0
  59. package/rules/tree-sitter-queries/java/spring-session-attributes-setcomplete.yml +75 -0
  60. package/rules/tree-sitter-queries/java/springboot-default-package.yml +69 -0
  61. package/rules/tree-sitter-queries/java/switch-fall-through.yml +70 -0
  62. package/rules/tree-sitter-queries/java/switch-non-case-labels.yml +62 -0
  63. package/rules/tree-sitter-queries/javascript/switch-non-case-labels.yml +52 -0
  64. package/rules/tree-sitter-queries/kotlin/prepared-statement-indices.yml +49 -0
  65. package/rules/tree-sitter-queries/php/no-exit-die.yml +52 -0
  66. package/rules/tree-sitter-queries/php/this-in-static-context.yml +75 -0
  67. package/rules/tree-sitter-queries/plsql/delete-update-where.yml +56 -0
  68. package/rules/tree-sitter-queries/plsql/end-loop-semicolon.yml +51 -0
  69. package/rules/tree-sitter-queries/plsql/fetch-bulk-collect-limit.yml +47 -0
  70. package/rules/tree-sitter-queries/plsql/forallsave-exceptions.yml +51 -0
  71. package/rules/tree-sitter-queries/plsql/no-synchronize.yml +47 -0
  72. package/rules/tree-sitter-queries/plsql/not-null-initialization.yml +59 -0
  73. package/rules/tree-sitter-queries/plsql/raise-application-error-codes.yml +50 -0
  74. package/rules/tree-sitter-queries/python/exit-signature-check.yml +66 -0
  75. package/rules/tree-sitter-queries/python/in-operator-unsupported.yml +57 -0
  76. package/rules/tree-sitter-queries/python/iter-return-iterator.yml +59 -0
  77. package/rules/tree-sitter-queries/python/notimplemented-boolean-context.yml +67 -0
  78. package/rules/tree-sitter-queries/python/return-in-generator.yml +58 -0
  79. package/rules/tree-sitter-queries/python/return-in-init.yml +59 -0
  80. package/rules/tree-sitter-queries/python/send-file-mimetype.yml +53 -0
  81. package/rules/tree-sitter-queries/python/yield-return-outside-function.yml +57 -0
  82. package/tools/lsp-navigation.js +14 -16
  83. package/tools/lsp-navigation.ts +14 -18
@@ -1149,9 +1149,7 @@ export async function handleBooboo(
1149
1149
  inner.spans?.[0];
1150
1150
  if (!span) continue;
1151
1151
  const absFile = span.file_name
1152
- ? path.isAbsolute(span.file_name)
1153
- ? span.file_name
1154
- : path.join(targetPath, span.file_name)
1152
+ ? (path.isAbsolute(span.file_name) ? span.file_name : path.join(targetPath, span.file_name))
1155
1153
  : targetPath;
1156
1154
  issues.push({
1157
1155
  file: path.relative(targetPath, absFile),
@@ -1183,9 +1181,7 @@ export async function handleBooboo(
1183
1181
  for (const diag of json?.generalDiagnostics ?? []) {
1184
1182
  if (!["error", "warning"].includes(diag.severity)) continue;
1185
1183
  const absFile = diag.file
1186
- ? path.isAbsolute(diag.file)
1187
- ? diag.file
1188
- : path.join(targetPath, diag.file)
1184
+ ? (path.isAbsolute(diag.file) ? diag.file : path.join(targetPath, diag.file))
1189
1185
  : targetPath;
1190
1186
  if (shouldIncludeFile(absFile)) {
1191
1187
  issues.push({
@@ -1331,7 +1327,7 @@ export async function handleBooboo(
1331
1327
  );
1332
1328
  const output = (result.stdout || "") + (result.stderr || "");
1333
1329
  const csRe =
1334
- /^([^\s(]+\.cs)\((\d+),(\d+)\):\s+(error|warning)\s+([A-Z]+\d+):\s+([^\[]+)/gm;
1330
+ /^([^\s(]+\.cs)\((\d+),(\d+)\):\s+(error|warning)\s+([A-Z]+\d+):\s+([^[]+)/gm;
1335
1331
  for (const m of output.matchAll(csRe)) {
1336
1332
  const [, file, line, col, sev, code, msg] = m;
1337
1333
  const absFile = path.isAbsolute(file)
@@ -1394,10 +1390,13 @@ export async function handleBooboo(
1394
1390
  timeout: 60_000,
1395
1391
  });
1396
1392
  const output = (result.stdout || "") + (result.stderr || "");
1397
- const gleamRe =
1398
- /^([^:\n]+):(\d+):(\d+)\s*(?:error|warning)[^\n]*\n([^\n]+)/gm;
1399
- for (const m of output.matchAll(gleamRe)) {
1400
- const [, file, line, col, msg] = m;
1393
+ const gleamLines = output.split("\n");
1394
+ const gleamHeaderRe = /^([^:]+):(\d+):(\d+)[ \t]*(?:error|warning)/;
1395
+ for (let i = 0; i < gleamLines.length; i++) {
1396
+ const m = gleamHeaderRe.exec(gleamLines[i]);
1397
+ if (!m) continue;
1398
+ const [, file, line, col] = m;
1399
+ const msg = gleamLines[i + 1]?.trim() ?? "";
1401
1400
  const absFile = path.isAbsolute(file)
1402
1401
  ? file
1403
1402
  : path.join(targetPath, file);
@@ -1408,7 +1407,7 @@ export async function handleBooboo(
1408
1407
  col: parseInt(col, 10),
1409
1408
  severity: "error",
1410
1409
  code: "gleam",
1411
- message: msg.trim(),
1410
+ message: msg,
1412
1411
  compiler: "gleam check",
1413
1412
  });
1414
1413
  }
@@ -1426,8 +1425,10 @@ export async function handleBooboo(
1426
1425
  timeout: 120_000,
1427
1426
  });
1428
1427
  const output = (result.stdout || "") + (result.stderr || "");
1429
- const zigRe = /^([^:\n]+):(\d+):(\d+):\s*(error|warning|note):\s*([^\n]+)/gm;
1430
- for (const m of output.matchAll(zigRe)) {
1428
+ const zigLineRe = /^([^:]+):(\d+):(\d+):[ \t]*(error|warning|note):[ \t]*(.+)/;
1429
+ for (const zigLine of output.split("\n")) {
1430
+ const m = zigLineRe.exec(zigLine);
1431
+ if (!m) continue;
1431
1432
  const [, file, line, col, sev, msg] = m;
1432
1433
  const absFile = path.isAbsolute(file)
1433
1434
  ? file
package/index.ts CHANGED
@@ -1148,7 +1148,7 @@ export default function (pi: ExtensionAPI) {
1148
1148
  if (dupeWarnings.length > 0) {
1149
1149
  return {
1150
1150
  block: true,
1151
- reason: `🔴 STOP - Redefining existing export(s). Import instead:\n${dupeWarnings.map((w) => `${w}`).join("\n")}`,
1151
+ reason: "🔴 STOP - Redefining existing export(s). Import instead:\n" + dupeWarnings.map((w) => "" + w).join("\n"),
1152
1152
  };
1153
1153
  }
1154
1154
 
@@ -1321,9 +1321,9 @@ export default function (pi: ExtensionAPI) {
1321
1321
  // --- Inject turn-end findings into next agent turn ---
1322
1322
  // jscpd, madge, and turn-end delta results are cached at turn_end and consumed here
1323
1323
  // via the context event, which fires before each provider request.
1324
- // Important: context handlers must APPEND to the existing message list, not replace it.
1325
- // Replacing `event.messages` can drop the user's first prompt entirely, which causes
1326
- // OpenAI Responses requests to fail with: "One of input/previous_response_id/prompt/conversation_id must be provided."
1324
+ // Important: keep the user's prompt as the trailing message. Some provider bridges
1325
+ // treat the final message as the active user action, so pi-lens context must be
1326
+ // prepended instead of appended.
1327
1327
  // biome-ignore lint/suspicious/noExplicitAny: pi.on("context") overload has TS resolution bug
1328
1328
  (pi as any).on(
1329
1329
  "context",
@@ -1348,7 +1348,7 @@ export default function (pi: ExtensionAPI) {
1348
1348
  ?.messages ?? [];
1349
1349
 
1350
1350
  return {
1351
- messages: [...existingMessages, ...injectedMessages],
1351
+ messages: [...injectedMessages, ...existingMessages],
1352
1352
  };
1353
1353
  } catch (err) {
1354
1354
  dbg(`context event error: ${err}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-lens",
3
- "version": "3.8.37",
3
+ "version": "3.8.39",
4
4
  "type": "module",
5
5
  "description": "Real-time code feedback for pi \u2014 LSP, linters, formatters, type-checking, structural analysis & booboo",
6
6
  "repository": {
@@ -55,7 +55,8 @@
55
55
  "tsconfig.json",
56
56
  "README.md",
57
57
  "CHANGELOG.md",
58
- "banner.svg"
58
+ "banner.svg",
59
+ "banner.png"
59
60
  ],
60
61
  "peerDependencies": {
61
62
  "@mariozechner/pi-coding-agent": "*"
@@ -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