type funcFlagsAnalyzer … type pstate … const psNoInfo … const psCallsPanic … const psMayReturn … const psTop … func makeFuncFlagsAnalyzer(fn *ir.Func) *funcFlagsAnalyzer { … } // setResults transfers func flag results to 'funcProps'. func (ffa *funcFlagsAnalyzer) setResults(funcProps *FuncProps) { … } func (ffa *funcFlagsAnalyzer) getState(n ir.Node) pstate { … } func (ffa *funcFlagsAnalyzer) setState(n ir.Node, st pstate) { … } func (ffa *funcFlagsAnalyzer) updateState(n ir.Node, st pstate) { … } func (ffa *funcFlagsAnalyzer) panicPathTable() map[ir.Node]pstate { … } // blockCombine merges together states as part of a linear sequence of // statements, where 'pred' and 'succ' are analysis results for a pair // of consecutive statements. Examples: // // case 1: case 2: // panic("foo") if q { return x } <-pred // return x panic("boo") <-succ // // In case 1, since the pred state is "always panic" it doesn't matter // what the succ state is, hence the state for the combination of the // two blocks is "always panics". In case 2, because there is a path // to return that avoids the panic in succ, the state for the // combination of the two statements is "may return". func blockCombine(pred, succ pstate) pstate { … } // branchCombine combines two states at a control flow branch point where // either p1 or p2 executes (as in an "if" statement). func branchCombine(p1, p2 pstate) pstate { … } // stateForList walks through a list of statements and computes the // state/disposition for the entire list as a whole, as well // as updating disposition of intermediate nodes. func (ffa *funcFlagsAnalyzer) stateForList(list ir.Nodes) pstate { … } func isMainMain(fn *ir.Func) bool { … } func isWellKnownFunc(s *types.Sym, pkg, name string) bool { … } // isExitCall reports TRUE if the node itself is an unconditional // call to os.Exit(), a panic, or a function that does likewise. func isExitCall(n ir.Node) bool { … } // pessimize is called to record the fact that we saw something in the // function that renders it entirely impossible to analyze. func (ffa *funcFlagsAnalyzer) pessimize() { … } // shouldVisit reports TRUE if this is an interesting node from the // perspective of computing function flags. NB: due to the fact that // ir.CallExpr implements the Stmt interface, we wind up visiting // a lot of nodes that we don't really need to, but these can // simply be screened out as part of the visit. func shouldVisit(n ir.Node) bool { … } // nodeVisitPost helps implement the propAnalyzer interface; when // called on a given node, it decides the disposition of that node // based on the state(s) of the node's children. func (ffa *funcFlagsAnalyzer) nodeVisitPost(n ir.Node) { … } func (ffa *funcFlagsAnalyzer) nodeVisitPre(n ir.Node) { … }