lint: avoid false positives with custom errors-package

When using `errors.New(fmt.Sprintf(...))`,
lint will alert that you should use `fmt.Errorf(...)`.

Before this patch, this alert was also displayed
when using a custom errors-package.
There are valid use cases to use `errors.New(fmt.Sprintf(...))`
in a custom errors-package context.

This patch avoids the "false positive" alert
when a custom errors-package is imported in the current file.

Fixes golang/lint#350

Change-Id: I7cc82a3435b184f8b4cad0752a75d44f33536dce
GitHub-Last-Rev: ad257d26802aca316d6b83758fcb143083934587
GitHub-Pull-Request: golang/lint#360
Reviewed-on: https://go-review.googlesource.com/96091
Reviewed-by: Andrew Bonventre <andybons@golang.org>
diff --git a/lint.go b/lint.go
index cc6fef2..f60106c 100644
--- a/lint.go
+++ b/lint.go
@@ -23,6 +23,7 @@
 	"unicode"
 	"unicode/utf8"
 
+	"golang.org/x/tools/go/ast/astutil"
 	"golang.org/x/tools/go/gcexportdata"
 )
 
@@ -1126,6 +1127,9 @@
 		if !isErrorsNew && !isTestingError {
 			return true
 		}
+		if !f.imports("errors") {
+			return true
+		}
 		arg := ce.Args[0]
 		ce, ok = arg.(*ast.CallExpr)
 		if !ok || !isPkgDot(ce.Fun, "fmt", "Sprintf") {
@@ -1694,6 +1698,20 @@
 	return rx.FindStringSubmatch(line)
 }
 
+// imports returns true if the current file imports the specified package path.
+func (f *file) imports(importPath string) bool {
+	all := astutil.Imports(f.fset, f.f)
+	for _, p := range all {
+		for _, i := range p {
+			uq, err := strconv.Unquote(i.Path.Value)
+			if err == nil && importPath == uq {
+				return true
+			}
+		}
+	}
+	return false
+}
+
 // srcLine returns the complete line at p, including the terminating newline.
 func srcLine(src []byte, p token.Position) string {
 	// Run to end of line in both directions if not at line start/end.
diff --git a/testdata/errorf-custom.go b/testdata/errorf-custom.go
new file mode 100644
index 0000000..7980c8d
--- /dev/null
+++ b/testdata/errorf-custom.go
@@ -0,0 +1,25 @@
+// Test for allowed errors.New(fmt.Sprintf()) when a custom errors package is imported.
+
+// Package foo ...
+package foo
+
+import (
+	"fmt"
+
+	"github.com/pkg/errors"
+)
+
+func f(x int) error {
+	if x > 10 {
+		return errors.New(fmt.Sprintf("something %d", x)) // OK
+	}
+	if x > 5 {
+		return errors.New(g("blah")) // OK
+	}
+	if x > 4 {
+		return errors.New("something else") // OK
+	}
+	return nil
+}
+
+func g(s string) string { return "prefix: " + s }