tg.wantStale("mypkg", "./testgo list mypkg claims mypkg is NOT stale after removing y.go; should be stale")
}
+func TestWildcardMatchesSyntaxErrorDirs(t *testing.T) {
+ tg := testgo(t)
+ defer tg.cleanup()
+ tg.tempFile("src/mypkg/x.go", `package mypkg`)
+ tg.tempFile("src/mypkg/y.go", `pkg mypackage`)
+ tg.setenv("GOPATH", tg.path("."))
+ tg.cd(tg.path("src/mypkg"))
+ tg.runFail("list", "./...")
+ tg.runFail("build", "./...")
+ tg.runFail("install", "./...")
+}
+
func TestGoListWithTags(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
if !match(name) {
return nil
}
- if _, err = buildContext.ImportDir(path, 0); err != nil {
+
+ // We keep the directory if we can import it, or if we can't import it
+ // due to invalid Go source files. This means that directories containing
+ // parse errors will be built (and fail) instead of being silently skipped
+ // as not matching the pattern. Go 1.5 and earlier skipped, but that
+ // behavior means people miss serious mistakes.
+ // See golang.org/issue/11407.
+ if p, err := buildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) {
if _, noGo := err.(*build.NoGoError); !noGo {
log.Print(err)
}
GoFiles []string // .go source files (excluding CgoFiles, TestGoFiles, XTestGoFiles)
CgoFiles []string // .go source files that import "C"
IgnoredGoFiles []string // .go source files ignored for this build
+ InvalidGoFiles []string // .go source files with detected problems (parse error, wrong package name, and so on)
CFiles []string // .c source files
CXXFiles []string // .cc, .cpp and .cxx source files
MFiles []string // .m (Objective-C) source files
return p, err
}
+ var badGoError error
var Sfiles []string // files with ".S" (capital S)
var firstFile, firstCommentFile string
imported := make(map[string][]token.Position)
name := d.Name()
ext := nameExt(name)
+ badFile := func(err error) {
+ if badGoError == nil {
+ badGoError = err
+ }
+ p.InvalidGoFiles = append(p.InvalidGoFiles, name)
+ }
+
match, data, filename, err := ctxt.matchFile(p.Dir, name, true, allTags)
if err != nil {
- return p, err
+ badFile(err)
+ continue
}
if !match {
if ext == ".go" {
pf, err := parser.ParseFile(fset, filename, data, parser.ImportsOnly|parser.ParseComments)
if err != nil {
- return p, err
+ badFile(err)
+ continue
}
pkg := pf.Name.Name
p.Name = pkg
firstFile = name
} else if pkg != p.Name {
- return p, &MultiplePackageError{
+ badFile(&MultiplePackageError{
Dir: p.Dir,
Packages: []string{p.Name, pkg},
Files: []string{firstFile, name},
- }
+ })
+ p.InvalidGoFiles = append(p.InvalidGoFiles, name)
}
if pf.Doc != nil && p.Doc == "" {
p.Doc = doc.Synopsis(pf.Doc.Text())
if line != 0 {
com, err := strconv.Unquote(qcom)
if err != nil {
- return p, fmt.Errorf("%s:%d: cannot parse import comment", filename, line)
- }
- if p.ImportComment == "" {
+ badFile(fmt.Errorf("%s:%d: cannot parse import comment", filename, line))
+ } else if p.ImportComment == "" {
p.ImportComment = com
firstCommentFile = name
} else if p.ImportComment != com {
- return p, fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir)
+ badFile(fmt.Errorf("found import comments %q (%s) and %q (%s) in %s", p.ImportComment, firstCommentFile, com, name, p.Dir))
}
}
}
}
if path == "C" {
if isTest {
- return p, fmt.Errorf("use of cgo in test %s not supported", filename)
- }
- cg := spec.Doc
- if cg == nil && len(d.Specs) == 1 {
- cg = d.Doc
- }
- if cg != nil {
- if err := ctxt.saveCgo(filename, p, cg); err != nil {
- return p, err
+ badFile(fmt.Errorf("use of cgo in test %s not supported", filename))
+ } else {
+ cg := spec.Doc
+ if cg == nil && len(d.Specs) == 1 {
+ cg = d.Doc
}
+ if cg != nil {
+ if err := ctxt.saveCgo(filename, p, cg); err != nil {
+ badFile(err)
+ }
+ }
+ isCgo = true
}
- isCgo = true
}
}
}
p.GoFiles = append(p.GoFiles, name)
}
}
+ if badGoError != nil {
+ return p, badGoError
+ }
if len(p.GoFiles)+len(p.CgoFiles)+len(p.TestGoFiles)+len(p.XTestGoFiles) == 0 {
return p, &NoGoError{p.Dir}
}