const usageMessage … func usage() { … } var mode … var varVar … var output … var outfilelist … var htmlOut … var funcOut … var pkgcfg … var pkgconfig … var outputfiles … var profile … var counterStmt … var covervarsoutfile … var cmode … var cgran … const atomicPackagePath … const atomicPackageName … func main() { … } // parseFlags sets the profile and counterStmt globals and performs validations. func parseFlags() error { … } func readOutFileList(path string) ([]string, error) { … } func readPackageConfig(path string) error { … } type Block … type Package … type Func … type File … // findText finds text in the original source, starting at pos. // It correctly skips over comments and assumes it need not // handle quoted strings. // It returns a byte offset within f.src. func (f *File) findText(pos token.Pos, text string) int { … } // Visit implements the ast.Visitor interface. func (f *File) Visit(node ast.Node) ast.Visitor { … } func mkCounterVarName(idx int) string { … } func mkPackageIdVar() string { … } func mkMetaVar() string { … } func mkPackageIdExpression() string { … } func (f *File) preFunc(fn ast.Node, fname string) { … } func (f *File) postFunc(fn ast.Node, funcname string, flit bool, body *ast.BlockStmt) { … } func annotate(names []string) { … } func (p *Package) annotateFile(name string, fd io.Writer) { … } // setCounterStmt returns the expression: __count[23] = 1. func setCounterStmt(f *File, counter string) string { … } // incCounterStmt returns the expression: __count[23]++. func incCounterStmt(f *File, counter string) string { … } // atomicCounterStmt returns the expression: atomic.AddUint32(&__count[23], 1) func atomicCounterStmt(f *File, counter string) string { … } // newCounter creates a new counter expression of the appropriate form. func (f *File) newCounter(start, end token.Pos, numStmt int) string { … } // addCounters takes a list of statements and adds counters to the beginning of // each basic block at the top level of that list. For instance, given // // S1 // if cond { // S2 // } // S3 // // counters will be added before S1 and before S3. The block containing S2 // will be visited in a separate call. // TODO: Nested simple blocks get unnecessary (but correct) counters func (f *File) addCounters(pos, insertPos, blockEnd token.Pos, list []ast.Stmt, extendToClosingBrace bool) { … } // hasFuncLiteral reports the existence and position of the first func literal // in the node, if any. If a func literal appears, it usually marks the termination // of a basic block because the function body is itself a block. // Therefore we draw a line at the start of the body of the first function literal we find. // TODO: what if there's more than one? Probably doesn't matter much. func hasFuncLiteral(n ast.Node) (bool, token.Pos) { … } // statementBoundary finds the location in s that terminates the current basic // block in the source. func (f *File) statementBoundary(s ast.Stmt) token.Pos { … } // endsBasicSourceBlock reports whether s changes the flow of control: break, if, etc., // or if it's just problematic, for instance contains a function literal, which will complicate // accounting due to the block-within-an expression. func (f *File) endsBasicSourceBlock(s ast.Stmt) bool { … } // isControl reports whether s is a control statement that, if labeled, cannot be // separated from its label. func (f *File) isControl(s ast.Stmt) bool { … } type funcLitFinder … func (f *funcLitFinder) Visit(node ast.Node) (w ast.Visitor) { … } func (f *funcLitFinder) found() bool { … } type block1 … // offset translates a token position into a 0-indexed byte offset. func (f *File) offset(pos token.Pos) int { … } // addVariables adds to the end of the file the declarations to set up the counter and position variables. func (f *File) addVariables(w io.Writer) { … } type pos2 … var seenPos2 … // dedup takes a token.Position pair and returns a pair that does not // duplicate any existing pair. The returned pair will have the Offset // fields cleared. func dedup(p1, p2 token.Position) (r1, r2 token.Position) { … } func (p *Package) emitMetaData(w io.Writer) { … } // atomicOnAtomic returns true if we're instrumenting // the sync/atomic package AND using atomic mode. func atomicOnAtomic() bool { … } // atomicPackagePrefix returns the import path prefix used to refer to // our special import of sync/atomic; this is either set to the // constant atomicPackageName plus a dot or the empty string if we're // instrumenting the sync/atomic package itself. func atomicPackagePrefix() string { … } func (p *Package) emitMetaFile(outpath string) { … }