github.com/jujuyuki/gospal@v1.0.1-0.20210215170718-af79fae13b20/ssa/build/config.go (about) 1 package build 2 3 import ( 4 "fmt" 5 "go/build" 6 "io" 7 "io/ioutil" 8 "log" 9 "os" 10 11 "github.com/jujuyuki/gospal/ssa" 12 "golang.org/x/tools/go/loader" 13 gossa "golang.org/x/tools/go/ssa" 14 "golang.org/x/tools/go/ssa/ssautil" 15 ) 16 17 // srcReader is a wrapper for source code which can be read through a NewReader. 18 type srcReader interface { 19 NewReader() io.Reader 20 } 21 22 type Configurer interface { 23 Builder 24 Default() Configurer 25 AddBadPkg(pkg, reason string) Configurer 26 WithBuildLog(l io.Writer, flags int) Configurer 27 WithPtaLog(l io.Writer, flags int) Configurer 28 } 29 30 // Config represents a build configuration. 31 type Config struct { 32 badPkgs map[string]string 33 34 bldLog io.Writer // Build log. 35 bldLFlags int // Build log flags. 36 ptaLog io.Writer // Pointer analysis log. 37 ptaLFlags int // Pointer analysis log flags. 38 39 src srcReader // src points to the program source. 40 } 41 42 func newConfig(src srcReader) *Config { 43 return &Config{ 44 badPkgs: make(map[string]string), 45 bldLog: ioutil.Discard, 46 bldLFlags: log.LstdFlags, 47 ptaLog: ioutil.Discard, 48 ptaLFlags: log.LstdFlags, 49 src: src, 50 } 51 } 52 53 // WithBuildLog adds build log to config. 54 func (c *Config) WithBuildLog(l io.Writer, flags int) Configurer { 55 c.bldLog = l 56 c.bldLFlags = flags 57 return c 58 } 59 60 // WithPtaLog adds pointer analysis log to config. 61 func (c *Config) WithPtaLog(l io.Writer, flags int) Configurer { 62 //c := b.(*Config) 63 c.ptaLog = l 64 c.ptaLFlags = flags 65 return c 66 } 67 68 // AddBadPkg marks a package 'bad' to avoid loading. 69 func (c *Config) AddBadPkg(pkg, reason string) Configurer { 70 //c := b.(*Config) 71 c.badPkgs[pkg] = reason 72 return c 73 } 74 75 func (c *Config) Build() (*ssa.Info, error) { 76 var lconf = loader.Config{Build: &build.Default} 77 bldLog := log.New(c.bldLog, "ssabuild: ", c.bldLFlags) 78 79 switch src := c.src.(type) { 80 case *FileSrc: 81 args, err := lconf.FromArgs(src.Files, false /* No tests */) 82 if err != nil { 83 return nil, err 84 } 85 if len(args) > 0 { 86 return nil, fmt.Errorf("surplus arguments: %q", args) 87 } 88 default: 89 os.Chdir(os.TempDir()) 90 parsed, err := lconf.ParseFile("tmp", src.NewReader()) 91 if err != nil { 92 return nil, err 93 } 94 lconf.CreateFromFiles("", parsed) 95 } 96 97 // Load, parse and type-check program 98 lprog, err := lconf.Load() 99 if err != nil { 100 return nil, err 101 } 102 bldLog.Print("Program loaded and type checked") 103 104 prog := ssautil.CreateProgram(lprog, gossa.GlobalDebug|gossa.BareInits) 105 106 var ignoredPkgs []string 107 if len(c.badPkgs) == 0 { 108 prog.Build() 109 } else { 110 for _, info := range lprog.AllPackages { 111 if reason, badPkg := c.badPkgs[info.Pkg.Path()]; badPkg { 112 bldLog.Printf("Skip package: %s (%s)", info.Pkg.Name(), reason) 113 ignoredPkgs = append(ignoredPkgs, info.Pkg.Name()) 114 } else { 115 prog.Package(info.Pkg).Build() 116 } 117 } 118 } 119 120 return &ssa.Info{ 121 IgnoredPkgs: ignoredPkgs, 122 FSet: lprog.Fset, 123 Prog: prog, 124 LProg: lprog, 125 BldLog: c.bldLog, 126 PtaLog: c.ptaLog, 127 }, nil 128 } 129 130 // Default returns a default configuration for static analysis. 131 func (c *Config) Default() Configurer { 132 return c. 133 AddBadPkg("reflect", "Reflection is not supported"). 134 AddBadPkg("runtime", "Runtime is ignored for static analysis"). 135 AddBadPkg("internal/singleflight", "Singleflight uses unsupported []chan"). 136 AddBadPkg("fmt", "Fmt is known to cause unwanted recursive loops") 137 }