Commit 248d426b authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent aba7a2d5
...@@ -43,6 +43,7 @@ import ( ...@@ -43,6 +43,7 @@ import (
"os" "os"
"path/filepath" "path/filepath"
"sort" "sort"
"strconv"
"strings" "strings"
"text/template" "text/template"
...@@ -51,9 +52,7 @@ import ( ...@@ -51,9 +52,7 @@ import (
// traceEvent represents 1 trace:event definition // traceEvent represents 1 trace:event definition
type traceEvent struct { type traceEvent struct {
// TODO += Pos token.Position Pkg *Package // package this trace event is part of
// Pkgi *loader.PackageInfo
Pkg *types.Package // package where trace event is declared
// declaration of function to signal the event // declaration of function to signal the event
// the declaration is constructed on the fly via converting e.g. // the declaration is constructed on the fly via converting e.g.
...@@ -67,35 +66,45 @@ type traceEvent struct { ...@@ -67,35 +66,45 @@ type traceEvent struct {
// the func declaration is not added anywhere in the sources - just its // the func declaration is not added anywhere in the sources - just its
// AST + package is virtually constructed. // AST + package is virtually constructed.
*ast.FuncDecl *ast.FuncDecl
typinfo *types.Info // types information for ^^^ FuncDecl
typpkg *types.Package // XXX needed ? same or not same as .Pkg ?
// XXX -> .Pkg.{traceTypeInfo,tracePkg}
// typinfo *types.Info // types information for ^^^ FuncDecl
// typpkg *types.Package // XXX needed ? same or not same as .Pkg ?
// XXX -> = augmented package (original package + funcs for all trace event declarations) ? // XXX -> = augmented package (original package + funcs for all trace event declarations) ?
} }
// traceImport represents 1 trace:import directive // traceImport represents 1 trace:import directive
type traceImport struct { type traceImport struct {
// XXX back link to *Package?
Pos token.Position Pos token.Position
PkgPath string PkgPath string
} }
// Package represents tracing-related information about a package // Package represents tracing-related information about a package
type Package struct { type Package struct {
//Pkgi *loader.PackageInfo Pkgi *loader.PackageInfo // original non-augmented package
Pkg *types.Package // original non-augmented package
Eventv []*traceEvent // trace events this package defines Eventv []*traceEvent // trace events this package defines
Importv []*traceImport // trace imports of other packages Importv []*traceImport // trace imports of other packages
// TODO // original package is augmented with tracing code
// - []*ast.File for added trace:event funcs // information about tracing code is below:
// - fset for ^^^
// - *types.Checker - to typecheck ^^^ files traceFilev []*ast.File // files for added trace:event funcs
// - *types.Package - augmented package with ^^^ traceFset *token.FileSet // fset for ^^^
// - *types.Info - typeinfo for ^^^
traceChecker *types.Checker // to typecheck ^^^
tracePkg *types.Package // original package augmented ^^^
traceTypeInfo *types.Info // typeinfo for ^^^
// XXX tests + xtests
} }
// progImporter is types.Importer that imports packages from loaded loader.Program // progImporter is types.Importer that imports packages from loaded loader.Program
// TODO also import package not yet imported by prog
type progImporter struct { type progImporter struct {
prog *loader.Program prog *loader.Program
} }
...@@ -112,7 +121,6 @@ func (pi *progImporter) Import(path string) (*types.Package, error) { ...@@ -112,7 +121,6 @@ func (pi *progImporter) Import(path string) (*types.Package, error) {
// parseTraceEvent parses trace event definition into traceEvent // parseTraceEvent parses trace event definition into traceEvent
// text is text argument after "//trace:event " // text is text argument after "//trace:event "
//func parseTraceEvent(prog *loader.Program, pkgi *loader.PackageInfo, srcfile *ast.File, pos token.Position, text string) (*traceEvent, error) {
func (p *Package) parseTraceEvent(srcfile *ast.File, pos token.Position, text string) (*traceEvent, error) { func (p *Package) parseTraceEvent(srcfile *ast.File, pos token.Position, text string) (*traceEvent, error) {
posErr := func(format string, argv ...interface{}) error { posErr := func(format string, argv ...interface{}) error {
return fmt.Errorf("%v: "+format, append([]interface{}{pos}, argv...)...) return fmt.Errorf("%v: "+format, append([]interface{}{pos}, argv...)...)
...@@ -123,8 +131,8 @@ func (p *Package) parseTraceEvent(srcfile *ast.File, pos token.Position, text st ...@@ -123,8 +131,8 @@ func (p *Package) parseTraceEvent(srcfile *ast.File, pos token.Position, text st
} }
// prepare artificial package with trace event definition as func declaration // prepare artificial package with trace event definition as func declaration
buf := &Buffer{} // XXX package name must be from trace definition context ? buf := &Buffer{}
buf.emit("package %s", p.Pkg.Name()) buf.emit("package %s", p.Pkgi.Pkg.Name())
// add all imports from original source file // add all imports from original source file
// so that inside it all looks like as if it was in original source context // so that inside it all looks like as if it was in original source context
...@@ -145,16 +153,17 @@ func (p *Package) parseTraceEvent(srcfile *ast.File, pos token.Position, text st ...@@ -145,16 +153,17 @@ func (p *Package) parseTraceEvent(srcfile *ast.File, pos token.Position, text st
buf.emit("\nfunc " + text) buf.emit("\nfunc " + text)
// now parse/typecheck // now parse/typecheck
// tfset := token.NewFileSet()
filename := fmt.Sprintf("%v:%v+trace:event %v", pos.Filename, pos.Line, text) filename := fmt.Sprintf("%v:%v+trace:event %v", pos.Filename, pos.Line, text)
//println("--------") //println("--------")
//println(buf.String()) //println(buf.String())
//println("--------") //println("--------")
tf, err := parser.ParseFile(tfset, filename, buf.String(), 0) tf, err := parser.ParseFile(p.traceFset, filename, buf.String(), 0)
if err != nil { if err != nil {
return nil, err // should already have pos' as prefix return nil, err // should already have pos' as prefix
} }
p.traceFilev = append(p.traceFilev, tf)
// must be: // must be:
// GenDecl{IMPORT} // GenDecl{IMPORT}
// FuncDecl // FuncDecl
...@@ -172,14 +181,20 @@ func (p *Package) parseTraceEvent(srcfile *ast.File, pos token.Position, text st ...@@ -172,14 +181,20 @@ func (p *Package) parseTraceEvent(srcfile *ast.File, pos token.Position, text st
} }
// typecheck prepared file to get trace func argument types // typecheck prepared file to get trace func argument types
err = p.typCheck.Files([]*ast.File{tf}) // (type information lands into p.traceTypeInfo)
err = p.traceChecker.Files([]*ast.File{tf})
if err != nil { if err != nil {
return err // should already have pos' as prefix return nil, err // should already have pos' as prefix
} }
/* return &traceEvent{Pkg: p, FuncDecl: declf}, nil
// typecheck prepared package to get trace func argument types }
conf := types.Config{
// packageTrace returns tracing information about a package
func packageTrace(prog *loader.Program, pkgi *loader.PackageInfo) (*Package, error) {
// prepare Package with typechecker ready to typecheck trace files
// (to get trace func argument types)
tconf := &types.Config{
Importer: &progImporter{prog}, Importer: &progImporter{prog},
// we took imports from original source file verbatim, // we took imports from original source file verbatim,
...@@ -187,27 +202,19 @@ func (p *Package) parseTraceEvent(srcfile *ast.File, pos token.Position, text st ...@@ -187,27 +202,19 @@ func (p *Package) parseTraceEvent(srcfile *ast.File, pos token.Position, text st
DisableUnusedImportCheck: true, DisableUnusedImportCheck: true,
} }
tfset := token.NewFileSet() // XXX ok to separate or use original package fset?
tpkg := types.NewPackage(pkgi.Pkg.Path(), pkgi.Pkg.Name())
tinfo := &types.Info{Types: make(map[ast.Expr]types.TypeAndValue)} tinfo := &types.Info{Types: make(map[ast.Expr]types.TypeAndValue)}
tpkg, err := conf.Check("xxx", tfset, []*ast.File{tf}, tinfo) p := &Package{
if err != nil { Pkgi: pkgi,
return nil, err // should already have pos' as prefix traceFset: tfset,
traceChecker: types.NewChecker(tconf, tfset, tpkg, tinfo),
tracePkg: tpkg,
traceTypeInfo: tinfo,
} }
_ = tpkg // go through files of the original package and process //trace: directives
*/
// XXX +pos? -> pos is already there in tfunc
return &traceEvent{Pkg: pkgi.Pkg, FuncDecl: declf, typinfo: tinfo, typpkg: tpkg}, nil
}
// packageTrace returns tracing information about a package
func packageTrace(prog *loader.Program, pkgi *loader.PackageInfo) (*Package, error) {
// XXX create empty Package instead of vvv
eventv := []*traceEvent{}
importv := []*traceImport{}
// go through files of the package and process //trace: directives
for _, file := range pkgi.Files { // ast.File for _, file := range pkgi.Files { // ast.File
for _, commgroup := range file.Comments { // ast.CommentGroup for _, commgroup := range file.Comments { // ast.CommentGroup
for _, comment := range commgroup.List { // ast.Comment for _, comment := range commgroup.List { // ast.Comment
...@@ -231,27 +238,28 @@ func packageTrace(prog *loader.Program, pkgi *loader.PackageInfo) (*Package, err ...@@ -231,27 +238,28 @@ func packageTrace(prog *loader.Program, pkgi *loader.PackageInfo) (*Package, err
directive, arg := textv[0], textv[1] directive, arg := textv[0], textv[1]
switch directive { switch directive {
case "//trace:event": case "//trace:event":
event, err := parseTraceEvent(prog, pkgi, file, pos, arg) event, err := p.parseTraceEvent(file, pos, arg)
if err != nil { if err != nil {
nil, err return nil, err
} }
eventv = append(eventv, event) // XXX needed here? - better append in parseTraceEvent
p.Eventv = append(p.Eventv, event)
case "//trace:import": case "//trace:import":
// Unqote arg as in regular import // Unqote arg as in regular import
importPath, err := strconv.Unquote(arg) importPath, err := strconv.Unquote(arg)
if err != nil || arg[0] == `'` { if err != nil || arg[0] == '\'' {
nil, fmt.Errorf("%v: invalid trace-import path %v", pos, arg) return nil, fmt.Errorf("%v: invalid trace-import path %v", pos, arg)
} }
// reject duplicate imports // reject duplicate imports
for _, imported := range importv { for _, imported := range p.Importv {
if importPath == imported.PkgPath { if importPath == imported.PkgPath {
return nil, fmt.Errorf("%v: duplicate trace import of %v (previous at %v)", pos, importPath, imported.Pos) return nil, fmt.Errorf("%v: duplicate trace import of %v (previous at %v)", pos, importPath, imported.Pos)
} }
} }
importv = append(importv, &traceImport{Pos: pos, PkgPath: importPath}) p.Importv = append(p.Importv, &traceImport{Pos: pos, PkgPath: importPath})
default: default:
return nil, fmt.Errorf("%v: unknown tracing directive %q", pos, directive) return nil, fmt.Errorf("%v: unknown tracing directive %q", pos, directive)
...@@ -261,10 +269,10 @@ func packageTrace(prog *loader.Program, pkgi *loader.PackageInfo) (*Package, err ...@@ -261,10 +269,10 @@ func packageTrace(prog *loader.Program, pkgi *loader.PackageInfo) (*Package, err
} }
// events and imports go in canonical order // events and imports go in canonical order
sort.Sort(byEventName(eventv)) sort.Sort(byEventName(p.Eventv))
sort.Sort(byPkgPath(importv)) sort.Sort(byPkgPath(p.Importv))
return &Package{Pkgi: pkgi, Eventv: eventv, Importv: importv} return p, nil
} }
// ---------------------------------------- // ----------------------------------------
...@@ -298,7 +306,7 @@ func (te *traceEvent) Argv() string { ...@@ -298,7 +306,7 @@ func (te *traceEvent) Argv() string {
// ArgvTyped returns argument list with types // ArgvTyped returns argument list with types
// types are qualified relative to original package // types are qualified relative to original package
func (te *traceEvent) ArgvTyped() string { func (te *traceEvent) ArgvTyped() string {
return te.ArgvTypedRelativeTo(te.Pkg) return te.ArgvTypedRelativeTo(te.Pkg.tracePkg)
} }
// ArgvTypedRelativeTo returns argument list with types qualified relative to specified package // ArgvTypedRelativeTo returns argument list with types qualified relative to specified package
...@@ -323,7 +331,7 @@ func (te *traceEvent) ArgvTypedRelativeTo(pkg *types.Package) string { ...@@ -323,7 +331,7 @@ func (te *traceEvent) ArgvTypedRelativeTo(pkg *types.Package) string {
} }
arg := strings.Join(namev, ", ") arg := strings.Join(namev, ", ")
typ := te.typinfo.Types[field.Type].Type typ := te.Pkg.traceTypeInfo.Types[field.Type].Type
arg += " " + types.TypeString(typ, qf) arg += " " + types.TypeString(typ, qf)
argv = append(argv, arg) argv = append(argv, arg)
...@@ -343,7 +351,7 @@ func (te *traceEvent) NeedPkgv() []string { ...@@ -343,7 +351,7 @@ func (te *traceEvent) NeedPkgv() []string {
} }
for _, field := range te.FuncDecl.Type.Params.List { for _, field := range te.FuncDecl.Type.Params.List {
typ := te.typinfo.Types[field.Type].Type typ := te.Pkg.traceTypeInfo.Types[field.Type].Type
_ = types.TypeString(typ, qf) _ = types.TypeString(typ, qf)
} }
...@@ -559,7 +567,10 @@ func tracegen(pkgpath string, buildCtx *build.Context, cwd string) error { ...@@ -559,7 +567,10 @@ func tracegen(pkgpath string, buildCtx *build.Context, cwd string) error {
//return nil //return nil
// tracing info for this specified package // tracing info for this specified package
tpkg := packageTrace(lprog, pkgi) tpkg, err := packageTrace(lprog, pkgi)
if err != nil {
return err // XXX err ctx
}
// prologue // prologue
prologue := &Buffer{} prologue := &Buffer{}
...@@ -594,7 +605,10 @@ func tracegen(pkgpath string, buildCtx *build.Context, cwd string) error { ...@@ -594,7 +605,10 @@ func tracegen(pkgpath string, buildCtx *build.Context, cwd string) error {
return fmt.Errorf("%v: package %s must be also regularly imported", timport.Pos, timport.PkgPath) return fmt.Errorf("%v: package %s must be also regularly imported", timport.Pos, timport.PkgPath)
} }
impPkg := packageTrace(lprog, impPkgi) impPkg, err := packageTrace(lprog, impPkgi)
if err != nil {
return err // XXX err ctx
}
for _, event := range impPkg.Eventv { for _, event := range impPkg.Eventv {
needPkg.Add(event.NeedPkgv()...) needPkg.Add(event.NeedPkgv()...)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment