### Full Example: Setup, Load, and Analyze Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/server.md Demonstrates the typical workflow: setting up a `FileServer`, loading a package file, and performing a semantic pass on the loaded root file. ```julia using StaticLint # Create a server server = StaticLint.setup_server() # Load and analyze a single file root = StaticLint.loadfile(server, "src/MyPackage.jl") StaticLint.semantic_pass(root) ``` -------------------------------- ### Server Setup Function Parameters Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/configuration.md Shows the default parameters for the `setup_server` function, which customizes the analysis environment. ```julia setup_server(env=dirname(Pkg.Types.Context().env.project_file), depot=first(Pkg.depots()), cache=joinpath(dirname(pathof(SymbolServer)), "..", "store")) ``` -------------------------------- ### Example Usage Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/binding.md Demonstrates how to parse code, run semantic analysis, and extract bindings using StaticLint.jl. ```APIDOC ## Example Usage ```julia using StaticLint, CSTParser # Parse some code code = "x = 42" cst = CSTParser.parse(code, true) # Run semantic analysis server = StaticLint.setup_server() file = StaticLint.File("test.jl", code, cst, nothing, server) StaticLint.setroot(file, file) StaticLint.setfile(server, "test.jl", file) StaticLint.semantic_pass(file) # Extract bindings function find_bindings(x) if StaticLint.hasbinding(x) b = StaticLint.bindingof(x) println("Name: $(StaticLint.valof(b.name))") println("Refs: $(length(b.refs))") end if x.args !== nothing for arg in x.args find_bindings(arg) end end end find_bindings(cst) ``` ``` -------------------------------- ### Toplevel State Example Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/state-machines.md Demonstrates the usage of the Toplevel state machine by analyzing a simple Julia code string. This example shows how StaticLint processes code, binds variables, and defers function body analysis. ```julia using StaticLint code = """ x = 1 function foo(y) return x + y end foo(2) """ cst = CSTParser.parse(code, true) server = StaticLint.setup_server() file = StaticLint.File("test.jl", code, cst, nothing, server) StaticLint.setroot(file, file) StaticLint.setfile(server, "test.jl", file) # semantic_pass creates and uses Toplevel internally StaticLint.semantic_pass(file) # At this point: # - x is bound at top level # - foo is bound at top level # - foo's body was added to delayed list ``` -------------------------------- ### Setup Server with Custom Environment Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/configuration.md Configure the StaticLint server to analyze a project in a different directory with a custom package depot. ```julia using StaticLint # Analyze a different project server = StaticLint.setup_server( env = "/path/to/other/project", depot = "/path/to/custom/depot" ) root = StaticLint.loadfile(server, "/path/to/other/project/src/Package.jl") StaticLint.semantic_pass(root) ``` -------------------------------- ### Setup FileServer Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/server.md Initializes a `FileServer` instance, loading symbol information from the Julia depot. This is the primary way to create a server for analysis. ```julia server = StaticLint.setup_server() ``` -------------------------------- ### setup_server Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/lint-interface.md Creates and configures a FileServer with access to installed packages. Initializes a FileServer with an empty file cache, an external environment, and extended method information. ```APIDOC ## Function Signature ```julia setup_server(env=dirname(Pkg.Types.Context().env.project_file), depot=first(Pkg.depots()), cache=joinpath(dirname(pathof(SymbolServer)), "..", "store")) ``` ### Parameters | Parameter | Type | Default | Description | |-----------|------|---------|-------------| | env | `String` | Current project directory | Environment path for loading Project.toml | | depot | `String` | First depot in stack | Julia depot directory containing installed packages | | cache | `String` | SymbolServer cache | Cache directory for symbol information | ### Return Type `FileServer` - A configured server ready for file loading and analysis ### Description Initializes a FileServer with: - An empty file cache (`.files`) - An external environment containing all available packages - Extended method information for type piracy detection ### Example Usage ```julia using StaticLint # Default setup server = StaticLint.setup_server() ``` ``` -------------------------------- ### Example Usage Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/scope.md Demonstrates how to parse Julia code, set up the StaticLint server, and traverse the scope tree to inspect scope information. ```APIDOC ## Example Usage ```julia using StaticLint, CSTParser code = """ module MyModule x = 42 function foo(y) z = x + y return z end end """ cst = CSTParser.parse(code, true) server = StaticLint.setup_server() file = StaticLint.File("test.jl", code, cst, nothing, server) StaticLint.setroot(file, file) StaticLint.setfile(server, "test.jl", file) StaticLint.semantic_pass(file) # Walk the scope tree function show_scopes(expr, depth=0) if StaticLint.hasscope(expr) scope = StaticLint.scopeof(expr) indent = " " ^ depth println("\$(indent)Scope (head=$(expr.head)):") for (name, binding) in scope.names println("\$(indent) - \$name") end end if expr.args !== nothing for arg in expr.args show_scopes(arg, depth + 1) end end end show_scopes(cst) ``` ``` -------------------------------- ### Example Usage of traverse Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/traverse.md Demonstrates how to use the traverse function with a sample Julia expression and a StaticLint state machine. ```APIDOC ## Example Usage ```julia using StaticLint # Create a state machine for semantic analysis file = StaticLint.File("test.jl", "a = 1 + 2", CSTParser.parse("a = 1 + 2", true), nothing, server) env = StaticLint.getenv(file, server) StaticLint.setscope!(file.cst, StaticLint.Scope(file.cst)) state = StaticLint.Toplevel(file, [file.path], StaticLint.scopeof(file.cst), false, nothing, [], [], env, server) # Traverse will process child nodes in execution order StaticLint.traverse(file.cst, state) ``` ``` -------------------------------- ### Setup StaticLint Server Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/lint-interface.md Configures and initializes a StaticLint server with a custom environment and depot path. This is the first step before performing any linting operations. ```julia server = StaticLint.setup_server( env = "/path/to/project", depot = "/path/to/depot" ) ``` -------------------------------- ### Add StaticLint Package Source: https://github.com/julia-vscode/staticlint.jl/blob/master/README.md Install the StaticLint package using the Julia package manager. ```julia using Pkg Pkg.add("StaticLint") ``` -------------------------------- ### Example Usage of Traverse Function Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/traverse.md Demonstrates how to set up a state machine and use the `traverse` function to process a Julia expression. ```julia using StaticLint # Create a state machine for semantic analysis file = StaticLint.File("test.jl", "a = 1 + 2", CSTParser.parse("a = 1 + 2", true), nothing, server) env = StaticLint.getenv(file, server) StaticLint.setscope!(file.cst, StaticLint.Scope(file.cst)) state = StaticLint.Toplevel(file, [file.path], StaticLint.scopeof(file.cst), false, nothing, [], [], env, server) # Traverse will process child nodes in execution order StaticLint.traverse(file.cst, state) ``` -------------------------------- ### Method Definition Example Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/binding.md Illustrates how multiple method definitions for a function are handled by creating a root binding and adding subsequent methods to its references. ```julia f() = 1 # Creates root binding for 'f' f(x) = 2 # Resolves to root binding; adds new method to refs f(x, y) = 3 # Resolves to root binding; adds new method to refs ``` -------------------------------- ### Example Usage: Examining Metadata Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/meta.md Demonstrates how to parse code, set up the StaticLint server, and traverse expression nodes to display their associated metadata. ```julia using StaticLint, CSTParser code = "x = 42" cst = CSTParser.parse(code, true) server = StaticLint.setup_server() file = StaticLint.File("test.jl", code, cst, nothing, server) StaticLint.setroot(file, file) StaticLint.setfile(server, "test.jl", file) StaticLint.semantic_pass(file) # Examine metadata function show_metadata(x, depth=0) if StaticLint.hasmeta(x) indent = " " ^ depth meta = x.meta if StaticLint.hasbinding(meta) binding = StaticLint.bindingof(meta) println("\$(indent)Binding: $(StaticLint.valof(binding.name))") end if StaticLint.hasref(meta) ref = meta.ref println("\$(indent)Reference to: $ref") end if StaticLint.hasscope(meta) println("\$(indent)Introduces scope") end if meta.error !== nothing println("\$(indent)Error: $(meta.error)") end end if x.args !== nothing for arg in x.args show_metadata(arg, depth + 1) end end end show_metadata(cst) ``` -------------------------------- ### StaticLint Usage: All Checks Enabled Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/configuration.md Example of running StaticLint with all checks enabled by default. This performs all 10 available checks. ```julia using StaticLint code = "x = undefined_var" cst = StaticLint.lint_string(code) # All 10 checks are performed ``` -------------------------------- ### Example: Custom LintOptions Configuration Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/lint-interface.md Shows how to create a LintOptions object to enable only specific linting checks. `nothing` can be used to retain the default setting for a check. ```julia # Enable only specific checks opts = StaticLint.LintOptions( true, # check calls false, # skip iterator checks true, # check nothing comparisons false, # skip const if checks nothing, # use default for lazy nothing, # use default for datadecl nothing, # use default for typeparam nothing, # use default for modname nothing, # use default for pirates nothing # use default for useoffuncargs ) StaticLint.check_all(cst, opts, env) ``` -------------------------------- ### Complete StaticLint Workflow Example Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/utilities.md Demonstrates a full workflow using StaticLint and CSTParser, including parsing code, setting up the server, analyzing the file, and inspecting bindings, scopes, and errors within the parsed Abstract Syntax Tree (AST). ```julia using StaticLint, CSTParser code = """ module MyModule x = 42 y = x + 1 end """ # Parse and analyze cst = CSTParser.parse(code, true) server = StaticLint.setup_server() file = StaticLint.File("test.jl", code, cst, nothing, server) StaticLint.setroot(file, file) StaticLint.setfile(server, "test.jl", file) StaticLint.semantic_pass(file) # Use utilities function inspect(x, depth=0) indent = " " ^ depth # Check for binding if StaticLint.hasbinding(x) b = StaticLint.bindingof(x) println("\$(indent)Binding: $(StaticLint.valof(b.name))") end # Check for scope if StaticLint.hasscope(x) scope = StaticLint.scopeof(x) println("\$(indent)Scope with: $(join(keys(scope.names), ", "))") end # Check for error if StaticLint.haserror(x) error_code = StaticLint.errorof(x) println("\$(indent)Error: \$error_code") end # Recurse if x.args !== nothing for arg in x.args inspect(arg, depth + 1) end end end inspect(cst) ``` -------------------------------- ### Example: Running All Lint Checks Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/lint-interface.md Demonstrates the complete process of setting up StaticLint, parsing code, performing a semantic pass, and running all lint checks on a simple Julia code snippet. ```julia using StaticLint, CSTParser code = "if true; x = 1; end" cst = CSTParser.parse(code, true) server = StaticLint.setup_server() file = StaticLint.File("test.jl", code, cst, nothing, server) StaticLint.setroot(file, file) StaticLint.setfile(server, "test.jl", file) StaticLint.semantic_pass(file) env = StaticLint.getenv(file, server) opts = StaticLint.LintOptions() # All checks enabled StaticLint.check_all(cst, opts, env) ``` -------------------------------- ### Complex Resolution Example with MissingRef in Julia Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/resolution.md This example demonstrates a complex resolution scenario within nested modules, highlighting a `MissingRef` error when trying to access an undefined variable `data`. ```julia using StaticLint code = """ module MyModule import JSON function process(data::JSON.JSONObject) result = JSON.parse(data) return result end module Utils using ..MyModule function helper() return MyModule.process(data) # data not defined - MissingRef end end end """ cst, hints = StaticLint.lint_string(code; gethints=true) for (expr, msg) in hints if contains(msg, "MissingRef") println("Unresolved: $msg") end end # Output: Unresolved reference to 'data' at... ``` -------------------------------- ### Setup Default FileServer Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/lint-interface.md Initializes a FileServer with default configurations for environment, depot, and cache paths. This server is used by linting functions to manage file context and symbol information. ```julia using StaticLint # Default setup server = StaticLint.setup_server() ``` -------------------------------- ### getroot Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/server.md Gets the root file of the project associated with a given file. ```APIDOC ## getroot ### Description Gets the root file of the project associated with a given file. ### Method `getroot(file::File) -> Union{Nothing,File}` ### Parameters #### Path Parameters - **file** (File) - The file object. ### Returns - **Union{Nothing,File}** - The root file, or nothing if the file is the root. ``` -------------------------------- ### Feature Flag Example Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/configuration.md Demonstrates the internal NO_NEW_BINDINGS feature flag used to control macro behavior during semantic analysis. ```julia const NO_NEW_BINDINGS = 0x1 ``` -------------------------------- ### Example Usage: Walking the Scope Tree Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/scope.md Demonstrates how to parse Julia code, set up the StaticLint server, and traverse the scope tree to print information about scopes and their bindings. This is useful for analyzing code structure and variable visibility. ```julia using StaticLint, CSTParser code = """ module MyModule x = 42 function foo(y) z = x + y return z end end """ cst = CSTParser.parse(code, true) server = StaticLint.setup_server() file = StaticLint.File("test.jl", code, cst, nothing, server) StaticLint.setroot(file, file) StaticLint.setfile(server, "test.jl", file) StaticLint.semantic_pass(file) # Walk the scope tree function show_scopes(expr, depth=0) if StaticLint.hasscope(expr) scope = StaticLint.scopeof(expr) indent = " " ^ depth println("\$(indent)Scope (head=$(expr.head)):") for (name, binding) in scope.names println("\$(indent) - "name) end end if expr.args !== nothing for arg in expr.args show_scopes(arg, depth + 1) end end end show_scopes(cst) ``` -------------------------------- ### Check and Get File Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/server.md Checks if a file is loaded in the server and retrieves it if it exists. This is useful for avoiding redundant loading. ```julia if StaticLint.hasfile(server, "src/MyModule.jl") file = StaticLint.getfile(server, "src/MyModule.jl") end ``` -------------------------------- ### File Root Operations Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/server.md Gets the root file of the project for a given file, or sets a new root file reference. ```julia # Root file operations StaticLint.getroot(file::File) -> Union{Nothing,File} StaticLint.setroot(file::File, root::File) -> File ``` -------------------------------- ### File Server Association Operations Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/server.md Gets the parent `AbstractServer` for a `File`, or associates a `File` with a specific `FileServer`. ```julia # Server operations StaticLint.getserver(file::File) -> AbstractServer StaticLint.setserver(file::File, server::FileServer) -> File ``` -------------------------------- ### Execution Order Examples for Traverse Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/traverse.md Illustrates the execution order of child nodes processed by the `traverse` function for various Julia syntax constructs. ```julia # Assignment: RHS first, then LHS a = b # traverse(b), traverse(a) ``` ```julia # Where clause: type parameters first, then base f(x::T) where T <: Number # process where, then f(x::T) ``` ```julia # Generator: range first, then body (x^2 for x in 1:10) # process (1:10), then (x^2) ``` ```julia # Call with keyword parameters: positional first f(1, 2; key=3) # process 1, 2, then key=3 ``` -------------------------------- ### Custom Check Execution Example Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/configuration.md Run specific StaticLint checks on a string of code or all checks with custom options, like disabling type piracy detection. ```julia using StaticLint, CSTParser code = "x = 1; x += 1" cst = StaticLint.lint_string(code) server = StaticLint.setup_server() file = StaticLint.File("test.jl", code, cst, nothing, server) env = StaticLint.getenv(file, server) # Run only specific checks StaticLint.check_call(cst, env) StaticLint.check_for_pirates(cst) # Or run all with options opts = StaticLint.LintOptions(pirates=false) # Skip type piracy StaticLint.check_all(cst, opts, env) ``` -------------------------------- ### Parse and Extract Bindings Example Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/binding.md Parses a Julia code string, performs semantic analysis, and recursively finds and prints information about bindings within the Abstract Syntax Tree. ```julia using StaticLint, CSTParser # Parse some code code = "x = 42" cst = CSTParser.parse(code, true) # Run semantic analysis server = StaticLint.setup_server() file = StaticLint.File("test.jl", code, cst, nothing, server) StaticLint.setroot(file, file) StaticLint.setfile(server, "test.jl", file) StaticLint.semantic_pass(file) # Extract bindings function find_bindings(x) if StaticLint.hasbinding(x) b = StaticLint.bindingof(x) println("Name: $(StaticLint.valof(b.name))") println("Refs: $(length(b.refs))") end if x.args !== nothing for arg in x.args find_bindings(arg) end end end find_bindings(cst) ``` -------------------------------- ### Custom Linting Configuration Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/README.md Configure linting options to enable or disable specific checks, such as const conditions or type piracy. This example also shows parsing code and performing semantic analysis before custom checks. ```julia using StaticLint code = "if true; x = 1; end" cst = CSTParser.parse(code, true) # Run with specific checks opts = StaticLint.LintOptions( constif = true, # Check const conditions pirates = false, # Skip type piracy checks others... = true # Default for other checks ) server = StaticLint.setup_server() file = StaticLint.File("test.jl", code, cst, nothing, server) StaticLint.semantic_pass(file) env = StaticLint.getenv(file, server) StaticLint.check_all(cst, opts, env) ``` -------------------------------- ### Get Root Method Binding Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/utilities.md Retrieves the root binding for a given method. If the function has multiple methods, it returns the first method binding. Otherwise, it returns the binding itself. Useful for tracing method overloads back to their original definition. ```julia get_root_method(b, server) -> Any get_root_method(b::Binding, server) -> Binding ``` -------------------------------- ### setup_server Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/server.md Sets up a FileServer with an external environment, loading symbol information from the Julia depot. ```APIDOC ## setup_server ### Description Sets up a FileServer with an external environment. Returns a `FileServer` with symbol information loaded from the Julia depot. ### Method `setup_server(env=dirname(...), depot=first(...), cache=...) -> FileServer` ### Example ```julia server = StaticLint.setup_server() ``` ``` -------------------------------- ### getpath Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/server.md Gets the absolute file path of a File object. ```APIDOC ## getpath ### Description Gets the absolute file path of a File object. ### Method `getpath(file::File) -> String` ### Parameters #### Path Parameters - **file** (File) - The file object. ### Returns - **String** - The absolute file path. ``` -------------------------------- ### Server and Files Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/README.md Manages the project's file structure and server instance. `setup_server()` initializes the server, and `FileServer` and `File` represent the server and individual files within the project, respectively. ```APIDOC ## `setup_server()` ### Description Initializes and returns a `FileServer` instance for managing project files during analysis. ### Method `setup_server()` ### Parameters None. ### Request Example ```julia using StaticLint server = StaticLint.setup_server() ``` ### Response - **server** (FileServer) - An initialized file server instance. ``` ```APIDOC ## `loadfile(server, filepath)` ### Description Loads a file into the `FileServer` and returns its AST root node. ### Method `loadfile(server, filepath)` ### Parameters - **server** (FileServer) - The file server instance. - **filepath** (String) - The path to the file to load. ### Request Example ```julia using StaticLint server = StaticLint.setup_server() root = StaticLint.loadfile(server, "src/MyPackage.jl") ``` ### Response - **root** (AST Node) - The root of the Abstract Syntax Tree for the loaded file. ``` -------------------------------- ### Missing Reference Error Example in Julia Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/resolution.md Demonstrates a `MissingRef` error when an identifier, such as `undefined_variable`, cannot be resolved because it is not found in any scope. ```julia x = undefined_variable # Error - undefined_variable not found ``` -------------------------------- ### Relative Import Error Example in Julia Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/resolution.md Illustrates a `RelativeImportTooManyDots` error where a relative import has more dots than the available parent scope depth. ```julia module A import ...foo # Error - only 1 parent scope available end ``` -------------------------------- ### StaticLint Usage: Disable Specific Checks Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/configuration.md Example of disabling type piracy and nothing comparison checks while keeping others enabled. ```julia # Enable all except type piracy and nothing comparison checks opts = StaticLint.LintOptions( call = true, iter = true, nothingcomp = false, # Skip constif = true, lazy = true, datadecl = true, typeparam = true, modname = true, pirates = false, # Skip useoffuncargs = true ) StaticLint.check_all(cst, opts, env) ``` -------------------------------- ### Toplevel State Initialization Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/state-machines.md Initializes the Toplevel state machine, setting up the environment, root scope, and initial lists for delayed and resolveonly expressions. ```julia env = getenv(file, server) setscope!(getcst(file), Scope(nothing, getcst(file), Dict(), Dict{Symbol,Any}(...), nothing)) state = Toplevel( file, # The file being analyzed [getpath(file)], # Initial included files scopeof(getcst(file)), # Root scope modified_expr === nothing, # in_modified_expr modified_expr, # modified_exprs list EXPR[], # Empty delayed list EXPR[], # Empty resolveonly list env, # External environment server, # The file server 0 # flags ) ``` -------------------------------- ### LintOptions Partial Configuration with Nothing Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/configuration.md Demonstrates using `nothing` to specify default values for certain LintOptions fields while customizing others. ```julia LintOptions(true, false, nothing, true, nothing, ...) ``` -------------------------------- ### Analyze Julia Project Files Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/README.md Set up a server, load project files, and perform semantic analysis on the entire project. This allows for checking all loaded files and retrieving linting issues. ```julia using StaticLint # Analyze entire project server = StaticLint.setup_server() root = StaticLint.loadfile(server, "src/MyPackage.jl") StaticLint.semantic_pass(root) # Check all loaded files for (path, file) in server.files println("Analyzed: $path") end # Get hints from all files root, hints = StaticLint.lint_file("src/MyPackage.jl"; gethints=true) if !isempty(hints) println("Found $(length(hints)) issues") end ``` -------------------------------- ### Run StaticLint on a Julia Project Source: https://github.com/julia-vscode/staticlint.jl/wiki/Example This snippet demonstrates the complete workflow for running StaticLint on a Julia project. It includes setting up SymbolServer, loading project files, performing scope analysis, and executing lint checks. Ensure the `sscachedir` and `envdir` paths are correctly configured for your environment. ```julia using StaticLint, SymbolServer # Where the SymbolServer cache files are stored. This can be any dir, the default is ".../SymbolServer/store" where ever that is. (Mine is set to the cache used by vscode) const sscachedir = "/home/zac/.config/Code/User/globalStorage/julialang.language-julia/symbolstorev2/" # Directory of the environment you want to load, this must have a Manifest.toml file. const envdir = "/home/zac/.julia/environments/v1.5/" # This is the 'root' file of the project. All other files will (hopefully!) be loaded subsequently through analysis of calls to `include`. rootfile = "/home/zac/.julia/dev/StaticLint/src/StaticLint.jl" function f(rootfile) # This will hold the files of the loaded project server = StaticLint.FileServer(); # Get symbols from all packages in the environment (this may take a while if sscachedir is new/empty) _,server.symbolserver = SymbolServer.getstore(SymbolServerInstance("", sscachedir), envdir) # Some internal fiddling to make connect references between packages within the environment. server.symbol_extends = SymbolServer.collect_extended_methods(server.symbolserver) # Loads and parses the file f = StaticLint.loadfile(server, rootfile) # StaticLint's main run- finding variables, scopes, etc. StaticLint.scopepass(f) # Run lint checks. hints = Dict() slopts = StaticLint.LintOptions(:) for (path, file) in server.files StaticLint.check_all(file.cst, slopts, server) hints[path] = StaticLint.collect_hints(file.cst, server) end for (p, hs) in hints println(p) for (offset, x) in hs if StaticLint.haserror(x) && StaticLint.errorof(x) isa StaticLint.LintCodes println(" ", StaticLint.LintCodeDescriptions[StaticLint.errorof(x)], " at ", offset) else # missing reference println(" Missing reference for `$(StaticLint.CSTParser.valof(x))` at ", offset) end end end end ``` -------------------------------- ### Run Semantic Analysis on a Julia Project Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/semantic-pass.md This snippet demonstrates how to set up a server, load a Julia file, and run the `semantic_pass` function for static code analysis. It then shows how to traverse the resulting CST to access binding information. ```julia using StaticLint, CSTParser # Create a file server server = StaticLint.setup_server() # Load a Julia file root = StaticLint.loadfile(server, "src/MyPackage.jl") # Run semantic analysis StaticLint.semantic_pass(root) # Access analysis results through metadata on the CST function show_bindings(expr) if StaticLint.hasbinding(expr) binding = StaticLint.bindingof(expr) println("Binding: $(binding.name)") end if expr.args !== nothing for arg in expr.args show_bindings(arg) end end end show_bindings(root.cst) ``` -------------------------------- ### loadfile Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/server.md Loads a file from disk, parses it, creates a File object, and stores it in the server. ```APIDOC ## loadfile ### Description Loads a file from disk, parses it, creates a File object, and stores it in the server. Throws an exception if the file cannot be read. ### Method `loadfile(server::FileServer, path::String) -> File` ### Parameters #### Path Parameters - **server** (FileServer) - The server instance. - **path** (String) - The path of the file to load. ### Returns - **File** - The loaded file object. ### Example ```julia root = StaticLint.loadfile(server, "src/MyPackage.jl") ``` ``` -------------------------------- ### Get Error Code from Expression Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/utilities.md Retrieves the lint error code associated with an expression. Returns the error code if present, otherwise returns nothing. ```julia errorof(x::EXPR) -> Union{LintCodes, Nothing} ``` -------------------------------- ### Get All References to a Variable Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/README.md Retrieves a list of all references (uses) for a given variable's binding. The `refs` field on the binding object contains this information. ```julia binding = bindingof(name_expr) all_references = binding.refs ``` -------------------------------- ### Access Reference Metadata Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/README.md Gets the reference associated with an identifier expression, indicating where it points to (e.g., a binding, a module). This metadata is attached to the AST node. ```julia expr.meta.ref # The reference for this identifier ``` -------------------------------- ### Meta Constructor Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/meta.md Creates an empty metadata structure with all fields initialized to nothing. ```julia Meta() # Create empty metadata with all fields as nothing ``` -------------------------------- ### Retrieve All Methods from Binding Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/binding.md Demonstrates how to extract all method definitions associated with a function's root binding. ```julia binding = bindingof(f_identifier) methods = [StaticLint.get_method(ref) for ref in binding.refs if StaticLint.get_method(ref) !== nothing] ``` -------------------------------- ### Method Definitions Handling Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/binding.md Explains how multiple method definitions for a function are handled by the Binding system, with the first method creating a root binding and subsequent methods being added to its references. ```APIDOC ## Method Definitions For functions with multiple methods, the first method's binding becomes the "root" binding. Subsequent method definitions resolve to the root method's binding, and their method expressions are added to the root binding's `refs` list. Example: ```julia f() = 1 # Creates root binding for 'f' f(x) = 2 # Resolves to root binding; adds new method to refs f(x, y) = 3 # Resolves to root binding; adds new method to refs ``` To get all methods: ```julia binding = bindingof(f_identifier) methods = [StaticLint.get_method(ref) for ref in binding.refs if StaticLint.get_method(ref) !== nothing] ``` ``` -------------------------------- ### StaticLint Usage: Partial Specification Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/configuration.md Demonstrates setting only specific LintOptions fields and relying on defaults for the rest. ```julia # Set only the options we care about, use defaults for the rest opts = StaticLint.LintOptions(true, false, nothing, true, nothing, nothing, nothing, nothing, nothing, nothing) # Results in: call=T, iter=F, nothingcomp=T (default), constif=T, lazy=T (default), ... ``` -------------------------------- ### Working with Bindings Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/README.md Provides utilities for inspecting and working with variable bindings within the code's Abstract Syntax Tree (AST). `hasbinding()`, `bindingof()`, and `valof()` are key functions. ```APIDOC ## `hasbinding(x)` ### Description Checks if an AST node `x` has an associated binding. ### Method `hasbinding(x)` ### Parameters - **x** (AST Node) - The AST node to check. ### Request Example ```julia using StaticLint # Assume cst is an AST node if StaticLint.hasbinding(cst) println("Node has a binding.") end ``` ### Response - **Bool** - `true` if the node has a binding, `false` otherwise. ``` ```APIDOC ## `bindingof(x)` ### Description Retrieves the `Binding` object associated with an AST node `x`. ### Method `bindingof(x)` ### Parameters - **x** (AST Node) - The AST node. ### Request Example ```julia using StaticLint # Assume cst has a binding b = StaticLint.bindingof(cst) ``` ### Response - **Binding** - The `Binding` object associated with the node. ``` ```APIDOC ## `valof(symbol)` ### Description Retrieves the string value of a symbol. ### Method `valof(symbol)` ### Parameters - **symbol** (Symbol) - The symbol to get the value from. ### Request Example ```julia using StaticLint # Assume b is a Binding object println("Binding name: ", StaticLint.valof(b.name)) ``` ### Response - **String** - The string representation of the symbol. ``` -------------------------------- ### Get Error Code and Description Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/README.md Retrieve the error code for an expression and its corresponding descriptive message from the LintCodeDescriptions dictionary. This is useful for understanding and reporting linting issues. ```julia error_code = StaticLint.errorof(expr) # Get code description = StaticLint.LintCodeDescriptions[error_code] # Get message ``` -------------------------------- ### File Too Big for Include Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/errors.md Including files larger than `LARGE_FILE_LIMIT` (2MB) is flagged to prevent performance issues. This example shows an `include()` statement for a file exceeding this limit. ```julia include("huge_file_5gb.jl") # FileTooBig - exceeds limit ``` -------------------------------- ### LintOptions Shorthand for All Enabled Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/configuration.md A shorthand constructor for LintOptions that enables all linting checks. ```julia LintOptions(:) ``` -------------------------------- ### retrieve_delayed_scope Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/utilities.md Gets the scope for a delayed evaluation context in Julia. For function/macro definitions, it returns the parent scope; otherwise, it calls `retrieve_scope`. Used for analyzing function bodies. ```APIDOC ## retrieve_delayed_scope ### Description Get the scope for a delayed evaluation context. ### Signature ```julia retrieve_delayed_scope(x::EXPR) -> Union{Scope, Nothing} ``` ### Behavior: - For function/macro definitions: returns parent scope - Otherwise calls `retrieve_scope` - Used for analyzing function bodies ``` -------------------------------- ### Simple Binding Constructor Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/binding.md Creates a binding using an expression 'x' for both the name and value, initializing an empty list for references. ```julia Binding(x::EXPR) ``` -------------------------------- ### Lint File With Hints Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/lint-interface.md Analyzes a Julia file from disk and returns the root File object along with a list of error/hint messages from all loaded files. Useful for comprehensive project-wide diagnostics. ```julia using StaticLint # With error collection root, errors = StaticLint.lint_file("src/MyPackage.jl"; gethints=true) # Show errors by file current_file = "" for (expr, message) in errors # Message includes " at offset ... of /path/to/file.jl" println(message) end ``` -------------------------------- ### Load File from Disk Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/server.md Loads a file from the filesystem, parses its content into a `File` object, and stores it within the `FileServer`. Throws an error if the file cannot be read. ```julia root = StaticLint.loadfile(server, "src/MyPackage.jl") ``` -------------------------------- ### Retrieve Scope for Expression Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/utilities.md Gets the scope associated with an expression. If the expression does not have an immediate scope, it walks up the parent chain to find the nearest enclosing scope. Returns nothing if no scope is found. ```julia retrieve_scope(x::EXPR) -> Union{Scope, Nothing} ``` -------------------------------- ### Custom Configuration Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/README.md Allows users to customize linting behavior by providing a `LintOptions` struct. This enables fine-grained control over which checks are performed. ```APIDOC ## `LintOptions(; kwargs...)` ### Description Constructs a `LintOptions` object to configure the linting process. Various keyword arguments control specific checks. ### Method `LintOptions(; kwargs...)` ### Parameters - **constif** (Bool) - Optional. If `true`, checks `const` conditions. - **pirates** (Bool) - Optional. If `true`, enables type piracy checks. - **others...** (Bool) - Optional. Default for other checks. ### Request Example ```julia using StaticLint opts = StaticLint.LintOptions( constif = true, pirates = false ) ``` ### Response - **opts** (LintOptions) - A configured lint options object. ``` ```APIDOC ## `check_all(cst, opts, env)` ### Description Performs all configured lint checks on the given AST node using the specified options and environment. ### Method `check_all(cst, opts, env)` ### Parameters - **cst** (AST Node) - The Abstract Syntax Tree node to check. - **opts** (LintOptions) - The linting options to apply. - **env** (Environment) - The analysis environment. ### Request Example ```julia using StaticLint # Assume cst, opts, and env are already defined StaticLint.check_all(cst, opts, env) ``` ### Response This function performs checks and may report issues. It does not explicitly return a value. ``` -------------------------------- ### Retrieve Delayed Scope for Evaluation Context Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/utilities.md Gets the scope for a delayed evaluation context. For function or macro definitions, it returns the parent scope. Otherwise, it calls `retrieve_scope`. This is used for analyzing function bodies. ```julia retrieve_delayed_scope(x::EXPR) -> Union{Scope, Nothing} ``` -------------------------------- ### setserver Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/server.md Sets the parent server for a given file. ```APIDOC ## setserver ### Description Sets the parent server for a given file. ### Method `setserver(file::File, server::FileServer) -> File` ### Parameters #### Path Parameters - **file** (File) - The file object. - **server** (FileServer) - The server to set as parent. ### Returns - **File** - The modified file object. ``` -------------------------------- ### AbstractServer Interface Source: https://github.com/julia-vscode/staticlint.jl/blob/master/README.md An AbstractServer is required to hold files within a project and provide access to user-installed packages. Implementations must support these functions. ```APIDOC ## AbstractServer Functions ### `StaticLint.hasfile(server, path)::Bool` #### Description Checks if the server contains a file matching the given path. ### `StaticLint.getfile(server, path)::AbstractFile` #### Description Retrieves the file at the specified path. Assumes the server already has this file. ### `StaticLint.setfile(server, path, file)::AbstractFile` #### Description Stores the provided `file` in the server under the given `path`, returning the stored file. ### `StaticLint.canloadfile(server, path)::Bool` #### Description Determines if the server is capable of loading the file denoted by `path`, potentially from an external source. ### `StaticLint.loadfile(server, path)::AbstractFile` #### Description Loads the file at the specified `path` from an external source, such as the hard drive. ### `StaticLint.getsymbolserver(server)::Dict{String,SymbolServer.ModuleStore}` #### Description Retrieves the server's depot of loadable packages. ``` -------------------------------- ### Workflow for Checking Issues Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/lint-interface.md A common workflow to lint a file and report any found issues. This snippet demonstrates how to check if the hints list is empty and iterate through it if issues are present. ```julia using StaticLint # Simple check for issues root, hints = lint_file("src/Package.jl"; gethints=true) # hints is a vector of (expr, message) tuples if !isempty(hints) println("Found $(length(hints)) issues:") for (expr, msg) in hints println(" - $msg") end else println("No issues found") end ``` -------------------------------- ### getserver Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/server.md Retrieves the parent server associated with a given file. ```APIDOC ## getserver ### Description Retrieves the parent server associated with a given file. ### Method `getserver(file::File) -> AbstractServer` ### Parameters #### Path Parameters - **file** (File) - The file object. ### Returns - **AbstractServer** - The parent server. ``` -------------------------------- ### Basic Constructor Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/scope.md Constructs a new Scope associated with a given expression, initializing it with empty bindings and no parent. ```APIDOC ## Constructors ### Basic Constructor ```julia Scope(expr::EXPR) ``` Creates a scope for the given expression with empty bindings and no parent scope. ``` -------------------------------- ### Use Correct Comparison for Nothing with NothingEquality Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/errors.md Avoid using `==` to compare with `nothing`. Instead, use `===` for strict equality or `isnothing(x)` for a more idiomatic check. This prevents potential misunderstandings of equality. ```julia if x == nothing # NothingEquality - use === or isnothing instead end ``` -------------------------------- ### Binding Constructors Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/binding.md Provides constructors for creating Binding objects, including a simple constructor and a full constructor with all fields. ```APIDOC ## Constructors ### Simple Constructor ```julia Binding(x::EXPR) ``` Creates a binding with the name extracted from `x`, using `x` as the value, and initializing the refs list as empty. ### Full Constructor ```julia Binding(name, val, type, refs) -> Binding Binding(name, val, type, refs, is_public) -> Binding ``` ``` -------------------------------- ### Load and Analyze File Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/lint-interface.md Loads a Julia file into the StaticLint server and performs a semantic pass for analysis. This prepares the file for linting checks. ```julia root = StaticLint.loadfile(server, "/path/to/file.jl") StaticLint.semantic_pass(root) ``` -------------------------------- ### Iterate Through Server Files Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/server.md Iterate over all files loaded by the server, printing the path of each loaded file. This is useful for understanding the scope of files analyzed by the server. ```julia for (path, file) in server.files println("Loaded: $path") end ``` -------------------------------- ### Access Server Files After Linting Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/lint-interface.md Retrieves the FileServer instance after linting a file, allowing access to all loaded files within the project. Demonstrates how to inspect the server's file cache. ```julia root, hints = StaticLint.lint_file("src/MyPackage.jl"; gethints=true) server = StaticLint.getserver(root) for (path, file) in server.files println("Analyzed: $path") end ``` -------------------------------- ### Use Correct Inequality for Nothing with NothingNotEq Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/errors.md Avoid using `!=` to compare with `nothing`. Instead, use `!==` for strict inequality or `!isnothing(x)` for a more idiomatic check. This ensures clarity in conditional logic. ```julia if x != nothing # NothingNotEq - use !== or !isnothing instead end ``` -------------------------------- ### LintOptions Constructors Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/lint-interface.md Provides various ways to construct LintOptions objects. This includes a default constructor enabling all checks, a shorthand, and a custom constructor for fine-grained control. ```julia LintOptions() # All checks enabled (default) LintOptions(:) # All checks enabled (shorthand) LintOptions(true, false, true, ...) # Custom configuration LintOptions(true, nothing, true, ...) # nothing means use default ``` -------------------------------- ### AbstractServer Interface Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/types.md Abstract base type for server implementations. Defines required methods for file system interaction and symbol server access. ```julia # Abstract Interfaces ### AbstractServer Abstract base type for server implementations. Required methods: - `hasfile(server, path)::Bool` - `getfile(server, path)::AbstractFile` - `setfile(server, path, file)::AbstractFile` - `canloadfile(server, path)::Bool` - `loadfile(server, path)::AbstractFile` - `getsymbolserver(server)::Dict` ``` -------------------------------- ### setfile Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/server.md Stores a file in the server. ```APIDOC ## setfile ### Description Stores a file in the server. ### Method `setfile(server::FileServer, path::String, file::File) -> File` ### Parameters #### Path Parameters - **server** (FileServer) - The server instance. - **path** (String) - The path where the file will be stored. - **file** (File) - The file object to store. ### Returns - **File** - The stored file object. ### Example ```julia f = StaticLint.File("src/test.jl", code, cst, nothing, server) StaticLint.setfile(server, "src/test.jl", f) ``` ``` -------------------------------- ### Full Binding Constructor Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/binding.md Constructs a Binding with specified name, value, type, and references, optionally including a public flag. ```julia Binding(name, val, type, refs) -> Binding Binding(name, val, type, refs, is_public) -> Binding ``` -------------------------------- ### Basic Scope Constructor Source: https://github.com/julia-vscode/staticlint.jl/blob/master/_autodocs/api-reference/scope.md Creates a new Scope instance for a given expression, initializing it with empty bindings and no parent scope. ```julia Scope(expr::EXPR) ``` -------------------------------- ### Import StaticLint Module Source: https://github.com/julia-vscode/staticlint.jl/blob/master/README.md Import the StaticLint module into your Julia session to use its functionalities. ```julia using StaticLint ```