Skip to content

Commit

Permalink
🧪 Add test for synonym types (#128)
Browse files Browse the repository at this point in the history
The `analyzer` package currently has tests for type aliases that define
a new type, like this:

```go
type TestAlias Test
```

But not for type aliases that _don't_ define a new type but only a new
symbol, like this:

```go
type TestSynonym = Test
```

I've called this second category "synonyms" but Go's documentation calls
them "aliases". What the current tests call "aliases" is generally seen
as a distinct type with the same memory layout.

This PR adds tests for these "synonyms". All of these tests pass. The PR
can be merged with no impact on any of the analyzer's behaviour.

**Why am I adding these tests?**

Because while these tests pass with Go 1.21, they fail with Go 1.23 and
above. I haven't figured out what change in Go 1.23 breaks the analyzer
for these cases yet. But when it comes time to fix the analyzer, these
tests will be useful.

**The linter is buggy in `golangci-lint` now.**

When compiling `go-exhaustruct` directly, the `go 1.21` directive in
`go.mod` makes sure the behaviour works as expected. However,
`golangci-lint` does not compile `go-exhaustruct` directly: it imports
the analyzer and then compiles `golangci-lint` as a whole. A few days
ago, `golangci-lint` changed their `go 1.22` directive to `go 1.23`,
which silently broke the `exhaustruct` linter.

Starting with `golangci-lint` v1.65.0, the `exhaustruct` linter does not
detect missing fields for types with an alias. Here is the smallest
example I could build to reproduce:

```go
package foo

type Foo struct {
	A int
	B int
}

type FooAlias = Foo

func MyFunc() {
	_ = FooAlias{
		A: 1,
	}
}
```

When running linters on the code above, we observe this behaviour:

✅ `golangci-lint` v1.64.x detects the missing field.
❌ `golangci-lint` v1.65.x does not detect the missing field.
✅ `go-exhaustruct` v3.3.0 compiled with Go 1.22 detects the missing field.
❌ `go-exhaustruct` v3.3.0 compiled with Go 1.23 does not detect the missing field.

I plan to open an issue on `golangci-lint` as well, because it's their
upgrade that broke the linter. However I think the fix will be easiest
to implement in `go-exhaustruct`.
  • Loading branch information
busser authored Feb 21, 2025
1 parent 64da973 commit 91a3d1d
Showing 1 changed file with 25 additions and 0 deletions.
25 changes: 25 additions & 0 deletions analyzer/testdata/src/i/i.go
Original file line number Diff line number Diff line change
Expand Up @@ -223,3 +223,28 @@ func shouldFailExternalTypeAliases() {
_ = TestExternalAliasAlias{} // want "i.TestExternalAliasAlias is missing fields A, B"
_ = TestExternalExcludedAlias{} // want "i.TestExternalExcludedAlias is missing fields A, B"
}

type TestSynonym = Test
type TestSynonymSynonym = TestSynonym
type TestSynonymAlias TestSynonym
type TestSynonymExcluded = Test

func shouldFailTypeSynonyms() {
_ = TestSynonym{} // want "i.Test is missing fields A, B, C, D"
_ = TestSynonymSynonym{} // want "i.Test is missing fields A, B, C, D"
_ = TestSynonymAlias{} // want "i.TestSynonymAlias is missing fields A, B, C, D"
_ = TestSynonymExcluded{} // want "i.Test is missing fields A, B, C, D"
}

type TestExternalSynonym = e.External
type TestExternalSynonymSynonym = TestExternalSynonym
type TestExternalExcludedSynonym = e.ExternalExcluded

func shouldFailExternalTypeSynonyms() {
_ = TestExternalSynonym{} // want "e.External is missing fields A, B"
_ = TestExternalSynonymSynonym{} // want "e.External is missing fields A, B"
}

func shouldSucceedExcludedSynonyms() {
_ = TestExternalExcludedSynonym{}
}

0 comments on commit 91a3d1d

Please sign in to comment.