aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/declextract/interface.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2025-04-09 10:38:03 +0200
committerDmitry Vyukov <dvyukov@google.com>2025-04-10 17:07:48 +0000
commit2d9fa31cf7abaddf944824814053e67b4d5c478e (patch)
tree12c10728542789e81ec4eef0496250933516e217 /pkg/declextract/interface.go
parenta6ec893839824d1b080d8c0c02360e5db5c6d39f (diff)
pkg/declextract: export syscall variants as separate interfaces
Export each syscall variant (e.g. fcnt$*) as a separate interface. Effectively these are separate syscalls. We will want this for ioctl as well (it's not 1 interface).
Diffstat (limited to 'pkg/declextract/interface.go')
-rw-r--r--pkg/declextract/interface.go44
1 files changed, 23 insertions, 21 deletions
diff --git a/pkg/declextract/interface.go b/pkg/declextract/interface.go
index d891b4899..e7a859da9 100644
--- a/pkg/declextract/interface.go
+++ b/pkg/declextract/interface.go
@@ -19,6 +19,9 @@ type Interface struct {
ManualDescriptions bool
AutoDescriptions bool
ReachableLOC int
+
+ scopeArg int
+ scopeVal string
}
const (
@@ -38,7 +41,7 @@ func (ctx *context) noteInterface(iface *Interface) {
func (ctx *context) finishInterfaces() {
for _, iface := range ctx.interfaces {
- iface.ReachableLOC = ctx.reachableLOC(iface.Func, iface.Files[0])
+ iface.ReachableLOC = ctx.reachableLOC(iface.Func, iface.Files[0], iface.scopeArg, iface.scopeVal)
slices.Sort(iface.Files)
iface.Files = slices.Compact(iface.Files)
if iface.Access == "" {
@@ -57,7 +60,6 @@ func (ctx *context) processFunctions() {
ctx.funcs[fn.Name] = fn
}
}
- nocallers := 0
for _, fn := range ctx.Functions {
for _, scope := range fn.Scopes {
for _, callee := range scope.Calls {
@@ -65,34 +67,26 @@ func (ctx *context) processFunctions() {
if called == nil || called == fn {
continue
}
- fn.calls = append(fn.calls, called)
+ scope.calls = append(scope.calls, called)
called.callers++
}
}
- if len(fn.calls) == 0 {
- nocallers++
- }
}
}
-func (ctx *context) reachableLOC(name, file string) int {
+func (ctx *context) reachableLOC(name, file string, scopeArg int, scopeVal string) int {
fn := ctx.findFunc(name, file)
if fn == nil {
ctx.warn("can't find function %v called in %v", name, file)
return 0
}
- reachable := make(map[*Function]bool)
- ctx.collectRachable(fn, reachable)
- loc := 0
- for fn := range reachable {
- for _, scope := range fn.Scopes {
- loc += scope.LOC
- }
- }
- return loc
+ scopeFnArgs := ctx.inferArgFlow(fnArg{fn, scopeArg})
+ visited := make(map[*Function]bool)
+ return ctx.collectLOC(fn, scopeFnArgs, scopeVal, visited)
}
-func (ctx *context) collectRachable(fn *Function, reachable map[*Function]bool) {
+func (ctx *context) collectLOC(fn *Function, scopeFnArgs map[fnArg]bool, scopeVal string,
+ visited map[*Function]bool) int {
// Ignore very common functions when computing reachability for complexity analysis.
// Counting kmalloc/printk against each caller is not useful (they have ~10K calls).
// There are also subsystem common functions (e.g. functions called in some parts of fs/net).
@@ -103,13 +97,21 @@ func (ctx *context) collectRachable(fn *Function, reachable map[*Function]bool)
// 3 callers - 16527 functions
const commonFuncThreshold = 5
- reachable[fn] = true
- for _, callee := range fn.calls {
- if reachable[callee] || callee.callers >= commonFuncThreshold {
+ visited[fn] = true
+ loc := max(0, fn.EndLine-fn.StartLine-1)
+ for _, scope := range fn.Scopes {
+ if !relevantScope(scopeFnArgs, scopeVal, scope) {
+ loc -= max(0, scope.EndLine-scope.StartLine)
continue
}
- ctx.collectRachable(callee, reachable)
+ for _, callee := range scope.calls {
+ if visited[callee] || callee.callers >= commonFuncThreshold {
+ continue
+ }
+ loc += ctx.collectLOC(callee, scopeFnArgs, scopeVal, visited)
+ }
}
+ return loc
}
func (ctx *context) findFunc(name, file string) *Function {