// Static diff check — grep-style, no AST, no LLM. Looks for patterns // that are high-signal evidence of placeholder code. // // Findings are severity-graded: // block — explicit non-impl markers (unimplemented!, todo!, // panic!("not implemented"), throw new Error("not implemented")) // warn — TODO / FIXME / XXX / HACK comments on added lines, // new struct fields with no read-site anywhere in the diff, // suspiciously-empty function bodies ({ Ok(()) } / {} when // the commit message claims the fn "implements" something) // info — hardcoded "test" / "dummy" / "placeholder" strings in // added lines (could be real, just flag for inspection) // // Consumes: raw unified diff text from Gitea. import type { Finding } from "../types.ts"; // Rust + TypeScript patterns that almost always indicate "this is // not actually implemented yet." const BLOCK_PATTERNS: Array<{ re: RegExp; why: string }> = [ { re: /\bunimplemented!\s*\(/, why: "unimplemented!() macro call" }, { re: /\btodo!\s*\(/, why: "todo!() macro call" }, { re: /panic!\s*\(\s*"(?:not implemented|TODO|not yet|unimpl)/i, why: "panic! with not-implemented message" }, { re: /throw\s+new\s+Error\s*\(\s*['"](?:not implemented|TODO|unimpl)/i, why: "throw Error 'not implemented'" }, ]; const WARN_COMMENT_PATTERNS: Array<{ re: RegExp; why: string }> = [ { re: /^\+.*\/\/\s*(TODO|FIXME|XXX|HACK)\b/i, why: "TODO/FIXME/XXX/HACK comment added" }, { re: /^\+.*#\s*(TODO|FIXME|XXX|HACK)\b/i, why: "TODO/FIXME/XXX/HACK comment added" }, ]; const INFO_HARDCODED_PATTERNS: Array<{ re: RegExp; why: string }> = [ { re: /"(?:placeholder|dummy|foobar|xxx|replaceme|changeme)"/i, why: "suspicious hardcoded string" }, ]; export function runStaticCheck(diff: string): Finding[] { const findings: Finding[] = []; // Per-file walk: only look at ADDED lines (prefix '+' but not '+++' // which is the diff header). const perFile = splitDiffByFile(diff); for (const [path, lines] of perFile) { // Skip diff bookkeeping + pure-delete files if (!lines.some(l => l.startsWith("+") && !l.startsWith("+++"))) continue; for (let idx = 0; idx < lines.length; idx++) { const line = lines[idx]; if (!line.startsWith("+") || line.startsWith("+++")) continue; const added = line.slice(1); for (const { re, why } of BLOCK_PATTERNS) { if (re.test(added)) { findings.push({ check: "static", severity: "block", summary: `${why} in ${path}`, evidence: [`${path}:+${idx + 1}: ${added.trim().slice(0, 160)}`], }); } } for (const { re, why } of WARN_COMMENT_PATTERNS) { if (re.test(line)) { findings.push({ check: "static", severity: "warn", summary: `${why} in ${path}`, evidence: [`${path}:+${idx + 1}: ${added.trim().slice(0, 160)}`], }); } } for (const { re, why } of INFO_HARDCODED_PATTERNS) { if (re.test(added)) { findings.push({ check: "static", severity: "info", summary: `${why} in ${path}`, evidence: [`${path}:+${idx + 1}: ${added.trim().slice(0, 160)}`], }); } } } // "Field added but never read" heuristic — catches exactly the // Phase 45 DocRef placeholder pattern. Limited to the diff itself: // we're not doing a full-codebase grep here (too noisy; callers // elsewhere might exist). The point is: if NEITHER this diff nor // any other line in the diff reads the field, the PR is shipping // state without a consumer. const addedLines = lines.filter(l => l.startsWith("+") && !l.startsWith("+++")) .map(l => l.slice(1)); const newFields = extractNewFields(addedLines); for (const field of newFields) { const readPattern = new RegExp(`[\\.:]\\s*${escape(field)}\\b|\\b${escape(field)}\\s*:`); // The definition line itself matches readPattern — filter it out // by requiring at least TWO lines in the diff mention the field // (one defines, one reads). const hits = addedLines.filter(l => readPattern.test(l)); if (hits.length < 2) { findings.push({ check: "static", severity: "warn", summary: `field '${field}' added in ${path} but no read-site in the diff — could be placeholder state without a consumer`, evidence: [`${path}: added '${field}' with no reader; rest of diff has ${hits.length - 1} mentions`], }); } } } return findings; } function splitDiffByFile(diff: string): Map { const out = new Map(); let current: string | null = null; let buf: string[] = []; for (const line of diff.split(/\r?\n/)) { const m = line.match(/^diff --git a\/(\S+) b\/(\S+)/); if (m) { if (current) out.set(current, buf); current = m[2]; buf = []; continue; } buf.push(line); } if (current) out.set(current, buf); return out; } // Extract new `pub name: Type,` fields from added lines. Rust syntax. // Narrowly-scoped: only matches at the start of a trimmed line, // requires `pub ` prefix, ignores `pub fn` / `pub struct` / etc. function extractNewFields(addedLines: string[]): string[] { const fields = new Set(); for (const line of addedLines) { const t = line.trim(); // pub NAME: Type, const m = t.match(/^pub\s+(?!fn\b|struct\b|enum\b|mod\b|use\b|trait\b|impl\b|const\b|static\b|type\b)(\w+)\s*:/); if (m) fields.add(m[1]); } return Array.from(fields); } function escape(s: string): string { return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); }