ptrparam

package module
v0.6.31 Latest Latest
Warning

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

Go to latest
Published: Aug 24, 2026 License: MIT Imports: 10 Imported by: 0

README

Documentation

Overview

The configurable allow-list: the one exemption that is set rather than computed, and the only one that leaves no trace when it fires.

Derived-type resolution: a type DEFINED over another named type has that type's layout, and so its copy hazards, whatever methods it drops.

Foreign-convention detection: the analyzed module's own types are its design responsibility, but a foreign type follows its library's conventions.

Package ptrparam provides a go/analysis analyzer enforcing the gomatic Go immutability standard: function parameters are passed by value, never by pointer, unless a pointer is the pointed-to type's idiomatic calling convention.

A parameter is judged on its TYPE, not on its spelling: `*T`, an alias of `*T`, a defined type whose underlying is `*T`, and an instantiated generic alias are one rule, because they are one type and no call site can tell them apart.

There are six exemptions and no others. Five are decided from the type; the sixth is decided from what the loader happened to materialise and is stated at the end, where it used to be miscounted as a limitation.

  • Pointer-idiomatic, decided from the type itself and applying to any package including the analyzed module's own (semantic.go): the type is uncopyable under go vet's copylocks criterion — a struct whose POINTER is a sync.Locker while its value is not, directly or through a struct field or array element — or every exported method it declares takes the pointer receiver, so a value carries no usable API. The second is forgeable by design and its forgery is charged by yze/ptrrecv WHEN THE TYPE DECLARING THE METHOD IS THE PARAMETER'S OWN — the author who writes the pointer receiver is the one the finding lands on. It is NOT charged when the criterion is reached through the definition chain below: there the receiver was written on the source type, whose author may have had their own reason for it and was already paying that finding, so the definition buys silence at nobody's expense. That is ptrparam.inherited-hazard-is-a-layout-property (k1n8261k), open, and it is stated here rather than only in derived.go because docs/s03.md sends an enumerator to this comment. The first criterion costs the marker go vet then reports every copy of the type against.

  • An inherited copy hazard (derived.go): a type DEFINED over another named type — `type MyBuilder strings.Builder` — has that type's layout and so its copy hazards, while inheriting none of the methods that announce them. This one DOES apply to the analyzed module's own types, and it is the only exemption that does so on the strength of another type: the hazard is in the layout, and the layout is what a definition copies. Only the pointer-idiomatic question above is asked of a link in that chain, never the two below it — a foreign library's convention is about the library's own type and no signature anywhere can be handed the local one, and an -allow entry names a single `pkgpath.Name`. Inheriting either made one `type` line the cheapest silence available here.

  • Foreign convention (foreign.go): a type from OUTSIDE the analyzed module whose OWN PACKAGE's exported API hands out or accepts a pointer to it — in a function or method signature, an interface method, an exported struct field, or a callback field, directly or one container level deep. The analyzed module's own types are its own design responsibility and never gain it, and neither does a named type over a basic underlying, where `*T` is an out-parameter (flag.DurationVar's *time.Duration) rather than a passing convention.

    NO OTHER PACKAGE IS READ — not a sibling, not one inside the library's import namespace, not one the judged file imports. Both narrower readings were tried and both were forgeable from the tree being judged: an unrestricted scan of the imports made `_ "weaver"` a disablement, and restricting it to the library's own namespace fell to a go.mod `replace`, which makes an import path a purely local claim (k1n828c6). A pass carries no module identity for an imported package, so "a sibling, but a published one" is a distinction this analyzer has no instrument for. The cost is stated because it is real: a library that publishes the pointer only from a package beside the type — gqlparser's `*ast.QueryDocument`, whose own `ast` package mentions it nowhere — is REPORTED here, and the value the diagnostic prescribes silently loses mutations made through the alias. The move left to that author is an -allow entry, which an inventory can read, rather than an import line, which leaves no entry anywhere.

  • A type parameter: a generic seam whose instantiations the analyzer cannot judge, and the pointer is how a generic function binds to a caller-owned value.

  • The -allow flag (`analyzers: {yze/ptrparam: {allow: [...]}}` under stickler), a comma-separated list of fully-qualified `pkgpath.Name` types. This is a SILENT disablement channel: a configured entry produces no output, no count and no ratchet, and a misspelt entry is accepted without complaint and is simply dead. It is named here because an exemption nobody can enumerate is one nobody reviews.

A SIXTH EXEMPTION, named as one because that is what it is. Where go/types did not materialise a foreign type's own package — it reached the type through another package's alias re-export and loaded nothing else — the analyzer exempts the parameter. This comment called that "a scope limitation, which is not an exemption" and that was wrong twice over: it is the `return true` branch of foreignConvention, it produces silence at zero cost, and it disagreed with foreign.go's own comment, which had already been corrected to call it a disablement channel. An enumerator following docs/s03.md reads THIS comment, so counting it out of the list is how a shape passes every instrument by not being looked for.

It is import-list-dependent and it is DRIVER-DEPENDENT, which is the part worth writing down: a four-line alias package in the author's own module, `type Doc = ast.Doc`, silences the library's type under `go vet -vettool` while the same source reports under a packages.Load driver, and one blank import of the library flips the vet verdict back. Neither polarity is import-independent — blindness cannot tell "this library publishes no pointer convention" from "this library was not loaded" — so this is a choice between two channels rather than the absence of one. The repair is a loader that materialises the type's own package, which belongs to go-yze. ptrparam.verdict-does-not-follow-the-loaders-reach (k1n81qeg), open.

Semantic pointer-idiomatic detection: the discovery criteria applied live to any package's types.

Index

Constants

View Source
const ErrAllowEntry errs.Const = "-allow entry must be a fully-qualified type (pkgpath.Name)"

ErrAllowEntry reports an -allow entry that is not a fully-qualified type.

The list is the one exemption that is SET rather than computed, and it was also the only one that could be wrong without saying so. Entries were inserted as map keys with no parse at all, and lookups are exact matches on pkgpath.Name, so `NoDotHere`, `,,,`, a run of spaces and a trailing dot were each accepted in silence -- no error, no warning, no finding -- and an exemption naming nothing is indistinguishable from one that works.

This is refused where a setting VALUE is refused, at configuration load, which is the layer that says it once. Inside the analyzer it could only be said once per package that can see the entry, and a package-path typo could not be told from an entry aimed at code this pass does not import at all.

WHAT SHAPE CANNOT DECIDE, stated so the check is not mistaken for a guarantee: `control.Confg` for `control.Config` is a well-formed entry naming a type that does not exist, and it stays silent here. Catching that means knowing every type in the run, which no flag parse and no single pass has.

Variables

View Source
var Analyzer = newAnalyzer()

Analyzer reports pointer parameters whose pointed-to type has no pointer calling convention.

View Source
var Registration = goyze.Registration{
	Precision:  goyze.PrecisionExact,
	Name:       "ptrparam",
	Categories: []goyze.Category{"immutability"},
	URL:        "https://docs.gomatic.dev/yze/ptrparam",
	Analyzer:   Analyzer,
}

Registration declares this analyzer to the yze framework.

Functions

This section is empty.

Types

This section is empty.

Jump to

Keyboard shortcuts

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