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  }