You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
# ADR-39990: Resolve Package Identity via Type Information in Custom Linters
2
+
3
+
**Date**: 2026-06-18
4
+
**Status**: Draft
5
+
6
+
## Context
7
+
8
+
The `rawloginlib` analyzer detects raw `log.Printf`/`log.Fatal`-style calls in library packages by matching the selector's receiver identifier name syntactically (`ident.Name == "log"`). This name-based heuristic is unaware of Go's actual binding semantics: it produced CI-blocking false positives when a local variable or parameter named `log` shadowed the package (e.g. a `*customLogger` receiver), and false negatives when the stdlib package was imported under an alias (`import applog "log"`). Custom linters in this repo (e.g. ADR-39133, ADR-39263) share the same family of selector-inspection logic, so the fix needs to be reusable rather than local to one analyzer.
9
+
10
+
## Decision
11
+
12
+
We will determine package identity for selector expressions using resolved type information (`go/types`) instead of matching identifier names. We added `astutil.IsPkgSelector(pass, sel, pkgPath)`, which resolves the selector's receiver identifier through `pass.TypesInfo.ObjectOf`, confirms it is a `*types.PkgName`, and compares the imported package's import path. `rawloginlib` now gates its diagnostic on `IsPkgSelector(pass, sel, "log")` rather than the receiver's spelling. The helper is centralized in the shared `astutil` package so other linters can reuse the same type-resolved identity check.
13
+
14
+
## Alternatives Considered
15
+
16
+
### Alternative 1: Keep name matching with extra heuristics
17
+
We could have kept `ident.Name == "log"` and layered on ad-hoc handling for aliases and shadowing (e.g. scanning import specs to map alias names back to paths). This was rejected because it reconstructs, imperfectly, information the type checker already computes; it would remain fragile against any binding the heuristics did not anticipate.
18
+
19
+
### Alternative 2: Inline type resolution per linter
20
+
We could have inlined the `TypesInfo` / `*types.PkgName` resolution directly inside `rawloginlib` without a shared helper. This was rejected because the same logic already recurs across the repo's custom linters; duplicating it invites drift and repeated nil-safety bugs.
21
+
22
+
## Consequences
23
+
24
+
### Positive
25
+
- Eliminates the false-positive and false-negative classes for shadowed receivers and aliased imports, removing spurious CI failures.
26
+
- Provides a single, tested `astutil.IsPkgSelector` helper reusable by current and future linters.
27
+
28
+
### Negative
29
+
- Correctness now depends on `pass.TypesInfo` being populated; the helper degrades to `false` when type info is absent, so a misconfigured analysis pass silently under-reports rather than erroring.
30
+
- Type-based resolution is marginally more complex and less obvious to a reader than a direct name comparison.
31
+
32
+
### Neutral
33
+
- Diagnostic message text and `//nolint` suppression behavior are unchanged.
34
+
- Adds testdata cases (alias import, shadowed param/local) and `astutil` unit tests covering the new helper.
35
+
36
+
---
37
+
38
+
*This is a DRAFT ADR generated by the [Design Decision Gate](https://github.com/github/gh-aw/actions/runs/27739763043) workflow. The PR author must review, complete, and finalize this document before the PR can merge.*
0 commit comments