# Nilaway > We always welcome and love community contributions! Here we share a list of community-maintained projects related to NilAway which may be useful to you. Please direct issues to the corresponding repos --- We always welcome and love community contributions! Here we share a list of community-maintained projects related to NilAway which may be useful to you. Please direct issues to the corresponding repositories, as we cannot provide any support for them. - [nilaway-action](https://github.com/qbaware/nilaway-action): GitHub Action that uses NilAway to check potential nil panics in your repository. --- # Configurations ## General Flags #### `include-pkgs` > Default `""` (all packages are included) A comma-separated list of package prefixes to include for analysis. By default all packages (including standard and 3rd party libraries) will be loaded by the driver and passed to the linters for analysis. This may not be desirable in practice: the errors reported on them cannot be fixed locally, and the overhead for analyzing them is pointless. Hence this flag can be set to include packages that have certain prefixes (e.g., `go.uber.org`), such that only first-party code is analyzed. If a package is excluded from analysis, default nilabilities will be assumed (e.g., functions will be assumed to always return nonnil pointers). > [!WARNING] > Please note that even if a package is excluded from analysis, errors might still be reported on them if the nilness flows happens within the analyzed package, but it includes using a struct from the excluded package. For example, if the analyzed package constructs a struct from the excluded package, assigns a `nil` to a field, and then immediately dereferences the field. In this case, NilAway will report an error for this flow, but the location will be on the field (that resides in the excluded package). To only report errors on the desired packages, please use the error suppression mechanisms specified in the driver ([golangci-lint](https://golangci-lint.run/usage/false-positives/), [nogo](https://github.com/bazelbuild/rules_go/blob/master/go/nogo.rst)). Added in v0.1.0 #### `exclude-pkgs` > Default `""` (no packages are excluded) A comma-separated list of package prefixes to exclude for analysis. This takes precedence over `include-pkgs`. Added in v0.1.0 #### `exclude-file-docstrings` > Default `""` (no files are excluded) A comma-separated list of strings to search for in a file's docstrings to exclude a file from analysis. Added in v0.1.0 #### `pretty-print` > Default `false` A boolean flag indicating if NilAway should pretty print the errors (with ANSI color codes to highlight different components in the errors). Added in v0.1.0 #### `group-error-messages` > Default `true` A boolean flag indicating if NilAway should group similar error messages together. Added in v0.1.0 #### `experimental-struct-init` > Default `false` A boolean flag enabling experimental support in NilAway for more sophisticated tracking / analysis around struct fields and struct initializations (e.g., initializing an empty struct and then calling a function to populate the fields, such that the fields should be considered nonnil). Note that this feature brings performance penalties and false positives. We plan to further improve this feature and merge it in main NilAway, so this flag could be removed in the future. Added in v0.1.0 #### `experimental-anonymous-function` > Default `false` A boolean flag enabling experimental support for anonymous functions in NilAway. Note that this feature brings a fair number of false positives. We plan to further improve this feature and merge it in main NilAway, so this flag could be removed in the future. Added in v0.1.0 ## Driver-Specific Flags #### Standalone Checker Since the standalone linter driver does not support error suppression, which may be required for some deployments (see [Include Package](https://github.com/uber-go/nilaway/wiki/Configuration/#include-packages-include-pkgs) for a detailed discussion), we add two more flags to this specific checker for such functionality: #### `include-errors-in-files` > Default is the current working directory, meaning we only report errors for files within the current working directory. A comma-separated list of file prefixes to report errors. Added in v0.1.0 #### `exclude-errors-in-files` > Default "", meaning no errors are suppressed. A comma-separated list of file prefixes to exclude from error reporting. This takes precedence over include-errors-in-files. Added in v0.1.0 #### `json` > Default `false` A boolean flag indicating if the NilAway errors should be printed in JSON format for further post-processing. Added in v0.1.0 ## Passing Configurations ### Standalone Checker Flags can be specified directly on the command line: ``` nilaway -flag1 -flag2 ./... ``` ### golangci-lint Flags can be specified in `.golangci.yaml` configuration file: ```yaml linters-settings: custom: nilaway: type: "module" description: Static analysis tool to detect potential nil panics in Go code. settings: # Settings must be a "map from string to string" to mimic command line flags: the keys are # flag names and the values are the values to the particular flags. include-pkgs: "" # NilAway can be referred to as `nilaway` just like any other golangci-lint analyzers in other # parts of the configuration file. ``` ### Bazel/nogo Configurations of NilAway is slightly confusing: the flags should be passed to a specific `nilaway_config` analyzer, and error suppressions should be passed to the top-level `nilaway` analyzer instead.
Here is the technical explanation > NilAway adopts the standard flag passing mechanism in the [`go/analysis`](https://pkg.go.dev/golang.org/x/tools/go/analysis) framework. However, the multi-analyzer architecture of NilAway (see [wiki/Architecture](https://github.com/uber-go/nilaway/wiki/Architecture)) makes it slightly difficult to pass flags to NilAway. If we simply set the `Flags` fields to the top-level `nilaway.Analyzer`, by the time it is executed, the sub-analyzers have already done the work, making the flags meaningless (i.e., it can no long alter their behaviors). > > To address this problem, we have defined a separate `nilaway_config` analyzer which is only responsible for defining the `Flags` field and expose the configs through its return value. All other sub-analyzers will depend on the `config.Analyzer` and use the values there to execute different logic. > > This inevitably makes the configurations for NilAway slightly confusing: you will have to pass flags to the separate `nilaway_config` analyzer, while any error suppressions must be set for the top-level `nilaway` analyzer (since it is the one that eventually reports the errors). > > For drivers other than Bazel/nogo, we usually have a chance to run extra logic (e.g., during standalone driver initialiation, or during NilAway registration to golangci-lint) before the execution, where we can pass the top-level flags to the specific `nilaway_config` analyzer. However, unfortunately Bazel/nogo does not allow us to do so.
In your nogo's `config.json` file (see [nogo's documentation on configurations](https://github.com/bazelbuild/rules_go/blob/master/go/nogo.rst#configuring-analyzers) on how to pass this file to the nogo driver), you have to specify configurations for two analyzers. For example: ```json { "nilaway_config": { "analyzer_flags": { "include-pkgs": "go.uber.org", "exclude-pkgs": "vendor/", "exclude-file-docstrings": "@generated,Code generated by,Autogenerated by" } }, "nilaway": { "exclude_files": { "bazel-out": "this prevents nilaway from outputting diagnostics on intermediate test files" }, "only_files": { "my/code/path": "This is the comment for why we want to enable NilAway on this code path" } } } ``` --- # Developing NilAway is a static analysis tool that detects potential nil panics in Go code. It uses sophisticated analysis techniques to track nil flows within and across packages, reporting errors with nilness flows for easier debugging. ## Building ```bash make build # Build the nilaway binary to /bin/ ``` ## Testing ```bash make test # Run unit tests for all modules make cover # Run tests with coverage reports make integration-test # Run integration tests (using real drivers) ``` The following golden tests are available, which run NilAway on a base (usually `main`) and test (usually `HEAD`) branches on stdlib and compare the differences of NilAway violations. This is mostly run in CI to catch unexpected breakages. ```bash # The arguments are passed as an environment variable `ARGS`. # Use `make golden-test ARGS="-h" to see the available arguments. make golden-test ARGS="-base-branch main -test-branch HEAD -result-file /tmp/result.txt" ``` ## Linting ```bash make lint # Run all linting (format check, mod tidy, golangci-lint, nilaway self-check) make lint-fix # Run all linting with autofix (and auto-formats) applied ``` The following subcommands are available if you need to run individual linting components. Pass in `FIX=true` environment variable to apply auto-fixes _if available_. In most cases you only need to ever run `make lint` or `make lint-fix` instead of these. ```bash make format-lint # Check if Go files are correctly formatted make tidy-lint # Check go.mod tidiness make golangci-lint # Run golangci-lint only make nilaway-lint # Run nilaway on itself ``` ### Upgrading Dependencies Run `make upgrade-deps` to upgrade all dependencies and tools to their latest versions for all modules within NilAway. Optionally, set `GO_VERSION=` environment variable to upgrade to a specific Go version (e.g., `1.21`). ### Running NilAway ```bash # Build nilaway in current codebase. make build # Standalone usage bin/nilaway -include-pkgs="" ./... # With JSON output (disable pretty-print) bin/nilaway -json -pretty-print=false -include-pkgs="" ./... # Using custom golangci-lint build golangci-lint custom # Build custom binary with NilAway plugin ./custom-gcl run ./... # Run custom golangci-lint with NilAway ``` ## Architecture For best performance and easier maintenance, NilAway consists of multiple levels of sub-analyzers that are all `analysis.Analyzer`s, and they are connected by specifying dependencies (via `Requires` field) between them. Currently, the organization is as follows: - **nilaway.Analyzer** (nilaway.go) - Top-level analyzer that reports errors - **accumulation.Analyzer** - Collects triggers, runs inference, returns errors - **annotation.Analyzer** - Reads annotations from structs/interfaces/functions - **function.Analyzer** - Analyzes functions and creates triggers - **anonymousfunc.Analyzer** - Handles function literals - **structfield.Analyzer** - Handles struct field accesses - **affiliation.Analyzer** - Creates interface-struct affiliation triggers - **global.Analyzer** - Creates global variable triggers All the analyzers depend on `config.Analyzer` (`config/config.go`) to retrieve configurations. The decoupling of error generation and error reporting logic makes it possible to apply custom error reporting to fit other needs. For example, it is possible to create another top-level analyzer `nilaway-log` that depends on the accumulation analyzer, which simply retrieves the NilAway errors and logs them to a local file or database for later auditing. ### Key Components - **Triggers**: Flow conditions that may cause nil panics - **Annotations**: Metadata about nilability of types and functions - **Inference Engine**: Matches triggers with annotations to detect nil flows - **Facts Mechanism**: Caches analysis results across packages for performance ### Important Files - `nilaway.go` - Main analyzer entry point - `cmd/nilaway/main.go` - Standalone checker with additional flags - `cmd/gclplugin/gclplugin.go` - golangci-lint plugin integration - `accumulation/analyzer.go` - Core inference coordination - `config/config.go` - Configuration management ## Key Configuration Flags - `-include-pkgs`: Comma-separated package prefixes to analyze (recommended) - `-exclude-pkgs`: Package prefixes to exclude from analysis - `-pretty-print`: Enable/disable pretty error messages (default: true) - `-group-error-messages`: Group similar error messages - `-experimental-struct-init-enable`: Enable experimental struct initialization - `-experimental-anonymous-func-enable`: Enable experimental anonymous function support ## Performance Notes - Uses `go/analysis` Facts mechanism for cross-package caching - For large projects, use modular drivers (bazel/nogo or golangci-lint) over standalone checker - Recommend using `-include-pkgs` to focus analysis on first-party code only ## Module Structure - Root module: Core NilAway implementation - `tools/` module: Development tools (golden-test, integration-test) - `testdata/` directory: Comprehensive test cases organized by feature ## More docs Refer to `docs/` directory for more documentations on other aspects of NilAway. --- # Project Overview - [Configurations](configurations.md) - [Developing](developing.md) - [Community-Maintained Projects](community-maintained-projects.md)