Analyzer::Go::GoEngine
Inherits Analyzer < FileHelper < Reference < Object
Constants
Class methods
*_test.go is Go's hard-wired build-tag for test-only source.
go build excludes these files entirely; only go test pulls
them in. Real route handlers never live there, but framework
repos (echo, chi, gin) park hundreds of e.GET("/...", ...)
calls in *_test.go to exercise the router. Skip both in the
cross-file pre-passes (so test-file groups don't pollute the
production group map) and in each analyzer's per-file loop.
Also skip Go's toolchain-ignored directory prefixes: any
path component starting with _ (_examples/, _assets/,
_testdata/) is excluded by go build/go list outright.
kataras/iris alone parks 392 phantom endpoints under
_examples/...; they're documented apps, not production
routes the framework ships.
Takes the scan-base-relative path (Analyzer#base_relative_path),
never the absolute one. Go's toolchain rule is relative to the
module, so on an absolute path a single _-prefixed directory
anywhere above the scan base — ~/_work/repo on a self-hosted CI
runner — excluded every .go file in the project.
relative_path from base_relative_path is /-rooted, so "/_"
is exactly "a path segment starts with _" without the per-call
split allocation. The leading-_ check covers a caller that
passes an unrooted relative path.
Blanks out // line comments and /* */ block comments, replacing
them with spaces so every real line number stays put for PathInfo
reporting. Without this a commented-out call reads as a live one —
a // serveCmd.Flags().StringVar(&tok, "secret-token", ...) note
registered a flag that the binary does not accept.
All three Go string forms are tracked so a // or /* inside a
literal is never read as a comment opener: interpreted strings
("...", backslash escapes), rune literals ('.'), and raw
strings (`...`) — the last take no escapes and may span
newlines, which is why a shared C-family stripper is not enough.
Instance methods
Builds {import_path => {function_name => body}} for local Go
packages under the configured base paths. This is gated on callee
demand and reuses package_function_bodies, so default route scans
do not pay for go.mod discovery. It lets generated routers like
Hertz resolve feed.Feed when feed imports a sibling package from
the same module.
Builds {import_path => {method_name => [body, ...]}} for local Go
packages under the configured base paths. This complements
collect_import_path_function_bodies for route handlers referenced
as method values on imported package instances, e.g.
handler := api.NewHandler(svc); app.Get("/x", handler.Show).
Per-directory {method_name => [FunctionBody, ...]} map for
controller-style routes whose handler is referenced by method name
(Beego's web.Router("/x", &Ctrl{}, "get:Method")). Lets the
analyzer walk the controller method's body for callees even though
the registration call doesn't pass the handler as an argument.
Gated on callees_needed? so default scans pay nothing.
--- Beego controller-method pre-pass --------------------------------
Builds a per-directory {controller_type => [http_verb_methods]} map
so mapping-less web.Router("/x", &Ctrl{}) registrations resolve to
the exact methods the controller implements. Keyed by directory
because Beego controllers and their router registrations share a Go
package (== directory); a controller defined in a sibling file is
still found.
--- Cross-file function body pre-pass --------------------------------
Walks every cached .go source in file_contents and collects
top-level function_declaration nodes into a per-directory map
so cross-file identifier-handler resolution in
Noir::GoCalleeExtractor is O(1) at lookup time. The map is
keyed by directory because Go's name resolution rules are scoped
to a single package (== single directory), so we never have to
worry about cross-package leakage.
--- Tree-sitter group/route pre-pass --------------------------------
Does a cross-file fixpoint over every .go file in each package
directory, extracting group declarations (x := r.Group("/x") and
friends). Returns:
package_groups— per-directory{group_name => resolved_prefix}file_contents— cached source strings keyed by path, so the per-file second pass doesn't read files twice
group_method is the method name used for grouping — "Group" for
Gin/Echo/Fiber/Hertz (default), "Party" for Iris, "Subrouter"
for Mux.
The fixpoint handles the routes.go calling v1.GET(...) under a
v1 := r.Group("/v1") declared in main.go case — iterate until
no new entries land. In-file declarations win over external ones.
import_marker, when given, restricts the cross-file group/engine
pre-pass to files that actually import the framework. Group
variables (v1 := r.Group("/v1")) and root-engine bindings only
ever appear in framework-importing files, so skipping the rest
avoids parsing unrelated .go files — a large saving in mixed
repos (e.g. an example monorepo where most dirs use other routers).
file_contents is still populated for every file so the per-file
route pass and callee pre-pass keep their read cache.
Per-package directories that import a target framework. Some real
projects hide the concrete framework type behind a local interface, so
the file that calls router.GET(...) may not import Gin/Echo itself.
Cheap gate before the tree-sitter route pass. Handler-only files often
import Gin/Echo for *gin.Context / echo.Context, but they cannot emit
endpoints unless they contain a route/static registration call.
Read every .go file once into a {path => source} hash. Used by
analyzers (Goyave) that don't otherwise call
collect_package_groups_ts but still need the file_contents hash
as input to collect_package_function_bodies.
Returns the cross-file controller-method map for the given directory, or an empty map.
Returns the cross-file function-body map for the given directory, or an empty map when the directory has no captured functions.