Commit dcf3f530 authored by Kirill Smelkov's avatar Kirill Smelkov

.

parent b6676718
......@@ -74,9 +74,20 @@ type traceImport struct {
// XXX back link to *Package?
Pos token.Position
PkgName string
PkgPath string
}
// ImportSpec returns string representation of import spec
func (ti *traceImport) ImportSpec() string {
t := ti.PkgName
if t != "" {
t += " "
}
t += fmt.Sprintf("%q", ti.PkgPath)
return t
}
// Package represents tracing-related information about a package
type Package struct {
Pkgi *loader.PackageInfo // original non-augmented package
......@@ -186,6 +197,44 @@ func (p *Package) parseTraceEvent(srcfile *ast.File, pos token.Position, text st
return &traceEvent{Pkgt: p, FuncDecl: declf}, nil
}
// parseTraceImport parses trace import directive into traceImport
// text is text argument after "//trace:import "
func (p *Package) parseTraceImport(pos token.Position, text string) (*traceImport, error) {
// //trace:import "path/to/pkg"
// //traca:import name "path/to/pkg"
if len(text) == 0 {
return nil, fmt.Errorf("%v: empty trace-import spec", pos)
}
pkgname := ""
pkgqpath := text
if !(text[0] == '"' || text[0] == '\'') {
textv := strings.SplitN(text, " ", 2)
if len(textv) != 2 {
return nil, fmt.Errorf("%v: invalid trace-import spec %v", pos, text)
}
pkgname = textv[0]
pkgqpath = textv[1]
}
// Unqote pkgqpath as in regular import does
pkgpath, err := strconv.Unquote(pkgqpath)
if err != nil || pkgpath == "" || pkgpath[0] == '\'' {
return nil, fmt.Errorf("%v: invalid trace-import path %v", pos, pkgqpath)
}
// reject duplicate imports
for _, imported := range p.Importv {
if pkgpath == imported.PkgPath {
return nil, fmt.Errorf("%v: duplicate trace import of %v (previous at %v)", pos, pkgpath, imported.Pos)
}
}
return &traceImport{Pos: pos, PkgName: pkgname, PkgPath: pkgpath}, nil
}
// 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
......@@ -263,19 +312,13 @@ func packageTrace(prog *loader.Program, pkgi *loader.PackageInfo) (*Package, err
p.Eventv = append(p.Eventv, event)
case "//trace:import":
// Unqote arg as in regular import
importPath, err := strconv.Unquote(arg)
if err != nil || arg[0] == '\'' {
return nil, fmt.Errorf("%v: invalid trace-import path %v", pos, arg)
imported, err := p.parseTraceImport(pos, arg)
if err != nil {
return nil, err
}
// reject duplicate imports
for _, imported := range p.Importv {
if importPath == imported.PkgPath {
return nil, fmt.Errorf("%v: duplicate trace import of %v (previous at %v)", pos, importPath, imported.Pos)
}
}
p.Importv = append(p.Importv, &traceImport{Pos: pos, PkgPath: importPath})
// XXX needed here? - better append in parseTraceEvent
p.Importv = append(p.Importv, imported)
default:
return nil, fmt.Errorf("%v: unknown tracing directive %q", pos, directive)
......@@ -322,11 +365,12 @@ func (te *traceEvent) Argv() string {
// ArgvTyped returns argument list with types
// types are qualified relative to original package
func (te *traceEvent) ArgvTyped() string {
return te.ArgvTypedRelativeTo(te.Pkgt.tracePkg)
return te.ArgvTypedRelativeTo(te.Pkgt.tracePkg, nil)
}
// ArgvTypedRelativeTo returns argument list with types qualified relative to specified package
func (te *traceEvent) ArgvTypedRelativeTo(pkg *types.Package) string {
// importedAs specifies under which name a package was imported, if name was explicitly set
func (te *traceEvent) ArgvTypedRelativeTo(pkg *types.Package, importedAs map[string/*pkgpath*/]string/*pkgname*/) string {
argv := []string{}
// default qualifier - relative to original package
......@@ -336,6 +380,12 @@ func (te *traceEvent) ArgvTypedRelativeTo(pkg *types.Package) string {
return ""
}
// qualify as explicitly named
pkgname := importedAs[p.Path()]
if pkgname != "" {
return pkgname
}
// default qualification
return p.Name()
}
......@@ -415,8 +465,9 @@ func {{.Name}}_Attach(pg *tracing.ProbeGroup, probe func({{.ArgvTyped}})) *traci
// traceEventImportTmpl is code template generated for importing one trace event
var traceEventImportTmpl = template.Must(template.New("traceimport").Parse(`
//go:linkname {{.Pkgt.Pkgi.Pkg.Name}}_{{.Name}}_Attach {{.Pkgt.Pkgi.Pkg.Path}}.{{.Name}}_Attach
func {{.Pkgt.Pkgi.Pkg.Name}}_{{.Name}}_Attach(*tracing.ProbeGroup, func({{.ArgvTypedRelativeTo .ImporterPkg}})) *tracing.Probe
{{/* function to attach a probe to tracepoint imported via go:linkname */ -}}
//go:linkname {{.ImportSpec.PkgName}}_{{.Name}}_Attach {{.ImportSpec.PkgPath}}.{{.Name}}_Attach
func {{.ImportSpec.PkgName}}_{{.Name}}_Attach(*tracing.ProbeGroup, func({{.ArgvTypedRelativeTo .ImporterPkg .ImportedAs}})) *tracing.Probe
`))
// magic begins all files generated by gotrace
......@@ -592,9 +643,14 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error {
prologue.emit("\nimport (")
prologue.emit("\t%q", "lab.nexedi.com/kirr/neo/go/xcommon/tracing")
prologue.emit("\t%q", "unsafe")
// import of all packages needed for used types will go here in the end
// import of all packages needed for used types
needPkg := StrSet{}
// some packages are imported with explicit name
importedAs := map[string/*pkgpath*/]string/*pkgname*/{}
// code for trace:event definitions
text := &Buffer{}
for _, event := range tpkg.Eventv {
......@@ -609,13 +665,20 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error {
// code for trace:import imports
for _, timport := range tpkg.Importv {
text.emit("\n// traceimport: %q", timport.PkgPath)
text.emit("\n// traceimport: %s", timport.ImportSpec())
impProg, impPkgi, err := P.Import(timport.PkgPath)
if err != nil {
return fmt.Errorf("%v: error trace-importing %s: %v", timport.Pos, timport.PkgPath, err)
}
// set name of the package if it was not explicitly specified
if timport.PkgName == "" {
timport.PkgName = impPkgi.Pkg.Name()
} else {
importedAs[timport.PkgPath] = timport.PkgName
}
impPkg, err := packageTrace(impProg, impPkgi)
if err != nil {
return err // XXX err ctx
......@@ -625,8 +688,10 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error {
needPkg.Add(event.NeedPkgv()...)
importedEvent := struct{
*traceEvent
ImportSpec *traceImport
ImporterPkg *types.Package
} {event, pkgi.Pkg }
ImportedAs map[string]string
} {event, timport, pkgi.Pkg, importedAs}
err = traceEventImportTmpl.Execute(text, importedEvent)
if err != nil {
panic(err) // XXX
......@@ -644,7 +709,11 @@ func tracegen(pkgpath string, ctxt *build.Context, cwd string) error {
}
for _, needpkg := range needPkgv {
prologue.emit("\t%q", needpkg)
pkgname := importedAs[needpkg]
if pkgname != "" {
pkgname += " "
}
prologue.emit("\t%s%q", pkgname, needpkg)
}
prologue.emit(")")
......
......@@ -2,7 +2,10 @@ package pkg2
// trace-import another package
// NOTE "a/pkg1" is not regularly imported
//trace:import "a/pkg1"
////trace:import "a/pkg1"
// XXX temp
//trace:import bbb "a/pkg1"
// additional tracepoint which pkg2 defines
//trace:event traceDoSomething(i, j int, q string)
......
......@@ -2,8 +2,8 @@ package pkg3
import "testing"
// trace import that should be added only to tests
//trace:import "a/pkg1"
// trace import that should be added only to tests, and under specified package name
//trace:import aaa1 "a/pkg1"
func TestZzz(t *testing.T) {
if zzz() != 2 {
......
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