class Analyzer::Go::GoEngine

Direct Known Subclasses

Defined in:

analyzer/engines/go_engine.cr

Class Method Summary

Instance Method Summary

Instance methods inherited from class Analyzer

analyze analyze, base_path : String base_path, base_paths : Array(String) base_paths, callees_needed? : Bool callees_needed?, logger : NoirLogger logger, parallel_analyze(channel : Channel(String), &block : String -> Nil) parallel_analyze, read_file_content(path : String) : String read_file_content, result : Array(Endpoint) result, url : String url

Constructor methods inherited from class Analyzer

new(options : Hash(String, YAML::Any)) new

Macros inherited from class Analyzer

define_getter_methods(names) define_getter_methods

Instance methods inherited from module FileHelper

all_files : Array(String) all_files, get_files_by_extension(extension : String) : Array(String) get_files_by_extension, get_files_by_prefix(prefix : String) : Array(String) get_files_by_prefix, get_files_by_prefix_and_extension(prefix : String, extension : String) : Array(String) get_files_by_prefix_and_extension, get_public_dir_files(base_path : String, folder : String) : Array(String) get_public_dir_files, get_public_files(base_path : String, anchors : Array(String) = ["shard.yml", "Gemfile"]) : Array(String) get_public_files, populate_channel_with_files(channel : Channel(String)) populate_channel_with_files, populate_channel_with_filtered_files(channel : Channel(String), extension : String)
populate_channel_with_filtered_files(channel : Channel(String), extensions : Array(String))
populate_channel_with_filtered_files

Class Method Detail

def self.go_test_file?(path : String) : Bool #

*_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.


[View source]

Instance Method Detail

def add_param_to_endpoint(param : Param, endpoint : Endpoint) #

[View source]
def add_static_path_if_valid(static_path : Hash(String, String), public_dirs : Array(Hash(String, String))) #

[View source]
def collect_package_function_bodies(file_contents : Hash(String, String)) : Hash(String, Hash(String, Noir::GoCalleeExtractor::FunctionBody)) #

--- 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.


[View source]
def collect_package_groups_ts(group_method : String = "Group") : Tuple(Hash(String, Hash(String, String)), Hash(String, String)) #

--- 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.


[View source]
def read_package_file_contents : Hash(String, String) #

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.


[View source]
def resolve_public_dirs(public_dirs : Array(Hash(String, String))) #

[View source]
def resolve_public_dirs_with_glob(public_dirs : Array(Hash(String, String))) #

[View source]
def ts_function_bodies_for_directory(package_function_bodies : Hash(String, Hash(String, Noir::GoCalleeExtractor::FunctionBody)), dir : String) : Hash(String, Noir::GoCalleeExtractor::FunctionBody) #

Returns the cross-file function-body map for the given directory, or an empty map when the directory has no captured functions.


[View source]
def ts_groups_for_directory(package_groups : Hash(String, Hash(String, String)), dir : String) : Hash(String, String) #

Returns the cross-file group map for the given directory, or an empty map when the directory has no registered groups.


[View source]