MCPcopy
hub / github.com/uber-go/nilaway / inferContracts

Function inferContracts

assertion/function/functioncontracts/infer.go:33–151  ·  view source on GitHub ↗

inferContracts infers function contracts for a function if it has no contracts written. It returns a list of inferred contracts, which may be empty if no contract is inferred but is never nil.

(fn *ssa.Function)

Source from the content-addressed store, hash-verified

31// returns a list of inferred contracts, which may be empty if no contract is inferred but is never
32// nil.
33func inferContracts(fn *ssa.Function) Contracts {
34 nilnessTableSetByBB := make(map[*ssa.BasicBlock]nilnessTableSet)
35 retInstrs := getReturnInstrs(fn) // TODO: Consider *ssa.Panic
36 // No need of an expensive dataflow analysis if we can derive contracts from the return
37 // instructions directly.
38 if ctrs := deriveContracts(retInstrs, fn, nilnessTableSetByBB); len(ctrs) != 0 {
39 return ctrs
40 }
41
42 // Add the entry block to the queue.
43 // TODO: visit fn.Recover.
44 var queue []*ssa.BasicBlock
45 queue = append(queue, fn.Blocks[0])
46 seen := make([]bool, len(fn.Blocks)) // seen[i] means we have visited block i at least once.
47
48 // Visit every block in the queue.
49 for len(queue) > 0 {
50 b := queue[0]
51 queue = queue[1:]
52
53 // Create a nilnessTableSet for this block if it doesn't exist.
54 if _, ok := nilnessTableSetByBB[b]; !ok {
55 nilnessTableSetByBB[b] = newNilnessTableSet()
56 }
57
58 // Propagate nilnessTables from predecessors. Union every predecessor's nilnessTableSet
59 // into this block's nilnessTableSet.
60
61 // Map each predecessor to the nilnessTables propagated from it.
62 nilnessTablesUnderPred := make(map[*ssa.BasicBlock]nilnessTableSet)
63 for _, pred := range b.Preds {
64 var nilnessTableSetOfPred nilnessTableSet
65 if !seen[pred.Index] {
66 // Skip any predecessor that has not been visited yet.
67 continue
68 }
69 if r, ok := nilnessTableSetByBB[pred]; ok && len(r) != 0 {
70 nilnessTableSetOfPred = r
71 } else {
72 nilnessTableSetOfPred = newNilnessTableSet()
73 nilnessTableSetOfPred, _ = add(nilnessTableSetOfPred, nilnessTable{})
74 }
75 nilnessTableSetUnderThisPred := newNilnessTableSet()
76 for _, table := range nilnessTableSetOfPred {
77 // Copy all the existing values.
78 nTable := table.copy()
79 // Learn new nilness from the branch if any.
80 lTable, ok := learnNilness(b, pred, table)
81 if !ok {
82 // conflict found when extending this table, we should drop this table.
83 continue
84 }
85 nTable.addAll(lTable)
86 nilnessTableSetUnderThisPred, _ = add(nilnessTableSetUnderThisPred, nTable)
87 }
88 nilnessTablesUnderPred[pred] = nilnessTableSetUnderThisPred
89 }
90

Callers 1

collectFunctionContractsFunction · 0.85

Calls 9

getReturnInstrsFunction · 0.85
deriveContractsFunction · 0.85
newNilnessTableSetFunction · 0.85
addFunction · 0.85
learnNilnessFunction · 0.85
addAllMethod · 0.80
nilnessOfMethod · 0.80
expandNilnessMethod · 0.80
copyMethod · 0.65

Tested by

no test coverage detected