1
0
mirror of https://github.com/golang/go synced 2024-10-01 11:18:32 -06:00
go/cmd/oracle/main.go

133 lines
3.0 KiB
Go
Raw Normal View History

// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// oracle: a tool for answering questions about Go source code.
//
// With -format=plain, the oracle prints query results to the standard
// output in an editor-friendly format in which every line of output
// is of the form "pos: text", where pos = "-" if unknown.
//
// With -format=json, the oracle prints structured data in JSON syntax.
//
package main
import (
"bufio"
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
"bytes"
"encoding/json"
"flag"
"fmt"
"go/build"
"io"
"log"
"os"
"runtime"
"runtime/pprof"
go.tools/importer: generalize command-line syntax. Motivation: pointer analysis tools (like the oracle) want the user to specify a set of initial packages, like 'go test'. This change enables the user to specify a set of packages on the command line using importer.LoadInitialPackages(args). Each argument is interpreted as either: - a comma-separated list of *.go source files together comprising one non-importable ad-hoc package. e.g. "src/pkg/net/http/triv.go" gives us [main]. - an import path, denoting both the imported package and its non-importable external test package, if any. e.g. "fmt" gives us [fmt, fmt_test]. Current type-checker limitations mean that only the first import path may contribute tests: multiple packages augmented by *_test.go files could create import cycles, which 'go test' avoids by building a separate executable for each one. That approach is less attractive for static analysis. Details: (many files touched, but importer.go is the crux) importer: - PackageInfo.Importable boolean indicates whether package is importable. - un-expose Importer.Packages; expose AllPackages() instead. - CreatePackageFromArgs has become LoadInitialPackages. - imports() moved to util.go, renamed importsOf(). - InitialPackagesUsage usage message exported to clients. - the package name for ad-hoc packages now comes from the 'package' decl, not "main". ssa.Program: - added CreatePackages() method - PackagesByPath un-exposed, renamed 'imported'. - expose AllPackages and ImportedPackage accessors. oracle: - describe: explain and workaround a go/types bug. Misc: - Removed various unnecessary error.Error() calls in Printf args. R=crawshaw CC=golang-dev https://golang.org/cl/13579043
2013-09-06 16:13:57 -06:00
"code.google.com/p/go.tools/importer"
"code.google.com/p/go.tools/oracle"
)
var posFlag = flag.String("pos", "",
"Filename and byte offset or extent of a syntax element about which to query, "+
"e.g. foo.go:#123-#456, bar.go:#123.")
var modeFlag = flag.String("mode", "",
"Mode of query to perform: e.g. callers, describe, etc.")
var ptalogFlag = flag.String("ptalog", "",
"Location of the points-to analysis log file, or empty to disable logging.")
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
var formatFlag = flag.String("format", "plain", "Output format: 'plain' or 'json'.")
const usage = `Go source code oracle.
go.tools/importer: generalize command-line syntax. Motivation: pointer analysis tools (like the oracle) want the user to specify a set of initial packages, like 'go test'. This change enables the user to specify a set of packages on the command line using importer.LoadInitialPackages(args). Each argument is interpreted as either: - a comma-separated list of *.go source files together comprising one non-importable ad-hoc package. e.g. "src/pkg/net/http/triv.go" gives us [main]. - an import path, denoting both the imported package and its non-importable external test package, if any. e.g. "fmt" gives us [fmt, fmt_test]. Current type-checker limitations mean that only the first import path may contribute tests: multiple packages augmented by *_test.go files could create import cycles, which 'go test' avoids by building a separate executable for each one. That approach is less attractive for static analysis. Details: (many files touched, but importer.go is the crux) importer: - PackageInfo.Importable boolean indicates whether package is importable. - un-expose Importer.Packages; expose AllPackages() instead. - CreatePackageFromArgs has become LoadInitialPackages. - imports() moved to util.go, renamed importsOf(). - InitialPackagesUsage usage message exported to clients. - the package name for ad-hoc packages now comes from the 'package' decl, not "main". ssa.Program: - added CreatePackages() method - PackagesByPath un-exposed, renamed 'imported'. - expose AllPackages and ImportedPackage accessors. oracle: - describe: explain and workaround a go/types bug. Misc: - Removed various unnecessary error.Error() calls in Printf args. R=crawshaw CC=golang-dev https://golang.org/cl/13579043
2013-09-06 16:13:57 -06:00
Usage: oracle [<flag> ...] <args> ...
Use -help flag to display options.
Examples:
% oracle -pos=hello.go:#123 hello.go
% oracle -pos=hello.go:#123-#456 hello.go
go.tools/importer: generalize command-line syntax. Motivation: pointer analysis tools (like the oracle) want the user to specify a set of initial packages, like 'go test'. This change enables the user to specify a set of packages on the command line using importer.LoadInitialPackages(args). Each argument is interpreted as either: - a comma-separated list of *.go source files together comprising one non-importable ad-hoc package. e.g. "src/pkg/net/http/triv.go" gives us [main]. - an import path, denoting both the imported package and its non-importable external test package, if any. e.g. "fmt" gives us [fmt, fmt_test]. Current type-checker limitations mean that only the first import path may contribute tests: multiple packages augmented by *_test.go files could create import cycles, which 'go test' avoids by building a separate executable for each one. That approach is less attractive for static analysis. Details: (many files touched, but importer.go is the crux) importer: - PackageInfo.Importable boolean indicates whether package is importable. - un-expose Importer.Packages; expose AllPackages() instead. - CreatePackageFromArgs has become LoadInitialPackages. - imports() moved to util.go, renamed importsOf(). - InitialPackagesUsage usage message exported to clients. - the package name for ad-hoc packages now comes from the 'package' decl, not "main". ssa.Program: - added CreatePackages() method - PackagesByPath un-exposed, renamed 'imported'. - expose AllPackages and ImportedPackage accessors. oracle: - describe: explain and workaround a go/types bug. Misc: - Removed various unnecessary error.Error() calls in Printf args. R=crawshaw CC=golang-dev https://golang.org/cl/13579043
2013-09-06 16:13:57 -06:00
` + importer.InitialPackagesUsage
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
func init() {
// If $GOMAXPROCS isn't set, use the full capacity of the machine.
// For small machines, use at least 4 threads.
if os.Getenv("GOMAXPROCS") == "" {
n := runtime.NumCPU()
if n < 4 {
n = 4
}
runtime.GOMAXPROCS(n)
}
}
func main() {
flag.Parse()
args := flag.Args()
if len(args) == 0 {
fmt.Fprint(os.Stderr, usage)
os.Exit(1)
}
// Set up points-to analysis log file.
var ptalog io.Writer
if *ptalogFlag != "" {
if f, err := os.Create(*ptalogFlag); err != nil {
go.tools/importer: generalize command-line syntax. Motivation: pointer analysis tools (like the oracle) want the user to specify a set of initial packages, like 'go test'. This change enables the user to specify a set of packages on the command line using importer.LoadInitialPackages(args). Each argument is interpreted as either: - a comma-separated list of *.go source files together comprising one non-importable ad-hoc package. e.g. "src/pkg/net/http/triv.go" gives us [main]. - an import path, denoting both the imported package and its non-importable external test package, if any. e.g. "fmt" gives us [fmt, fmt_test]. Current type-checker limitations mean that only the first import path may contribute tests: multiple packages augmented by *_test.go files could create import cycles, which 'go test' avoids by building a separate executable for each one. That approach is less attractive for static analysis. Details: (many files touched, but importer.go is the crux) importer: - PackageInfo.Importable boolean indicates whether package is importable. - un-expose Importer.Packages; expose AllPackages() instead. - CreatePackageFromArgs has become LoadInitialPackages. - imports() moved to util.go, renamed importsOf(). - InitialPackagesUsage usage message exported to clients. - the package name for ad-hoc packages now comes from the 'package' decl, not "main". ssa.Program: - added CreatePackages() method - PackagesByPath un-exposed, renamed 'imported'. - expose AllPackages and ImportedPackage accessors. oracle: - describe: explain and workaround a go/types bug. Misc: - Removed various unnecessary error.Error() calls in Printf args. R=crawshaw CC=golang-dev https://golang.org/cl/13579043
2013-09-06 16:13:57 -06:00
log.Fatal(err.Error())
} else {
buf := bufio.NewWriter(f)
ptalog = buf
defer func() {
buf.Flush()
f.Close()
}()
}
}
// Profiling support.
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
// -format flag
if *formatFlag != "json" && *formatFlag != "plain" {
fmt.Fprintf(os.Stderr, "Error: illegal -format value: %q", *formatFlag)
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
os.Exit(1)
}
// Ask the oracle.
res, err := oracle.Query(args, *modeFlag, *posFlag, ptalog, &build.Default)
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
if err != nil {
go.tools/importer: generalize command-line syntax. Motivation: pointer analysis tools (like the oracle) want the user to specify a set of initial packages, like 'go test'. This change enables the user to specify a set of packages on the command line using importer.LoadInitialPackages(args). Each argument is interpreted as either: - a comma-separated list of *.go source files together comprising one non-importable ad-hoc package. e.g. "src/pkg/net/http/triv.go" gives us [main]. - an import path, denoting both the imported package and its non-importable external test package, if any. e.g. "fmt" gives us [fmt, fmt_test]. Current type-checker limitations mean that only the first import path may contribute tests: multiple packages augmented by *_test.go files could create import cycles, which 'go test' avoids by building a separate executable for each one. That approach is less attractive for static analysis. Details: (many files touched, but importer.go is the crux) importer: - PackageInfo.Importable boolean indicates whether package is importable. - un-expose Importer.Packages; expose AllPackages() instead. - CreatePackageFromArgs has become LoadInitialPackages. - imports() moved to util.go, renamed importsOf(). - InitialPackagesUsage usage message exported to clients. - the package name for ad-hoc packages now comes from the 'package' decl, not "main". ssa.Program: - added CreatePackages() method - PackagesByPath un-exposed, renamed 'imported'. - expose AllPackages and ImportedPackage accessors. oracle: - describe: explain and workaround a go/types bug. Misc: - Removed various unnecessary error.Error() calls in Printf args. R=crawshaw CC=golang-dev https://golang.org/cl/13579043
2013-09-06 16:13:57 -06:00
fmt.Fprintf(os.Stderr, "%s\n", err)
os.Exit(1)
}
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
// Print the result.
switch *formatFlag {
case "json":
b, err := json.Marshal(res)
if err != nil {
go.tools/importer: generalize command-line syntax. Motivation: pointer analysis tools (like the oracle) want the user to specify a set of initial packages, like 'go test'. This change enables the user to specify a set of packages on the command line using importer.LoadInitialPackages(args). Each argument is interpreted as either: - a comma-separated list of *.go source files together comprising one non-importable ad-hoc package. e.g. "src/pkg/net/http/triv.go" gives us [main]. - an import path, denoting both the imported package and its non-importable external test package, if any. e.g. "fmt" gives us [fmt, fmt_test]. Current type-checker limitations mean that only the first import path may contribute tests: multiple packages augmented by *_test.go files could create import cycles, which 'go test' avoids by building a separate executable for each one. That approach is less attractive for static analysis. Details: (many files touched, but importer.go is the crux) importer: - PackageInfo.Importable boolean indicates whether package is importable. - un-expose Importer.Packages; expose AllPackages() instead. - CreatePackageFromArgs has become LoadInitialPackages. - imports() moved to util.go, renamed importsOf(). - InitialPackagesUsage usage message exported to clients. - the package name for ad-hoc packages now comes from the 'package' decl, not "main". ssa.Program: - added CreatePackages() method - PackagesByPath un-exposed, renamed 'imported'. - expose AllPackages and ImportedPackage accessors. oracle: - describe: explain and workaround a go/types bug. Misc: - Removed various unnecessary error.Error() calls in Printf args. R=crawshaw CC=golang-dev https://golang.org/cl/13579043
2013-09-06 16:13:57 -06:00
fmt.Fprintf(os.Stderr, "JSON error: %s\n", err)
go.tools/oracle: add option to output results in JSON syntax. See json.go for interface specification. Example usage: % oracle -format=json -mode=callgraph code.google.com/p/go.tools/cmd/oracle + Tests, based on (small) golden files. Overview: Each <query>Result structure has been "lowered" so that all but the most trivial logic in each display() function has been moved to the main query. Each one now has a toJSON method that populates a json.Result struct. Though the <query>Result structs are similar to the correponding JSON protocol, they're not close enough to be used directly; for example, the former contain richer semantic entities (token.Pos, ast.Expr, ssa.Value, pointer.Pointer, etc) whereas JSON contains only their printed forms using Go basic types. The choices of what levels of abstractions the two sets of structs should have is somewhat arbitrary. We may want richer information in the JSON output in future. Details: - oracle.Main has been split into oracle.Query() and the printing of the oracle.Result. - the display() method no longer needs an *oracle param, only a print function. - callees: sort the result for determinism. - callees: compute the union across all contexts. - callers: sort the results for determinism. - describe(package): fixed a bug in the predicate for method accessibility: an unexported method defined in pkg A may belong to a type defined in package B (via embedding/promotion) and may thus be accessible to A. New accessibleMethods() utility fixes this. - describe(type): filter methods by accessibility. - added tests of 'callgraph'. - pointer: eliminated the 'caller CallGraphNode' parameter from pointer.Context.Call callback since it was redundant w.r.t site.Caller(). - added warning if CGO_ENABLED is unset. R=crawshaw CC=golang-dev https://golang.org/cl/13270045
2013-09-03 13:29:02 -06:00
os.Exit(1)
}
var buf bytes.Buffer
if err := json.Indent(&buf, b, "", "\t"); err != nil {
fmt.Fprintf(os.Stderr, "json.Indent failed: %s", err)
os.Exit(1)
}
os.Stdout.Write(buf.Bytes())
case "plain":
res.WriteTo(os.Stdout)
}
}