-
Notifications
You must be signed in to change notification settings - Fork 21
/
functionReturnAnalysis.go
72 lines (62 loc) · 1.39 KB
/
functionReturnAnalysis.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
package main
import (
"fmt"
)
func (s Switch) allPathsReturn() bool {
allPathsReturn := true
hasDefault := false
for _, c := range s.cases {
allPathsReturn = allPathsReturn && c.block.allPathsReturn()
if len(c.expressions) == 0 {
hasDefault = true
} else {
if len(c.expressions) == 1 {
if constant, ok := c.expressions[0].(Constant); ok {
if constant.cType == TYPE_BOOL && constant.cValue == "true" {
hasDefault = true
}
}
}
}
}
return allPathsReturn && hasDefault
}
func (b Block) allPathsReturn() bool {
for _, s := range b.statements {
switch st := s.(type) {
case Block:
if st.allPathsReturn() {
return true
}
case Condition:
if st.block.allPathsReturn() && st.elseBlock.allPathsReturn() {
return true
}
case Loop:
// We cannot guarantee, that the loop body is executed at all. So analysis on its block doesn't matter.
case RangedLoop:
case Switch:
if st.allPathsReturn() {
return true
}
case StructDef:
case FunCall:
case Assignment:
case Break:
return false
case Continue:
return false
case Return:
return true
default:
panic(fmt.Sprintf("Unknown statement '%v' for return analysis", st))
}
}
return false
}
func (b Block) functionReturnAnalysis() error {
if !b.allPathsReturn() {
return fmt.Errorf("%wNot all code paths have a return statement", ErrCritical)
}
return nil
}