go/loader: improve robustness in face of input errors

    Before this change, many kinds of error would cause the loader to stop.
    making it brittle when analyzing large codebases, as in "godoc -analysis".

    This change moves operations that used to occur during
    configuration---(*build.Context).Import, loading, and parsing of
    initial packages---into the Load call, and ensures that all failures
    during Loading are reported at the end so that the maximum amount of
    progress is made.

    Also: redesign the tests and add many new cases.

Change-Id: Ia8cd99416af7c5d4a5fe133908adfa83676d401f
Reviewed-on: https://go-review.googlesource.com/3626
Reviewed-by: Robert Griesemer <gri@golang.org>
diff --git a/go/loader/util.go b/go/loader/util.go
index 1d782e1..1166c92 100644
--- a/go/loader/util.go
+++ b/go/loader/util.go
@@ -11,9 +11,10 @@
 	"go/token"
 	"io"
 	"os"
-	"path/filepath"
 	"strconv"
 	"sync"
+
+	"golang.org/x/tools/go/buildutil"
 )
 
 // parseFiles parses the Go source files within directory dir and
@@ -27,21 +28,13 @@
 	if displayPath == nil {
 		displayPath = func(path string) string { return path }
 	}
-	isAbs := filepath.IsAbs
-	if ctxt.IsAbsPath != nil {
-		isAbs = ctxt.IsAbsPath
-	}
-	joinPath := filepath.Join
-	if ctxt.JoinPath != nil {
-		joinPath = ctxt.JoinPath
-	}
 	var wg sync.WaitGroup
 	n := len(files)
 	parsed := make([]*ast.File, n)
 	errors := make([]error, n)
 	for i, file := range files {
-		if !isAbs(file) {
-			file = joinPath(dir, file)
+		if !buildutil.IsAbsPath(ctxt, file) {
+			file = buildutil.JoinPath(ctxt, dir, file)
 		}
 		wg.Add(1)
 		go func(i int, file string) {