#pragma once // Step 494: Annotate Whetstone's Own Code // Audits inferred annotations over parsed Whetstone headers. #include "AnnotationInference.h" #include "SafetyAuditor.h" #include "SelfHostCodebaseAudit.h" #include #include #include #include #include #include #include struct FileAnnotationAudit { std::string path; bool parseSuccess = false; int inferredTotal = 0; int complexityCount = 0; int riskCount = 0; int ownerCount = 0; int intentCount = 0; int tailCallCount = 0; std::vector warnings; }; struct SelfAnnotationAuditReport { std::vector files; int totalFiles = 0; int parsedFiles = 0; int inferredTotal = 0; int complexityCount = 0; int riskCount = 0; int ownerCount = 0; int intentCount = 0; int tailCallCount = 0; std::vector notes; double parseRate() const { return totalFiles > 0 ? static_cast(parsedFiles) / totalFiles : 1.0; } }; class SelfHostAnnotationAudit { public: static SelfAnnotationAuditReport auditDirectories(const std::vector& roots) { return auditFiles(SelfHostCodebaseAudit::listHeaderFiles(roots)); } static SelfAnnotationAuditReport auditFiles(const std::vector& files) { SelfAnnotationAuditReport out; out.totalFiles = static_cast(files.size()); for (const auto& path : files) { auto fa = auditFile(path); out.files.push_back(fa); accumulate(fa, out); } out.notes.push_back("Annotation inference audit completed"); return out; } static FileAnnotationAudit auditSource(const std::string& source, const std::string& label = "") { FileAnnotationAudit out; out.path = label; auto parsed = SelfHostHarness::parseSource(source, label); out.parseSuccess = parsed.parseSuccess; out.warnings = parsed.warnings; if (!parsed.parseSuccess || !parsed.ast) return out; parsed.ast->targetLanguage = "cpp"; AnnotationInference inf; auto inferred = inf.inferAll(parsed.ast.get()); out.inferredTotal = static_cast(inferred.size()); tallyInferred(inferred, out); tallyRiskFromSource(source, out); tallyOwnerFromSource(source, out); tallyIntentFromAst(parsed.ast.get(), out); return out; } private: static FileAnnotationAudit auditFile(const std::string& path) { FileAnnotationAudit out; out.path = path; auto parsed = SelfHostHarness::parseFile(path); out.parseSuccess = parsed.parseSuccess; out.warnings = parsed.warnings; if (!parsed.parseSuccess || !parsed.ast) return out; const std::string source = SelfHostHarness::readFile(path); parsed.ast->targetLanguage = "cpp"; AnnotationInference inf; auto inferred = inf.inferAll(parsed.ast.get()); out.inferredTotal = static_cast(inferred.size()); tallyInferred(inferred, out); tallyRiskFromSource(source, out); tallyOwnerFromSource(source, out); tallyIntentFromAst(parsed.ast.get(), out); return out; } static void tallyInferred(const std::vector& inferred, FileAnnotationAudit& out) { for (const auto& ann : inferred) { if (ann.annotationType == "ComplexityAnnotation") out.complexityCount++; if (ann.annotationType == "OwnerAnnotation") out.ownerCount++; if (ann.annotationType == "TailCallAnnotation") out.tailCallCount++; } } static void tallyRiskFromSource(const std::string& source, FileAnnotationAudit& out) { auto safety = SafetyAuditor::audit(source, "cpp", out.path); for (const auto& finding : safety.findings) { if (finding.riskLevel >= 2) out.riskCount++; } if (contains(source, "reinterpret_cast") || contains(source, "void*")) { out.riskCount++; } } static void tallyOwnerFromSource(const std::string& source, FileAnnotationAudit& out) { out.ownerCount += countRegex(source, std::regex(R"(std::unique_ptr<)")); out.ownerCount += countRegex(source, std::regex(R"(std::shared_ptr<)")); } static void tallyIntentFromAst(const Module* ast, FileAnnotationAudit& out) { const auto names = SelfHostHarness::getFunctionNames(ast); for (const auto& n : names) { if (isDescriptiveName(n)) out.intentCount++; } } static bool isDescriptiveName(const std::string& name) { static const std::vector verbs = { "parse", "build", "generate", "validate", "infer", "audit", "create", "load", "save", "render", "run", "check" }; std::string lower = toLower(name); for (const auto& v : verbs) { if (lower.find(v) == 0 || lower.find(v) != std::string::npos) return true; } return false; } static int countRegex(const std::string& text, const std::regex& re) { auto begin = std::sregex_iterator(text.begin(), text.end(), re); auto end = std::sregex_iterator(); int count = 0; for (auto it = begin; it != end; ++it) ++count; return count; } static std::string toLower(std::string s) { std::transform(s.begin(), s.end(), s.begin(), [](unsigned char c) { return static_cast(std::tolower(c)); }); return s; } static bool contains(const std::string& src, const std::string& needle) { return src.find(needle) != std::string::npos; } static void accumulate(const FileAnnotationAudit& f, SelfAnnotationAuditReport& out) { if (f.parseSuccess) out.parsedFiles++; out.inferredTotal += f.inferredTotal; out.complexityCount += f.complexityCount; out.riskCount += f.riskCount; out.ownerCount += f.ownerCount; out.intentCount += f.intentCount; out.tailCallCount += f.tailCallCount; } };