{"id":13607997,"url":"https://github.com/jordanlewis/gcassert","last_synced_at":"2025-05-16T03:02:19.801Z","repository":{"id":39618290,"uuid":"275647768","full_name":"jordanlewis/gcassert","owner":"jordanlewis","description":"Assert your Go code is inlined and bounds-check eliminated","archived":false,"fork":false,"pushed_at":"2025-04-30T16:46:44.000Z","size":67,"stargazers_count":257,"open_issues_count":3,"forks_count":14,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-30T17:47:28.653Z","etag":null,"topics":["go","golang"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jordanlewis.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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}},"created_at":"2020-06-28T18:47:31.000Z","updated_at":"2025-04-30T16:46:48.000Z","dependencies_parsed_at":"2024-01-30T21:46:03.790Z","dependency_job_id":"13040b1b-5f31-4914-a1f6-c8e840947aa8","html_url":"https://github.com/jordanlewis/gcassert","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jordanlewis%2Fgcassert","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jordanlewis%2Fgcassert/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jordanlewis%2Fgcassert/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jordanlewis%2Fgcassert/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jordanlewis","download_url":"https://codeload.github.com/jordanlewis/gcassert/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254459077,"owners_count":22074604,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["go","golang"],"created_at":"2024-08-01T19:01:23.436Z","updated_at":"2025-05-16T03:02:19.793Z","avatar_url":"https://github.com/jordanlewis.png","language":"Go","funding_links":[],"categories":["Compiling"],"sub_categories":[],"readme":"# gcassert\n\ngcassert is a program for making assertions about compiler decisions in\nGo programs, via inline comment directives like `//gcassert:inline`.\n\nCurrently supported [directives](#directives):\n\n- `//gcassert:inline` to assert function callsites are inlined\n- `//gcassert:bce` to assert bounds checks are eliminated\n- `//gcassert:noescape` to assert variables don't escape to the heap\n\n## Example\n\nGiven a file `foo.go`:\n\n```go\npackage foo\n\nfunc addOne(i int) int {\n    return i+1\n}\n\n//gcassert:inline\nfunc addTwo(i int) int {\n    return i+1\n}\n\nfunc a(ints []int) int {\n    var sum int\n    for i := range ints {\n        //gcassert:bce,inline\n        sum += addOne(ints[i])\n\n        sum += addTwo(ints[i]) //gcassert:bce\n\n        sum += ints[i] //gcassert:bce\n    }\n    return sum\n}\n```\n\nThe inline `//gcassert` directive will cause `gcassert` to fail if the line\n`sum += addOne(ints[i])` is either not inlined or contains bounds checks.\n\nA `//gcassert:inline` directive on a function will cause `gcassert` to fail\nif any of the callers of that function do not get inlined.\n\n`//gcassert` comments expect a comma-separated list of directives after\n`//gcassert:`. They can be included above the line in question or after, as an\ninline comment.\n\n## Installation\n\nTo get the gcassert binary:\n\n```bash\ngo install github.com/jordanlewis/gcassert/cmd/gcassert@latest\n```\n\nTo get the gcassert library:\n\n```bash\ngo get github.com/jordanlewis/gcassert\n```\n\n## Usage\n\n### As a binary\n\nRun gcassert on packages containing gcassert directives, like this:\n\n```bash\ngcassert ./package/path\n```\n\nThe program will output all lines that had a gcassert directive that wasn't\nrespected by the compiler.\n\nFor example, running on the testdata directory in this library will produce the\nfollowing output:\n\n```bash\n$ gcassert ./testdata\ntestdata/noescape.go:21:        foo := foo{a: 1, b: 2}: foo escapes to heap:\ntestdata/bce.go:8:      fmt.Println(ints[5]): Found IsInBounds\ntestdata/bce.go:17:     sum += notInlinable(ints[i]): call was not inlined\ntestdata/bce.go:19:     sum += notInlinable(ints[i]): call was not inlined\ntestdata/inline.go:45:  alwaysInlined(3): call was not inlined\ntestdata/inline.go:51:  sum += notInlinable(i): call was not inlined\ntestdata/inline.go:55:  sum += 1: call was not inlined\ntestdata/inline.go:58:  test(0).neverInlinedMethod(10): call was not inlined\n```\n\nInspecting each of the listed lines will show a `//gcassert` directive\nthat wasn't upheld when running the compiler on the package.\n\n### As a library\n\ngcassert is runnable as a library as well, for integration into your linter\nsuite. It has a single package function, `gcassert.GCAssert`.\n\nTo use it, pass in an `io.Writer` to which errors will be written and a list of\npaths to check for `gcassert` assertions, like this:\n\n```go\npackage main\n\nimport \"github.com/jordanlewis/gcassert\"\n\nfunc main() {\n    var buf strings.Builder\n    if err := gcassert.GCAssert(\u0026buf, \"./path/to/package\", \"./otherpath/to/package\"); err != nil {\n        // handle non-lint-failure related errors\n        panic(err)\n    }\n    // Output the errors to stdout.\n    fmt.Println(buf.String())\n}\n```\n\n## Directives\n\n\n```\n//gcassert:inline\n```\n\nThe inline directive on a CallExpr asserts that the following statement\ncontains a function that is inlined by the compiler. If the function does not\nget inlined, gcassert will fail.\n\nThe inline directive on a FuncDecl asserts that every caller of that function\nis actually inlined by the compiler.\n\n```\n//gcassert:bce\n```\n\nThe bce directive asserts that the following statement contains a slice index\nthat has no necessary bounds checks. If the compiler adds bounds checks,\ngcassert will fail.\n\n```\n//gcassert:noescape\n```\n\nThe noescape directive asserts that the line it's attached to (meaning,\nwhichever Go AST node is annotated by the comment) produces no \"escaped to\nheap\" messages by the Go compiler.\n\nThe Go compiler emits an \"escaped to heap\" message for a particular line of\ncode if any variables on that line of code are forced to escape.\n\nTypically, the compiler will emit such a message on the line of code that the\nvariable is declared on. This includes method receivers, method arguments, and\nvar declarations.\n\nThis means that the annotation must be attached to the line of code that\nactually contains the variable in question. For a multi-line function\nsignature, for example, the annotation must come on the line that has the\nvariable that would be expected not to escape to the heap:\n\n```go\ntype foo struct { a int }\n\n// This annotation will pass, because f does not escape.\n//gcassert:noescape\nfunc (f foo) returnA(\n// This annotation will fail, because a will escape to the heap.\n//gcassert:noescape\n    a int,\n) *int {\n    return \u0026a\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjordanlewis%2Fgcassert","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjordanlewis%2Fgcassert","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjordanlewis%2Fgcassert/lists"}