{"id":24746594,"url":"https://github.com/samuelmarks/type-correct","last_synced_at":"2026-05-08T00:35:10.612Z","repository":{"id":150265477,"uuid":"415683361","full_name":"SamuelMarks/type-correct","owner":"SamuelMarks","description":"Correct types: typed correctly","archived":false,"fork":false,"pushed_at":"2026-04-08T01:52:39.000Z","size":323,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-04-08T03:32:02.966Z","etag":null,"topics":["c","cpp","libclang","libtooling","llvm"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"cc0-1.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SamuelMarks.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2021-10-10T19:40:06.000Z","updated_at":"2026-04-08T01:52:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"a0371e0a-9d1e-4381-9ea3-b8e96a1b8a90","html_url":"https://github.com/SamuelMarks/type-correct","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/SamuelMarks/type-correct","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SamuelMarks%2Ftype-correct","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SamuelMarks%2Ftype-correct/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SamuelMarks%2Ftype-correct/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SamuelMarks%2Ftype-correct/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SamuelMarks","download_url":"https://codeload.github.com/SamuelMarks/type-correct/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SamuelMarks%2Ftype-correct/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32762279,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-07T02:14:30.463Z","status":"ssl_error","status_checked_at":"2026-05-07T02:14:29.405Z","response_time":62,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["c","cpp","libclang","libtooling","llvm"],"created_at":"2025-01-28T04:29:30.201Z","updated_at":"2026-05-08T00:35:10.605Z","avatar_url":"https://github.com/SamuelMarks.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"type-correct\n============\n\n[![CC0](https://img.shields.io/badge/license-CC0-%23373737)](LICENSE.md)\n[![x86-Darwin](https://github.com/SamuelMarks/type-correct/actions/workflows/x86-darwin.yml/badge.svg)](https://github.com/SamuelMarks/type-correct/actions/workflows/x86-darwin.yml)\n[![x86-Ubuntu](https://github.com/SamuelMarks/type-correct/actions/workflows/x86-ubuntu.yml/badge.svg)](https://github.com/SamuelMarks/type-correct/actions/workflows/x86-ubuntu.yml)\n\u003c!-- COVERAGE_BADGES_START --\u003e\n![Doc Coverage](https://img.shields.io/badge/doc%20coverage-100%25-brightgreen)\n![Test Coverage](https://img.shields.io/badge/test%20coverage-100%25-brightgreen)\n\u003c!-- COVERAGE_BADGES_END --\u003e\n\n**type-correct** is a modern [LLVM](https://llvm.org) and [LibTooling](https://clang.llvm.org/docs/LibTooling.html)\nautomated refactoring solution designed to 'fix' types. It rewrites inconsistent integer usage (commonly mixed `int`,\n`long`, and `size_t`) into a consistent, mathematically correct state, specifically targeting the elimination of\ntruncation warnings and signed/unsigned mismatches in legacy C and C++ codebases.\n\nUnlike simple regex replacements, `type-correct` builds a dependency graph of your variables, functions, and expressions\nto mathematically solve for the \"widest\" necessary type, ensuring global consistency across compilation units.\n\n---\n\n## Architectural Overview\n\n`type-correct` functions as more than a linter; it is a constraint solver. It parses the AST (Abstract Syntax Tree),\nidentifies usage patterns (assignments, comparisons, pointer arithmetic), and determines the optimal type width for\nevery connected component in your code.\n\n```mermaid\n%%{init: {'theme': 'base', 'themeVariables': { 'fontFamily': 'Roboto Mono Normal', 'fontSize': '16px'}}}%%\nflowchart TD\n%% Define Styles based on Project Design Codes\n   classDef blue fill:#4285f4,stroke:#20344b,stroke-width:2px,color:#ffffff,font-family:'Google Sans Medium';\n   classDef green fill:#34a853,stroke:#20344b,stroke-width:2px,color:#ffffff,font-family:'Google Sans Medium';\n   classDef yellow fill:#f9ab00,stroke:#20344b,stroke-width:2px,color:#ffffff,font-family:'Google Sans Medium';\n   classDef red fill:#ea4335,stroke:#20344b,stroke-width:2px,color:#ffffff,font-family:'Google Sans Medium';\n   classDef navy fill:#20344b,stroke:#57caff,stroke-width:2px,color:#ffffff,font-family:'Google Sans Medium';\n\n%% Nodes\n   Source[\"Source Code\u003cbr\u003e(.c / .cpp)\"]:::navy\n   Clang[\"Clang AST\u003cbr\u003eFrontend\"]:::blue\n   Matcher[\"AST Matcher\u003cbr\u003e(Identify Decls)\"]:::blue\n\n%% Safety Logic\n   Boundary[\"Safety Check\u003cbr\u003e(Struct/CMake)\"]:::red\n\n%% Solver Logic\n   Graph[\"Dependency\u003cbr\u003eGraph\"]:::yellow\n   Solver[\"Type Solver\u003cbr\u003e(Width Calc)\"]:::yellow\n   Ptr[\"Pointer Logic\u003cbr\u003e(ptrdiff_t)\"]:::yellow\n\n%% Output Logic\n   Facts[\"CTU Facts\u003cbr\u003e(Map/Reduce)\"]:::green\n   Writer[\"Rewriter\u003cbr\u003e(Apply Changes)\"]:::green\n\n%% Flow\n   Source --\u003e Clang\n   Clang --\u003e Matcher\n   Matcher --\u003e Boundary\n\n   Boundary -- \"If Safe\" --\u003e Graph\n   Boundary -. \"If System/Fixed\" .-\u003e Writer\n\n   Graph --\u003e Solver\n   Solver --\u003e Ptr\n   Ptr --\u003e Facts\n\n   Facts -- \"Global Type\" --\u003e Writer\n```\n\n### Core Components\n\n1. **StructAnalyzer (The Safety Gate):** Before modifying a variable, the tool determines if it is safe to change. It\n   heuristically detects \"System Boundaries\" by:\n    * Analyzing inclusion graphs (viral fixedness).\n    * Scanning neighbor `CMakeLists.txt` files to blindly identify `FetchContent` or `ExternalProject` directories (\n      vendored code).\n    * Checking for `attribute((packed))` or bitfields which lock memory layout.\n2. **TypeSolver (The Brain):** A graph-based solver that propagates type requirements. If `a = b`, and `b` must be\n   `size_t`, then `a` must also be at least `size_t`. It handles:\n    * **Pointer Semantics:** Variables used as array indices or in pointer arithmetic are forced to `ptrdiff_t` width (\n      or `size_t`) to prevent 64-bit truncation.\n    * **Symbolic Constraints:** Understanding relations like `c = a + b`.\n3. **FactManager (CTU):** Handles Cross-Translation Unit analysis via a Map-Reduce approach, allowing the tool to ensure\n   a function definition in `a.cpp` matches its usage in `b.cpp`.\n\n---\n\n## Automatic Conversions\n\nThe primary operation involves widening narrow integer types (`int`, `short`) to architecture-appropriate width types (\n`size_t`, `ptrdiff_t`) based on how they are actually used.\n\n```c\n#include \u003cstring.h\u003e\n\nint main(void) { \n\n    /* FROM */ \n    const int n = strlen(\"FOO\"); \n\n    /* TO: Correctly captures return type of strlen */ \n    const size_t n = strlen(\"FOO\"); \n\n    /* FROM */ \n    for(int i=0; i\u003cstrlen(\"BAR\"); i++) {} \n\n    /* TO: Loop index matches comparison type */ \n    for(size_t i=0; i\u003cstrlen(\"BAR\"); i++) {} \n\n    /* FROM */ \n    int f(long b) { return b; } \n    static const int c = f(5); \n\n    /* TO: Propagation of return types */ \n    long f(long b) { return b; } \n    static const long c = f(5); \n} \n```\n\n## Justification\n\nOften when building third-party libraries I get a bunch of warnings \"comparison between signed and unsigned types is\nUB\".\n\nNot every such occurrence has a trivial solution. But—in my experience—most do. Usually switching just one var from\n`int` to `size_t` also requires tracing all use of that var and changing all those types to `size_t` also. This is the\nmanual labor `type-correct` automates.\n\nFrom:\n\n```c\nunsigned long f() {return 0;} \nconst size_t v = f(); \n\nint main() { \n    std::vector\u003cfloat\u003e vec; \n    for(int i=0; i\u003cvec.size(); i++) {} \n} \n```\n\nTo:\n\n```c\nunsigned long f() {return 0;} \nconst unsigned long v = f(); \n\nint main() { \n    std::vector\u003cfloat\u003e vec; \n    for(size_t i=0; i\u003cvec.size(); i++) {} \n} \n```\n\nPS: I'm aware that [\n`size_type`](https://github.com/llvm/llvm-project/blob/d081d75dc8fc4b5173d6b15ffcf077d2e0d4143f/libcxx/include/vector#L321)\nisn't necessarily `size_t`—and that `decltype(vec)::size_type` would be more correct—but using it here anyway. Just to\nreiterate: C++ is an afterthought, my main target is C.\n\n## Integer Promotion \u0026 Truncation Safety\n\n```c\n#include \u003climits.h\u003e\n\nshort sh=SHRT_MAX; \nint i=INT_MAX; \nlong l=LONG_MAX; \nlong long ll=LLONG_MAX; /* C99 */ \n```\n\nTechnically, these are all [defined and expected](https://en.cppreference.com/w/c/language/conversion) [on clang as an [\n`ImplicitCastExpr`](https://clang.llvm.org/doxygen/classclang_1_1ImplicitCastExpr.html)]:\n\n```c\nll = l; \nl = i; \ni = sh; \n```\n\n(but the other\ndirection, '[narrowing](https://releases.llvm.org/13.0.0/tools/clang/tools/extra/docs/clang-tidy/checks/cppcoreguidelines-narrowing-conversions.html)',\nis implementation defined)\n\nHowever, IMHO, people doing `int sl = strlen(s);` actually want `size_t`.\nThis opinionated view is the assumption made for _type_correct_.\n\nBut… attempts are made to be reasonably conservative. See [\n`type_correct/tests/test_type_correct.cpp`](type_correct/tests/test_type_correct.cpp) for false positive and true\npositive checks.\n\n---\n\n## Detailed Usage\n\n`type-correct` is built as a standalone CLI tool that consumes a compilation database or acts on single files.\n\n### 1. Basic Audit\n\nBefore applying changes, stick to read-only \"Audit Mode\". This generates a change list table without touching disk.\n\n```bash\n$ type_correct_cli --audit --project-root=$(pwd) src/main.cpp\n```\n\n### 2. In-Place Refactoring\n\nTo apply changes directly to your source files:\n\n```bash\n$ type_correct_cli --in-place src/main.cpp\n```\n\n### 3. Iterative Global Analysis (CTU)\n\nFor complex projects where a header change affects multiple Translation Units (TUs), a single pass is insufficient.\n`type-correct` supports an iterative \"Fixed-Point Convergence\" mode using a Map-Reduce strategy.\n\n```bash\n# 1. Create a directory for intermediate facts\nmkdir facts\n\n# 2. Run iteratively until types stop changing\ntype_correct_cli \\\n  --phase=iterative \\\n  --facts-dir=facts \\\n  --project-root=$(pwd) \\\n  --in-place \\\n  src/*.cpp\n```\n\n### 4. Safety Flags\n\nBy default, the tool is conservative about changing struct layouts (ABI breaking). If you are recompiling the entire\nuniverse and want to optimize internal structs:\n\n```bash\n$ type_correct_cli --in-place --enable-abi-breaking-changes src/*.cpp\n```\n\n---\n\n## Build Instructions\n\nInstall a C++20 compliant compiler suite, CMake, and LLVM 16+ (from `brew`, `apt`, or source).\n\n**Dependencies:**\n\n* CMake \u003e= 3.20\n* LLVM/Clang \u003e= 16.0 (Required for modern LibTooling APIs)\n\n```sh\n$ mkdir build \u0026\u0026 cd build\n\n# Point to your LLVM installation root\n$ cmake .. \\\n  -DCMAKE_BUILD_TYPE='Debug' \\\n  -DCT_Clang_INSTALL_DIR='/usr/lib/llvm'\n\n$ cmake --build .\n```\n\n(Replace `/usr/lib/llvm` with your actual LLVM install directory found via `llvm-config --prefix`; on macOS `brew` it's `-DCT_Clang_INSTALL_DIR=/opt/homebrew/opt/llvm`).\n\n## Testing\n\nThe project uses `GoogleTest` for unit logic and `llvm-lit` for integration testing.\n\n```sh\n$ cd build\n$ ctest --output-on-failure\n```\n\n## Coverage Badges\n\n`scripts/update_coverage_badges.py` can compute documentation coverage from multiple open-source API doc generators and\nupdate the README badges.\n\nSupported doc sources:\n\n* Doxygen XML (C/C++/Objective-C/C#/Java)\n* JSDoc JSON (`jsdoc -X`) for JavaScript\n* TypeDoc JSON (`typedoc --json`) for TypeScript\n* OpenAPI specs (JSON/YAML) for REST APIs\n* Custom JSON counts (`documented` + `total`)\n\n```sh\n$ python3 scripts/update_coverage_badges.py \\\n  --doc-source doxygen=build/docs/xml \\\n  --doc-source typedoc=docs/typedoc.json\n```\n\nTo run coverage + doc coverage and refresh the shields in one step:\n\n```sh\n$ scripts/coverage_badges.sh [build]\n```\n\nEnable the pre-commit hook:\n\n```sh\n$ git config core.hooksPath .githooks\n```\n\n## Thanks\n\nBoilerplate from  https://github.com/banach-space/clang-tutor\n\n---\n\n### License\n\nThe person who associated a work with this deed has **dedicated** the work to the public domain by waiving all of his or her rights to the work worldwide under copyright law, including all related and neighboring rights, to the extent allowed by law.\n\nYou can copy, modify, distribute and perform the work, even for commercial purposes, all without asking permission. See [Other Information](#Other%20Information) below.\n\n#### Other Information\n\n  - In no way are the patent or trademark rights of any person affected by CC0, nor are the rights that other persons may have in the work or in how the work is used, such as publicity or privacy rights. \n  - Unless expressly stated otherwise, the person who associated a work with this deed makes no warranties about the work, and disclaims liability for all uses of the work, to the fullest extent permitted by applicable law. \n  - When using or citing the work, you should not imply endorsement by the author or the affirmer.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamuelmarks%2Ftype-correct","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsamuelmarks%2Ftype-correct","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsamuelmarks%2Ftype-correct/lists"}