Repository: google/wire (go)

Issue:
Panic when calling wire.Struct with a non-struct first argument
Code like this:

```go
package main

import "github.com/google/wire"

type A struct {
	B string
}

func makeA(string) A {
	panic(wire.Build(wire.Struct(new(*A), "*")))
}
```

causes a panic like this:

```
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x8 pc=0x57f376]

goroutine 1 [running]:
go/types.writeType(0xc0024a15f0, 0x776540, 0x0, 0x0, 0xc0002353a8, 0x1, 0x8)
        /home/gracenoah/.go/src/go/types/typestring.go:120 +0x6a6
go/types.WriteType(...)
        /home/gracenoah/.go/src/go/types/typestring.go:75
go/types.TypeString(0x776540, 0x0, 0x0, 0xc0001ccb40, 0x25)
        /home/gracenoah/.go/src/go/types/typestring.go:67 +0xb1
github.com/google/wire/internal/wire.processStructProvider(0xc0000ea280, 0xc002486aa0, 0xc00247d100, 0x6, 0x1, 0x75)
        /home/gracenoah/go/pkg/mod/github.com/google/wire@v0.3.0/internal/wire/parse.go:806 +0xb11
github.com/google/wire/internal/wire.(*objectCache).processExpr(0xc0021b3880, 0xc002486aa0, 0xc0001d6450, 0x5, 0x778ec0, 0xc00247d100, 0x0, 0x0, 0x20, 0x6d88a0, ...)
        /home/gracenoah/go/pkg/mod/github.com/google/wire@v0.3.0/internal/wire/parse.go:556 +0xb6e
github.com/google/wire/internal/wire.(*objectCache).processNewSet(0xc0021b3880, 0xc002486aa0, 0xc0001d6450, 0x5, 0xc00247d140, 0xc0021b38c0, 0x0, 0x0, 0x0, 0x0, ...)
        /home/gracenoah/go/pkg/mod/github.com/google/wire@v0.3.0/internal/wire/parse.go:592 +0x18c
github.com/google/wire/internal/wire.generateInjectors(0xc002486f50, 0xc0001dcd20, 0x2, 0xc00113f590, 0x29, 0x0, 0x0, 0xc0000ac010)
        /home/gracenoah/go/pkg/mod/github.com/google/wire@v0.3.0/internal/wire/wire.go:176 +0x9f4
github.com/google/wire/internal/wire.Generate(0x77a080, 0xc00008e000, 0xc000016064, 0x1d, 0xc000102000, 0x60, 0x60, 0xc0000ac010, 0x1, 0x1, ...)
        /home/gracenoah/go/pkg/mod/github.com/google/wire@v0.3.0/internal/wire/wire.go:99 +0x411
main.(*genCmd).Execute(0xc000077e78, 0x77a080, 0xc00008e000, 0xc0000a4120, 0x0, 0x0, 0x0, 0x30)
        /home/gracenoah/go/pkg/mod/github.com/google/wire@v0.3.0/cmd/wire/main.go:131 +0x247
main.main()
        /home/gracenoah/go/pkg/mod/github.com/google/wire@v0.3.0/cmd/wire/main.go:71 +0x4dc
exit status 2
```

_Originally posted by @gracenoah in https://github.com/google/wire/issues/201#issuecomment-547765661_

Pull request description:
internal/wire: fix crash when giving wire.Struct a bad first argument
Fixes #219

Patch:
diff --git a/internal/wire/parse.go b/internal/wire/parse.go
index 0af9629..d72e171 100644
--- a/internal/wire/parse.go
+++ b/internal/wire/parse.go
@@ -805,7 +805,7 @@ func processStructProvider(fset *token.FileSet, info *types.Info, call *ast.Call
 	st, ok := structPtr.Elem().Underlying().(*types.Struct)
 	if !ok {
 		return nil, notePosition(fset.Position(call.Pos()),
-			fmt.Errorf(firstArgReqFormat, types.TypeString(st, nil)))
+			fmt.Errorf(firstArgReqFormat, types.TypeString(structPtr, nil)))
 	}
 
 	stExpr := call.Args[0].(*ast.CallExpr)


Test patch:
diff --git a/internal/wire/testdata/StructNotAStruct/foo/foo.go b/internal/wire/testdata/StructNotAStruct/foo/foo.go
new file mode 100644
index 0000000..b308eba
--- /dev/null
+++ b/internal/wire/testdata/StructNotAStruct/foo/foo.go
@@ -0,0 +1,27 @@
+// Copyright 2019 The Wire Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package main
+
+import (
+	"fmt"
+)
+
+func main() {
+	fmt.Println(inject(A{"Hello"}))
+}
+
+type A struct {
+	B string
+}
diff --git a/internal/wire/testdata/StructNotAStruct/foo/wire.go b/internal/wire/testdata/StructNotAStruct/foo/wire.go
new file mode 100644
index 0000000..3bea345
--- /dev/null
+++ b/internal/wire/testdata/StructNotAStruct/foo/wire.go
@@ -0,0 +1,26 @@
+// Copyright 2019 The Wire Authors
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     https://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//+build wireinject
+
+package main
+
+import (
+	"github.com/google/wire"
+)
+
+func inject(a A) string {
+	wire.Build(wire.Struct(new(*A), "*"))
+	return ""
+}
diff --git a/internal/wire/testdata/StructNotAStruct/pkg b/internal/wire/testdata/StructNotAStruct/pkg
new file mode 100644
index 0000000..f7a5c8c
--- /dev/null
+++ b/internal/wire/testdata/StructNotAStruct/pkg
@@ -0,0 +1,1 @@
+example.com/foo
diff --git a/internal/wire/testdata/StructNotAStruct/want/wire_errs.txt b/internal/wire/testdata/StructNotAStruct/want/wire_errs.txt
new file mode 100644
index 0000000..e1ada68
--- /dev/null
+++ b/internal/wire/testdata/StructNotAStruct/want/wire_errs.txt
@@ -0,0 +1,1 @@
+example.com/foo/wire.go:x:y: first argument to Struct must be a pointer to a named struct; found **example.com/foo.A
\ No newline at end of file