codelint

package
v0.0.21 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 21, 2026 License: MIT Imports: 19 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var AllFormats = []FormatE{FormatHuman, FormatJson}
View Source
var PackageProps = packageprops.Props{
	WASMWASI:         packageprops.WASMBlocked,
	WASMJS:           packageprops.WASMBlocked,
	WASMFreestanding: packageprops.WASMBlocked,
}

PackageProps records this package's curated properties (ADR-0080). Seeded by `boxer code analysis golang wasmsurvey props generate`; curate by hand. The same group's `props verify` reconciles it.

Functions

func ExtractEnumPrefix

func ExtractEnumPrefix(doc *ast.CommentGroup) (prefix string, ok bool)

ExtractEnumPrefix returns the override prefix declared on a comment group (typically a TypeSpec's or GenDecl's Doc field), or ("", false) if no directive is present.

func IsGeneratedFile

func IsGeneratedFile(path string) (skip bool)

IsGeneratedFile reports whether a file path is one of the generation suffixes we always skip. Matches the grep filters in scripts/ci/lint.sh.

func LoadPackagesE

func LoadPackagesE(cfg LoadConfig, roots ...string) (pkgs []*packages.Package, err error)

LoadPackagesE loads the package graph rooted at the supplied patterns (e.g. "./..."), populating the syntax + type info each analyzer needs.

Generated files (*.out.go, *.gen.go) are filtered post-load — they remain in the package graph for type resolution but are not visited.

func NewCliCommand

func NewCliCommand() *cli.Command

Types

type Finding

type Finding struct {
	RuleId   string           `json:"rule"`
	Severity FindingSeverityE `json:"severity"`
	Path     string           `json:"path"`
	Line     int32            `json:"line,omitempty"`
	Col      int32            `json:"col,omitempty"`
	Message  string           `json:"message"`
}

Finding is a single rule violation discovered during a codelint pass.

Line and Col are 1-based; zero means "not pinpointed within the file". The shape matches doclint.Finding so reporters can be shared structurally.

type FindingSeverityE

type FindingSeverityE uint8

FindingSeverityE classifies a codelint finding. Mirrors doclint's vocabulary so the lint.sh aggregator can apply the same warn/fail trailer rules.

const (
	FindingSeverityInfo  FindingSeverityE = 1
	FindingSeverityWarn  FindingSeverityE = 2
	FindingSeverityError FindingSeverityE = 3
)

func ParseSeverityE

func ParseSeverityE(s string) (sev FindingSeverityE, err error)

func (FindingSeverityE) String

func (inst FindingSeverityE) String() (s string)

type FormatE

type FormatE uint8
const (
	FormatHuman FormatE = 1
	FormatJson  FormatE = 2
)

func ParseFormatE

func ParseFormatE(s string) (f FormatE, err error)

func (FormatE) String

func (inst FormatE) String() (s string)

type Linter

type Linter struct {
	// contains filtered or unexported fields
}

Linter aggregates rules and runs them against a loaded package set.

Zero value is usable; rules are added via Register.

func NewDefaultLinter added in v0.0.20

func NewDefaultLinter() (inst *Linter)

NewDefaultLinter returns a Linter carrying every shipped CS rule.

This is the rule set `gov codelint` runs, and the one an embedder — the composite gate, a consuming repository's own entry point — gets by default. It exists so those callers cannot silently diverge from the command: a rule added here reaches all of them at once.

func NewLinter

func NewLinter() (inst *Linter)

func (*Linter) Register

func (inst *Linter) Register(r RuleI)

func (*Linter) Run

func (inst *Linter) Run(pkgs []*packages.Package) iter.Seq2[Finding, error]

Run executes every registered rule against the supplied packages and yields findings as they are produced. Suppression directives are applied before yielding.

type LoadConfig

type LoadConfig struct {
	Ctx       context.Context
	Dir       string
	BuildTags []string
	Tests     bool
}

LoadConfig controls how the driver loads packages for analysis.

Dir is the directory the patterns resolve against; empty means the process working directory. An embedder linting a tree it did not chdir into — the composite gate run against another repository root — must set it, or the relative patterns silently resolve somewhere else.

type ReporterI

type ReporterI interface {
	Add(f Finding)
	FinishE() (err error)
}

ReporterI receives findings as they are produced and writes them out when FinishE is called.

func NewReporterE

func NewReporterE(format FormatE, w io.Writer) (r ReporterI, err error)

type RuleCS001

type RuleCS001 struct{}

RuleCS001 — fmt.Errorf outside the eh package.

CODINGSTANDARDS.md "Error Handling → Simple Wrapping" requires eh.Errorf for error construction so that stack traces and structured context are preserved. fmt.Errorf is allowed only inside the eh implementation itself.

func NewRuleCS001

func NewRuleCS001() (inst *RuleCS001)

func (*RuleCS001) Analyzer

func (inst *RuleCS001) Analyzer() (a *analysis.Analyzer)

func (*RuleCS001) DefaultSeverity

func (inst *RuleCS001) DefaultSeverity() (sev FindingSeverityE)

func (*RuleCS001) Id

func (inst *RuleCS001) Id() (id string)

type RuleCS002

type RuleCS002 struct{}

RuleCS002 — context.Context must be the first parameter.

CODINGSTANDARDS.md "Concurrency Patterns → Context" mandates that any function or method taking a context.Context places it as the first argument (receiver excluded). The check visits every *ast.FuncType so FuncDecl, FuncLit, interface methods, and function-typed fields are all covered with one walk.

The "must have a ctx for I/O-bound work" half of the standard is judgment-based and not enforced here.

func NewRuleCS002

func NewRuleCS002() (inst *RuleCS002)

func (*RuleCS002) Analyzer

func (inst *RuleCS002) Analyzer() (a *analysis.Analyzer)

func (*RuleCS002) DefaultSeverity

func (inst *RuleCS002) DefaultSeverity() (sev FindingSeverityE)

func (*RuleCS002) Id

func (inst *RuleCS002) Id() (id string)

type RuleCS003

type RuleCS003 struct{}

RuleCS003 — sync.Mutex / sync.RWMutex fields must be by value.

CODINGSTANDARDS.md "Concurrency Patterns → Mutexes" requires the mutex to live by value so zero-valued struct usage is safe and no extra heap allocation happens per instance. Function parameters taking *sync.Mutex are not flagged — passing-by-pointer is a normal caller-side mechanic and the standard's concern is where the mutex is owned, not how it is borrowed.

Both named and embedded pointer-mutex fields are flagged.

func NewRuleCS003

func NewRuleCS003() (inst *RuleCS003)

func (*RuleCS003) Analyzer

func (inst *RuleCS003) Analyzer() (a *analysis.Analyzer)

func (*RuleCS003) DefaultSeverity

func (inst *RuleCS003) DefaultSeverity() (sev FindingSeverityE)

func (*RuleCS003) Id

func (inst *RuleCS003) Id() (id string)

type RuleCS004

type RuleCS004 struct{}

RuleCS004 — prefer typed sync/atomic over the legacy free-function API.

CODINGSTANDARDS.md "Concurrency Patterns → Atomics" requires the typed forms introduced in Go 1.19 (atomic.Int64, atomic.Pointer[T], …) over the original atomic.LoadInt64(&v) / atomic.StoreInt64(&v, x) / atomic.AddInt64(&v, d) / atomic.SwapInt64(&v, x) / atomic.CompareAndSwapInt64(&v, old, new) family.

Detection is by package + receiver-shape rather than a hard-coded function list: any call to a package-level (no-receiver) function in sync/atomic is, by construction, the legacy API. The typed forms are methods on atomic.Int64 etc. and therefore have a non-nil receiver.

func NewRuleCS004

func NewRuleCS004() (inst *RuleCS004)

func (*RuleCS004) Analyzer

func (inst *RuleCS004) Analyzer() (a *analysis.Analyzer)

func (*RuleCS004) DefaultSeverity

func (inst *RuleCS004) DefaultSeverity() (sev FindingSeverityE)

func (*RuleCS004) Id

func (inst *RuleCS004) Id() (id string)

type RuleCS005

type RuleCS005 struct{}

RuleCS005 — declared interface names must end with capital 'I'.

CODINGSTANDARDS.md "Naming & Style → Interface Naming" requires the suffix so interface vs concrete is visible at every use site. Only direct interface declarations are checked; anonymous inline interfaces (e.g. in a function parameter list) have no name, and type aliases to an interface are deliberately out of scope here because CS008 will reject the alias outright.

func NewRuleCS005

func NewRuleCS005() (inst *RuleCS005)

func (*RuleCS005) Analyzer

func (inst *RuleCS005) Analyzer() (a *analysis.Analyzer)

func (*RuleCS005) DefaultSeverity

func (inst *RuleCS005) DefaultSeverity() (sev FindingSeverityE)

func (*RuleCS005) Id

func (inst *RuleCS005) Id() (id string)

type RuleCS006

type RuleCS006 struct{}

RuleCS006 — enum type names must end with capital 'E'.

CODINGSTANDARDS.md "Naming & Style → Enum Naming" requires the suffix so enum vs scalar is visible at every use site. Enums are detected structurally: a named type that appears as the declared type of two or more constants inside the same `const (...)` block is treated as an enum. iota-chained specs without an explicit Type are resolved via go/types, so the entire chain is counted.

Single-value `const Foo BarE = …` declarations are not classified as enums (insufficient evidence). External-package types are not flagged — they are not ours to rename.

func NewRuleCS006

func NewRuleCS006() (inst *RuleCS006)

func (*RuleCS006) Analyzer

func (inst *RuleCS006) Analyzer() (a *analysis.Analyzer)

func (*RuleCS006) DefaultSeverity

func (inst *RuleCS006) DefaultSeverity() (sev FindingSeverityE)

func (*RuleCS006) Id

func (inst *RuleCS006) Id() (id string)

type RuleCS007

type RuleCS007 struct{}

RuleCS007 — enum values must be prefixed with the enum type name minus its trailing 'E', or with the type's declared override prefix.

CODINGSTANDARDS.md "Naming & Style → Enum Naming" — given a type WeekdayE, every value is expected to start with `Weekday`. Detection of *which* types are enums reuses CS006's per-block heuristic: a named type with 2+ constants in the same `const (...)` block is an enum. Once classified, every constant of that type (including stragglers in single-value declarations elsewhere) is checked.

When the type-name prefix is awkwardly long, a per-enum override may be declared on the type:

//codelint:enum-prefix=Subtype
type StaticPolySubtypeE uint8

Types whose name does not end with 'E' and have no override are skipped here — CS006 covers the type-name issue and double-flagging the same root cause is noise.

func NewRuleCS007

func NewRuleCS007() (inst *RuleCS007)

func (*RuleCS007) Analyzer

func (inst *RuleCS007) Analyzer() (a *analysis.Analyzer)

func (*RuleCS007) DefaultSeverity

func (inst *RuleCS007) DefaultSeverity() (sev FindingSeverityE)

func (*RuleCS007) Id

func (inst *RuleCS007) Id() (id string)

type RuleCS008

type RuleCS008 struct{}

RuleCS008 — type aliases are not allowed.

CODINGSTANDARDS.md "Typing → Nominal Typing → No Aliases" prohibits the `type X = Y` form. Named-type declarations (`type X Y`) remain fine. Detection is purely positional: in an *ast.TypeSpec, the presence of the `=` token is recorded as a non-zero Assign position.

func NewRuleCS008

func NewRuleCS008() (inst *RuleCS008)

func (*RuleCS008) Analyzer

func (inst *RuleCS008) Analyzer() (a *analysis.Analyzer)

func (*RuleCS008) DefaultSeverity

func (inst *RuleCS008) DefaultSeverity() (sev FindingSeverityE)

func (*RuleCS008) Id

func (inst *RuleCS008) Id() (id string)

type RuleCS009

type RuleCS009 struct{}

RuleCS009 — banned imports.

func NewRuleCS009

func NewRuleCS009() (inst *RuleCS009)

func (*RuleCS009) Analyzer

func (inst *RuleCS009) Analyzer() (a *analysis.Analyzer)

func (*RuleCS009) DefaultSeverity

func (inst *RuleCS009) DefaultSeverity() (sev FindingSeverityE)

func (*RuleCS009) Id

func (inst *RuleCS009) Id() (id string)

type RuleCS010

type RuleCS010 struct{}

RuleCS010 — single-iterator types must use a canonical iterator method name.

The standard's quartet (All/Values/Keys/Backward) describes the single-collection-per-receiver case. Types that legitimately expose multiple distinct iterations (e.g. pushoutgraph's LiveChildren, ForwardEdges, DeletedPartitionMembers) use domain-describing names and are out of scope — this rule only fires when a receiver has exactly one iter-returning method whose name isn't in the quartet.

func NewRuleCS010

func NewRuleCS010() (inst *RuleCS010)

func (*RuleCS010) Analyzer

func (inst *RuleCS010) Analyzer() (a *analysis.Analyzer)

func (*RuleCS010) DefaultSeverity

func (inst *RuleCS010) DefaultSeverity() (sev FindingSeverityE)

func (*RuleCS010) Id

func (inst *RuleCS010) Id() (id string)

type RuleCS011

type RuleCS011 struct{}

RuleCS011 — direct process-environment access is prohibited.

CODINGSTANDARDS.md "Configuration → Environment Variables" and ADR-0009 require every env var to flow through public/config/env so declarations are discoverable, typed, doc-generated, and protected from lowercase-name / typo defects. The env package itself is the only sanctioned implementer of these calls.

Subsumes the original env/lint_test.go enforcer and additionally covers os.Environ (which the test had not modelled).

func NewRuleCS011

func NewRuleCS011() (inst *RuleCS011)

func (*RuleCS011) Analyzer

func (inst *RuleCS011) Analyzer() (a *analysis.Analyzer)

func (*RuleCS011) DefaultSeverity

func (inst *RuleCS011) DefaultSeverity() (sev FindingSeverityE)

func (*RuleCS011) Id

func (inst *RuleCS011) Id() (id string)

type RuleCS012 added in v0.0.14

type RuleCS012 struct{}

RuleCS012 — os/exec.Command/CommandContext/LookPath outside package extbin.

Every external program boxer spawns must be resolved through the extbin registry so the set of host binaries the toolkit can invoke stays enumerable — a supply-chain concern for a toolkit that ships airgapped. Test files are exempt: fixtures may shell out freely, and tests are not part of the shipped runtime surface.

func NewRuleCS012 added in v0.0.14

func NewRuleCS012() (inst *RuleCS012)

func (*RuleCS012) Analyzer added in v0.0.14

func (inst *RuleCS012) Analyzer() (a *analysis.Analyzer)

func (*RuleCS012) DefaultSeverity added in v0.0.14

func (inst *RuleCS012) DefaultSeverity() (sev FindingSeverityE)

func (*RuleCS012) Id added in v0.0.14

func (inst *RuleCS012) Id() (id string)

type RuleI

type RuleI interface {
	Id() (id string)
	DefaultSeverity() (sev FindingSeverityE)
	Analyzer() (a *analysis.Analyzer)
}

RuleI is implemented by every codelint rule.

Each rule exposes a go/analysis Analyzer that the driver runs once per loaded package. Severity is rule-supplied so the driver can label the translated Finding without rule-specific glue.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL