github.com/mshitrit/go-mutesting@v0.0.0-20210528084812-ff81dcaedfea/parse.go (about) 1 package mutesting 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/build" 7 "go/parser" 8 "go/token" 9 "go/types" 10 "golang.org/x/tools/go/loader" 11 "io/ioutil" 12 "path/filepath" 13 ) 14 15 // ParseFile parses the content of the given file and returns the corresponding ast.File node and its file set for positional information. 16 // If a fatal error is encountered the error return argument is not nil. 17 func ParseFile(file string) (*ast.File, *token.FileSet, error) { 18 data, err := ioutil.ReadFile(file) 19 if err != nil { 20 return nil, nil, err 21 } 22 23 return ParseSource(data) 24 } 25 26 // ParseSource parses the given source and returns the corresponding ast.File node and its file set for positional information. 27 // If a fatal error is encountered the error return argument is not nil. 28 func ParseSource(data interface{}) (*ast.File, *token.FileSet, error) { 29 fset := token.NewFileSet() 30 31 src, err := parser.ParseFile(fset, "", data, parser.ParseComments|parser.AllErrors) 32 if err != nil { 33 return nil, nil, err 34 } 35 36 return src, fset, err 37 } 38 39 // ParseAndTypeCheckFile parses and type-checks the given file, and returns everything interesting about the file. 40 // If a fatal error is encountered the error return argument is not nil. 41 func ParseAndTypeCheckFile(file string) (*ast.File, *token.FileSet, *types.Package, *types.Info, error) { 42 fileAbs, err := filepath.Abs(file) 43 if err != nil { 44 return nil, nil, nil, nil, fmt.Errorf("Could not absolute the file path of %q: %v", file, err) 45 } 46 dir := filepath.Dir(fileAbs) 47 48 buildPkg, err := build.ImportDir(dir, build.FindOnly) 49 if err != nil { 50 return nil, nil, nil, nil, fmt.Errorf("Could not create build package of %q: %v", file, err) 51 } 52 53 var conf = loader.Config{ 54 ParserMode: parser.AllErrors | parser.ParseComments, 55 } 56 57 if buildPkg.ImportPath != "." { 58 conf.Import(buildPkg.ImportPath) 59 } else { 60 // This is most definitely the case for files inside a "testdata" package 61 conf.CreateFromFilenames(dir, fileAbs) 62 } 63 64 prog, err := conf.Load() 65 if err != nil { 66 return nil, nil, nil, nil, fmt.Errorf("Could not load package of file %q: %v", file, err) 67 } 68 69 pkgInfo := prog.InitialPackages()[0] 70 71 var src *ast.File 72 for _, f := range pkgInfo.Files { 73 if prog.Fset.Position(f.Pos()).Filename == fileAbs { 74 src = f 75 76 break 77 } 78 } 79 80 return src, prog.Fset, pkgInfo.Pkg, &pkgInfo.Info, nil 81 }