@@ -49,3 +49,53 @@ func TestErrorConstructorsShouldReturnPointers(t *testing.T) {
4949 })
5050 }
5151}
52+
53+ // For consistency/convention, tests that all error types implement Error() method with pointer receiver
54+ func TestErrorMethodsShouldHavePointerReceivers (t * testing.T ) {
55+ cfg := & packages.Config {
56+ Mode : packages .NeedFiles | packages .NeedSyntax | packages .NeedTypes | packages .NeedTypesInfo ,
57+ Dir : "." ,
58+ }
59+
60+ pkgs , err := packages .Load (cfg , "." )
61+ require .NoError (t , err )
62+ require .Len (t , pkgs , 1 , "Expected exactly one package" )
63+
64+ pkg := pkgs [0 ]
65+
66+ // Track error type names (structs that end with "Error")
67+ errorTypes := make (map [string ]bool )
68+ for _ , file := range pkg .Syntax {
69+ ast .Inspect (file , func (n ast.Node ) bool {
70+ // Find all struct types that end with "Error"
71+ if typeSpec , ok := n .(* ast.TypeSpec ); ok {
72+ if _ , isStruct := typeSpec .Type .(* ast.StructType ); isStruct {
73+ if strings .HasSuffix (typeSpec .Name .Name , "Error" ) {
74+ errorTypes [typeSpec .Name .Name ] = true
75+ }
76+ }
77+ }
78+ return true
79+ })
80+ }
81+
82+ for _ , file := range pkg .Syntax {
83+ ast .Inspect (file , func (n ast.Node ) bool {
84+ if fn , ok := n .(* ast.FuncDecl ); ok {
85+ // Look for receiver methods
86+ if fn .Recv != nil && len (fn .Recv .List ) > 0 {
87+ recvType := fn .Recv .List [0 ].Type
88+ // Fail if found value receivers in error types
89+ if recv , ok := recvType .(* ast.Ident ); ok && errorTypes [recv .Name ] {
90+ pos := pkg .Fset .Position (fn .Pos ())
91+ assert .Fail (
92+ t , "Error() method should have pointer receiver" ,
93+ "%s: func (%s) Error() should be func (*%s) Error()" ,
94+ pos .Filename , recv .Name , recv .Name )
95+ }
96+ }
97+ }
98+ return true
99+ })
100+ }
101+ }
0 commit comments