/
weave.go
111 lines (103 loc) · 2.9 KB
/
weave.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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
// Package weave provides the weaver.
package weave
import (
"go/ast"
"go/parser"
"go/types"
"log"
"strings"
"golang.org/x/tools/go/loader"
"github.com/AkihiroSuda/aspectgo/aspect"
"github.com/AkihiroSuda/aspectgo/compiler/parse"
"github.com/AkihiroSuda/aspectgo/compiler/util"
"github.com/AkihiroSuda/aspectgo/compiler/weave/match"
)
// Weave weaves aspect files to the target package and emit the woven files to wovenGOPATH.
func Weave(wovenGOPATH string, target string, af *parse.AspectFile) ([]string, error) {
_, prog, err := loadTarget(target)
if err != nil {
return nil, err
}
matched, pointcutsByIdent, err := findMatchedThings(prog, af.Pointcuts)
if err != nil {
return nil, err
}
if util.DebugMode {
log.Printf("Found %d matches", len(matched))
}
if len(matched) != len(pointcutsByIdent) {
log.Fatal("impl error")
}
if len(matched) == 0 {
return []string{}, nil
}
rewrittenFnames1, err := rewriteAspectFile(wovenGOPATH, af)
if err != nil {
return nil, err
}
rw := &rewriter{
Program: prog,
Matched: matched,
Aspects: pointcutMapToAspectMap(af.Pointcuts),
PointcutsByIdent: pointcutsByIdent,
}
rewrittenFnames2, err := rewriteProgram(wovenGOPATH, rw)
if err != nil {
return nil, err
}
return append(rewrittenFnames1, rewrittenFnames2...), nil
}
func pointcutMapToAspectMap(pointcuts map[*types.Named]aspect.Pointcut) map[aspect.Pointcut]*types.Named {
aspects := make(map[aspect.Pointcut]*types.Named)
for asp, pc := range pointcuts {
x, ok := aspects[pc]
if ok {
log.Printf("pointcut conflict: %s vs %s", x, asp)
}
aspects[pc] = asp
}
return aspects
}
func findMatchedThings(prog *loader.Program, pointcuts map[*types.Named]aspect.Pointcut) (map[*ast.Ident]types.Object, map[*ast.Ident]aspect.Pointcut, error) {
objs := make(map[*ast.Ident]types.Object)
pointcutsByIdent := make(map[*ast.Ident]aspect.Pointcut)
for _, pkgInfo := range prog.InitialPackages() {
for id, obj := range pkgInfo.Uses {
posn := prog.Fset.Position(id.Pos())
if strings.HasSuffix(posn.Filename, "_aspect.go") {
continue
}
for _, pointcut := range pointcuts {
matched := match.ObjMatchPointcut(prog, id, obj, pointcut)
if !matched {
continue
}
if util.DebugMode {
log.Printf("MATCHED %s:%d:%d: %s, pointcut=%s",
posn.Filename, posn.Line, posn.Column,
obj, pointcut)
}
objs[id] = obj
xpt, ok := pointcutsByIdent[id]
if ok {
log.Printf("OVERRIDE %s:%d:%d: %s, pointcut=%s vs old=%s",
posn.Filename, posn.Line, posn.Column,
obj, pointcut, xpt)
}
pointcutsByIdent[id] = pointcut
}
}
}
return objs, pointcutsByIdent, nil
}
func loadTarget(target string) (*loader.Config, *loader.Program, error) {
conf := loader.Config{
ParserMode: parser.ParseComments,
}
conf.Import(target)
prog, err := conf.Load()
if err != nil {
return nil, nil, err
}
return &conf, prog, nil
}