doclint

package
v0.18.0 Latest Latest
Warning

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

Go to latest
Published: Aug 28, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package doclint resolves the doc links in this module's comments and reports the ones that name nothing.

Why

A removed symbol leaves its doc links behind. Go's own tooling does not complain: godoc renders a link to a symbol that no longer exists as an ordinary link, and golangci-lint's documentation linters check style, not reference resolution. Two releases in a row shipped documentation advertising API that had been cut, and neither was found by a gate — the first by a cleanup pass that happened to open the file, the second by a consumer trying to upgrade.

Only a bracketed name whose final component is a capitalized Go identifier is a link: Name, Type.Method, Type.Field, pkg.Name, pkg.Type.Method, each in brackets. That is go/doc/comment's own rule, deliberately inherited here: a bracketed lowercase name such as someHelper renders as literal text in published documentation, so it is not a link and this package does not resolve it. A reference of that shape naming a deleted symbol is real rot, but it is rot of a different class and needs a different instrument.

Resolution

The resolution unit is the directory, not the package: every .go file in a directory contributes names, test files included. That is what lets a production doc comment anchor a regression test by name — the convention the repo's comment rules sanction — while still catching an anchor that names a test somebody deleted.

A qualified link resolves its package part against the referencing file's own imports first. This module has an adapter/json package, so a bare package-name match for a json-qualified link would collide with encoding/json. When the file does not import the name, a unique in-module package with that name is the fallback, which is how a comment can reference a package that would be an import cycle to depend on. Links resolving outside the module are skipped: the standard library and this module's dependencies are not this gate's business.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AssertNoDanglingLinks(t TB, root string) (checked int)

AssertNoDanglingLinks reports every doc link under root that names nothing, and returns how many links it resolved.

The count is returned rather than asserted internally so the caller keeps its own floor visible: a walk that reaches no source resolves no links and would otherwise pass.

Types

type Link struct {
	// Pos is "file:line" of the comment group holding the link.
	Pos string
	// Text is the link as it appears between the brackets.
	Text string
	// ImportPath is the target package, empty for the referencing package.
	ImportPath string
	// Recv is the receiver or owning type, empty for a package-level name.
	Recv string
	// Name is the symbol name.
	Name string
}

Link is one doc link, with where it was written and what it names.

type Module

type Module struct {
	Path     string
	Packages []*Package
	// contains filtered or unexported fields
}

Module is a parsed module: every package under the walk root, indexed for resolution by import path and by package name.

func Load

func Load(root string) (*Module, error)

Load parses every Go file under root, skipping directories that hold no source a consumer reads: testdata, node_modules, and anything whose name starts with "." or "_". Files that do not parse are an error rather than a skip — a gate that quietly drops the file it cannot read reports a clean run over nothing.

func (*Module) Dangling

func (m *Module) Dangling() (dangling []Link, checked int)

Dangling returns every link in m that names nothing, in walk order.

A link whose target package is outside the module is not resolved and not reported: the standard library and this module's dependencies keep their own promises. Checked reports how many links were resolved, so a caller can tell "nothing dangles" from "nothing was read".

type Package

type Package struct {
	// Dir is the slash-separated path from the walk root, "." for the root.
	Dir string
	// ImportPath is the module path joined with Dir.
	ImportPath string
	// Name is the package clause of the directory's non-test files, falling
	// back to a test file's when a directory holds only tests.
	Name string
	// contains filtered or unexported fields
}

Package is one directory's Go files and every name they declare.

The directory rather than the package is the unit, so a name declared in an external test package (package foo_test beside package foo) resolves for a link written in either.

type TB

type TB interface {
	Helper()
	Errorf(format string, args ...any)
}

TB is the slice of testing.TB this gate uses, which *testing.T satisfies.

It is an interface of this package's own rather than testing.TB itself because testing.TB is deliberately unimplementable outside the standard library, and a gate whose failure path is unreachable from a test is a gate that can silently stop failing.

Jump to

Keyboard shortcuts

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