.gitignore added
[dotfiles/.git] / .config / coc / extensions / coc-go-data / tools / pkg / mod / honnef.co / go / tools@v0.1.1 / go / callgraph / cha / cha.go
1 // Copyright 2014 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 // Package cha computes the call graph of a Go program using the Class
6 // Hierarchy Analysis (CHA) algorithm.
7 //
8 // CHA was first described in "Optimization of Object-Oriented Programs
9 // Using Static Class Hierarchy Analysis", Jeffrey Dean, David Grove,
10 // and Craig Chambers, ECOOP'95.
11 //
12 // CHA is related to RTA (see go/callgraph/rta); the difference is that
13 // CHA conservatively computes the entire "implements" relation between
14 // interfaces and concrete types ahead of time, whereas RTA uses dynamic
15 // programming to construct it on the fly as it encounters new functions
16 // reachable from main.  CHA may thus include spurious call edges for
17 // types that haven't been instantiated yet, or types that are never
18 // instantiated.
19 //
20 // Since CHA conservatively assumes that all functions are address-taken
21 // and all concrete types are put into interfaces, it is sound to run on
22 // partial programs, such as libraries without a main or test function.
23 //
24 package cha
25
26 import (
27         "go/types"
28
29         "honnef.co/go/tools/go/callgraph"
30         "honnef.co/go/tools/go/ir"
31         "honnef.co/go/tools/go/ir/irutil"
32
33         "golang.org/x/tools/go/types/typeutil"
34 )
35
36 // CallGraph computes the call graph of the specified program using the
37 // Class Hierarchy Analysis algorithm.
38 //
39 func CallGraph(prog *ir.Program) *callgraph.Graph {
40         cg := callgraph.New(nil) // TODO(adonovan) eliminate concept of rooted callgraph
41
42         allFuncs := irutil.AllFunctions(prog)
43
44         // funcsBySig contains all functions, keyed by signature.  It is
45         // the effective set of address-taken functions used to resolve
46         // a dynamic call of a particular signature.
47         var funcsBySig typeutil.Map // value is []*ir.Function
48
49         // methodsByName contains all methods,
50         // grouped by name for efficient lookup.
51         methodsByName := make(map[string][]*ir.Function)
52
53         // methodsMemo records, for every abstract method call call I.f on
54         // interface type I, the set of concrete methods C.f of all
55         // types C that satisfy interface I.
56         methodsMemo := make(map[*types.Func][]*ir.Function)
57         lookupMethods := func(m *types.Func) []*ir.Function {
58                 methods, ok := methodsMemo[m]
59                 if !ok {
60                         I := m.Type().(*types.Signature).Recv().Type().Underlying().(*types.Interface)
61                         for _, f := range methodsByName[m.Name()] {
62                                 C := f.Signature.Recv().Type() // named or *named
63                                 if types.Implements(C, I) {
64                                         methods = append(methods, f)
65                                 }
66                         }
67                         methodsMemo[m] = methods
68                 }
69                 return methods
70         }
71
72         for f := range allFuncs {
73                 if f.Signature.Recv() == nil {
74                         // Package initializers can never be address-taken.
75                         if f.Name() == "init" && f.Synthetic == ir.SyntheticPackageInitializer {
76                                 continue
77                         }
78                         funcs, _ := funcsBySig.At(f.Signature).([]*ir.Function)
79                         funcs = append(funcs, f)
80                         funcsBySig.Set(f.Signature, funcs)
81                 } else {
82                         methodsByName[f.Name()] = append(methodsByName[f.Name()], f)
83                 }
84         }
85
86         addEdge := func(fnode *callgraph.Node, site ir.CallInstruction, g *ir.Function) {
87                 gnode := cg.CreateNode(g)
88                 callgraph.AddEdge(fnode, site, gnode)
89         }
90
91         addEdges := func(fnode *callgraph.Node, site ir.CallInstruction, callees []*ir.Function) {
92                 // Because every call to a highly polymorphic and
93                 // frequently used abstract method such as
94                 // (io.Writer).Write is assumed to call every concrete
95                 // Write method in the program, the call graph can
96                 // contain a lot of duplication.
97                 //
98                 // TODO(adonovan): opt: consider factoring the callgraph
99                 // API so that the Callers component of each edge is a
100                 // slice of nodes, not a singleton.
101                 for _, g := range callees {
102                         addEdge(fnode, site, g)
103                 }
104         }
105
106         for f := range allFuncs {
107                 fnode := cg.CreateNode(f)
108                 for _, b := range f.Blocks {
109                         for _, instr := range b.Instrs {
110                                 if site, ok := instr.(ir.CallInstruction); ok {
111                                         call := site.Common()
112                                         if call.IsInvoke() {
113                                                 addEdges(fnode, site, lookupMethods(call.Method))
114                                         } else if g := call.StaticCallee(); g != nil {
115                                                 addEdge(fnode, site, g)
116                                         } else if _, ok := call.Value.(*ir.Builtin); !ok {
117                                                 callees, _ := funcsBySig.At(call.Signature()).([]*ir.Function)
118                                                 addEdges(fnode, site, callees)
119                                         }
120                                 }
121                         }
122                 }
123         }
124
125         return cg
126 }