go.tools/oracle: change -mode argument into subcommand.
e.g. "oracle callgraph <package>" Also: simplified error handling. Eliminated oracle.errorf because it prepends "file:line:col: " to the error message so the main function can't safely prepend "Error: ". The position wasn't interesting though: it was just -pos, more or less. R=crawshaw, dominik.honnef, r CC=golang-dev https://golang.org/cl/13864044
This commit is contained in:
parent
39779f52c3
commit
3a4c0462d8
|
@ -24,7 +24,7 @@ trap "rm -f $log" EXIT
|
||||||
go get code.google.com/p/go.tools/cmd/oracle || die "'go get' failed"
|
go get code.google.com/p/go.tools/cmd/oracle || die "'go get' failed"
|
||||||
mv -f $GOPATH/bin/oracle $GOROOT/bin/
|
mv -f $GOPATH/bin/oracle $GOROOT/bin/
|
||||||
$GOROOT/bin/oracle >$log 2>&1 || true # (prints usage and exits 1)
|
$GOROOT/bin/oracle >$log 2>&1 || true # (prints usage and exits 1)
|
||||||
grep -q "Usage: oracle" $log || die "$GOROOT/bin/oracle not installed"
|
grep -q "Run.*help" $log || die "$GOROOT/bin/oracle not installed"
|
||||||
|
|
||||||
|
|
||||||
# Run Emacs, set the scope to the oracle tool itself,
|
# Run Emacs, set the scope to the oracle tool itself,
|
||||||
|
|
|
@ -6,9 +6,7 @@
|
||||||
// http://golang.org/s/oracle-design
|
// http://golang.org/s/oracle-design
|
||||||
// http://golang.org/s/oracle-user-manual
|
// http://golang.org/s/oracle-user-manual
|
||||||
//
|
//
|
||||||
// Run with -help for usage information.
|
// Run with -help flag or help subcommand for usage information.
|
||||||
//
|
|
||||||
// TODO(adonovan): perhaps -mode should be an args[1] verb, e.g. 'oracle callgraph ...'
|
|
||||||
//
|
//
|
||||||
package main
|
package main
|
||||||
|
|
||||||
|
@ -33,9 +31,6 @@ var posFlag = flag.String("pos", "",
|
||||||
"Filename and byte offset or extent of a syntax element about which to query, "+
|
"Filename and byte offset or extent of a syntax element about which to query, "+
|
||||||
"e.g. foo.go:#123,#456, bar.go:#123.")
|
"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", "",
|
var ptalogFlag = flag.String("ptalog", "",
|
||||||
"Location of the points-to analysis log file, or empty to disable logging.")
|
"Location of the points-to analysis log file, or empty to disable logging.")
|
||||||
|
|
||||||
|
@ -47,7 +42,7 @@ var reflectFlag = flag.Bool("reflect", true, "Analyze reflection soundly (slow).
|
||||||
const useHelp = "Run 'oracle -help' for more information.\n"
|
const useHelp = "Run 'oracle -help' for more information.\n"
|
||||||
|
|
||||||
const helpMessage = `Go source code oracle.
|
const helpMessage = `Go source code oracle.
|
||||||
Usage: oracle [<flag> ...] <args> ...
|
Usage: oracle [<flag> ...] <mode> <args> ...
|
||||||
|
|
||||||
The -format flag controls the output format:
|
The -format flag controls the output format:
|
||||||
plain an editor-friendly format in which every line of output
|
plain an editor-friendly format in which every line of output
|
||||||
|
@ -57,7 +52,8 @@ The -format flag controls the output format:
|
||||||
|
|
||||||
The -pos flag is required in all modes except 'callgraph'.
|
The -pos flag is required in all modes except 'callgraph'.
|
||||||
|
|
||||||
The -mode flag determines the query to perform:
|
The mode argument determines the query to perform:
|
||||||
|
|
||||||
callees show possible targets of selected function call
|
callees show possible targets of selected function call
|
||||||
callers show possible callers of selected function
|
callers show possible callers of selected function
|
||||||
callgraph show complete callgraph of program
|
callgraph show complete callgraph of program
|
||||||
|
@ -73,11 +69,11 @@ The user manual is available here: http://golang.org/s/oracle-user-manual
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
Describe the syntax at offset 530 in this file (an import spec):
|
Describe the syntax at offset 530 in this file (an import spec):
|
||||||
% oracle -mode=describe -pos=src/code.google.com/p/go.tools/cmd/oracle/main.go:#530 \
|
% oracle -pos=src/code.google.com/p/go.tools/cmd/oracle/main.go:#530 describe \
|
||||||
code.google.com/p/go.tools/cmd/oracle
|
code.google.com/p/go.tools/cmd/oracle
|
||||||
|
|
||||||
Print the callgraph of the trivial web-server in JSON format:
|
Print the callgraph of the trivial web-server in JSON format:
|
||||||
% oracle -mode=callgraph -format=json src/pkg/net/http/triv.go
|
% oracle -format=json src/pkg/net/http/triv.go callgraph
|
||||||
` + importer.InitialPackagesUsage
|
` + importer.InitialPackagesUsage
|
||||||
|
|
||||||
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
|
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
|
||||||
|
@ -94,6 +90,12 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func printHelp() {
|
||||||
|
fmt.Println(helpMessage)
|
||||||
|
fmt.Println("Flags:")
|
||||||
|
flag.PrintDefaults()
|
||||||
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Don't print full help unless -help was requested.
|
// Don't print full help unless -help was requested.
|
||||||
// Just gently remind users that it's there.
|
// Just gently remind users that it's there.
|
||||||
|
@ -102,13 +104,23 @@ func main() {
|
||||||
if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
|
if err := flag.CommandLine.Parse(os.Args[1:]); err != nil {
|
||||||
// (err has already been printed)
|
// (err has already been printed)
|
||||||
if err == flag.ErrHelp {
|
if err == flag.ErrHelp {
|
||||||
fmt.Println(helpMessage)
|
printHelp()
|
||||||
fmt.Println("Flags:")
|
|
||||||
flag.PrintDefaults()
|
|
||||||
}
|
}
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
args := flag.Args()
|
args := flag.Args()
|
||||||
|
if len(args) == 0 || args[0] == "" {
|
||||||
|
fmt.Fprint(os.Stderr, "Error: a mode argument is required.\n"+useHelp)
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
|
mode := args[0]
|
||||||
|
args = args[1:]
|
||||||
|
if mode == "help" {
|
||||||
|
printHelp()
|
||||||
|
os.Exit(2)
|
||||||
|
}
|
||||||
|
|
||||||
if len(args) == 0 {
|
if len(args) == 0 {
|
||||||
fmt.Fprint(os.Stderr, "Error: no package arguments.\n"+useHelp)
|
fmt.Fprint(os.Stderr, "Error: no package arguments.\n"+useHelp)
|
||||||
|
@ -145,20 +157,14 @@ func main() {
|
||||||
case "json", "plain", "xml":
|
case "json", "plain", "xml":
|
||||||
// ok
|
// ok
|
||||||
default:
|
default:
|
||||||
fmt.Fprintf(os.Stderr, "Error: illegal -format value: %q\n"+useHelp, *formatFlag)
|
fmt.Fprintf(os.Stderr, "Error: illegal -format value: %q.\n"+useHelp, *formatFlag)
|
||||||
os.Exit(2)
|
|
||||||
}
|
|
||||||
|
|
||||||
// -mode flag
|
|
||||||
if *modeFlag == "" {
|
|
||||||
fmt.Fprintf(os.Stderr, "Error: a query -mode is required.\n"+useHelp)
|
|
||||||
os.Exit(2)
|
os.Exit(2)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ask the oracle.
|
// Ask the oracle.
|
||||||
res, err := oracle.Query(args, *modeFlag, *posFlag, ptalog, &build.Default, *reflectFlag)
|
res, err := oracle.Query(args, mode, *posFlag, ptalog, &build.Default, *reflectFlag)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "%s\n"+useHelp, err)
|
fmt.Fprintf(os.Stderr, "Error: %s.\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +173,7 @@ func main() {
|
||||||
case "json":
|
case "json":
|
||||||
b, err := json.MarshalIndent(res.Serial(), "", "\t")
|
b, err := json.MarshalIndent(res.Serial(), "", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "JSON error: %s\n", err)
|
fmt.Fprintf(os.Stderr, "JSON error: %s.\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
os.Stdout.Write(b)
|
os.Stdout.Write(b)
|
||||||
|
@ -175,7 +181,7 @@ func main() {
|
||||||
case "xml":
|
case "xml":
|
||||||
b, err := xml.MarshalIndent(res.Serial(), "", "\t")
|
b, err := xml.MarshalIndent(res.Serial(), "", "\t")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "XML error: %s\n", err)
|
fmt.Fprintf(os.Stderr, "XML error: %s.\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
os.Stdout.Write(b)
|
os.Stdout.Write(b)
|
||||||
|
|
|
@ -111,9 +111,7 @@ result."
|
||||||
(setq buffer-read-only nil)
|
(setq buffer-read-only nil)
|
||||||
(erase-buffer)
|
(erase-buffer)
|
||||||
(insert "Go Oracle\n")
|
(insert "Go Oracle\n")
|
||||||
(let ((args (append (list go-oracle-command nil t nil
|
(let ((args (append (list go-oracle-command nil t nil posflag mode)
|
||||||
posflag
|
|
||||||
(format "-mode=%s" mode))
|
|
||||||
(split-string go-oracle-scope " " t))))
|
(split-string go-oracle-scope " " t))))
|
||||||
;; Log the command to *Messages*, for debugging.
|
;; Log the command to *Messages*, for debugging.
|
||||||
(message "Command: %s:" args)
|
(message "Command: %s:" args)
|
||||||
|
|
|
@ -68,14 +68,14 @@ func! s:RunOracle(mode, selected) range abort
|
||||||
if a:selected != -1
|
if a:selected != -1
|
||||||
let pos1 = s:getpos(line("'<"), col("'<"))
|
let pos1 = s:getpos(line("'<"), col("'<"))
|
||||||
let pos2 = s:getpos(line("'>"), col("'>"))
|
let pos2 = s:getpos(line("'>"), col("'>"))
|
||||||
let cmd = printf('%s -mode=%s -pos=%s:#%d,#%d %s',
|
let cmd = printf('%s -pos=%s:#%d,#%d %s %s',
|
||||||
\ s:go_oracle, a:mode,
|
\ s:go_oracle,
|
||||||
\ shellescape(fname), pos1, pos2, shellescape(sname))
|
\ shellescape(fname), pos1, pos2, a:mode, shellescape(sname))
|
||||||
else
|
else
|
||||||
let pos = s:getpos(line('.'), col('.'))
|
let pos = s:getpos(line('.'), col('.'))
|
||||||
let cmd = printf('%s -mode=%s -pos=%s:#%d %s',
|
let cmd = printf('%s -pos=%s:#%d %s %s',
|
||||||
\ s:go_oracle, a:mode,
|
\ s:go_oracle,
|
||||||
\ shellescape(fname), pos, shellescape(sname))
|
\ shellescape(fname), pos, a:mode, shellescape(sname))
|
||||||
endif
|
endif
|
||||||
call s:qflist(system(cmd))
|
call s:qflist(system(cmd))
|
||||||
endfun
|
endfun
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package oracle
|
package oracle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/token"
|
"go/token"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -29,7 +30,7 @@ func callees(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if call == nil {
|
if call == nil {
|
||||||
return nil, o.errorf(qpos.path[0], "there is no function call here")
|
return nil, fmt.Errorf("there is no function call here")
|
||||||
}
|
}
|
||||||
// TODO(adonovan): issue an error if the call is "too far
|
// TODO(adonovan): issue an error if the call is "too far
|
||||||
// away" from the current selection, as this most likely is
|
// away" from the current selection, as this most likely is
|
||||||
|
@ -37,13 +38,13 @@ func callees(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
||||||
|
|
||||||
// Reject type conversions.
|
// Reject type conversions.
|
||||||
if qpos.info.IsType(call.Fun) {
|
if qpos.info.IsType(call.Fun) {
|
||||||
return nil, o.errorf(call, "this is a type conversion, not a function call")
|
return nil, fmt.Errorf("this is a type conversion, not a function call")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reject calls to built-ins.
|
// Reject calls to built-ins.
|
||||||
if id, ok := unparen(call.Fun).(*ast.Ident); ok {
|
if id, ok := unparen(call.Fun).(*ast.Ident); ok {
|
||||||
if b, ok := qpos.info.ObjectOf(id).(*types.Builtin); ok {
|
if b, ok := qpos.info.ObjectOf(id).(*types.Builtin); ok {
|
||||||
return nil, o.errorf(call, "this is a call to the built-in '%s' operator", b.Name())
|
return nil, fmt.Errorf("this is a call to the built-in '%s' operator", b.Name())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -74,7 +75,7 @@ func callees(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
||||||
ptrAnalysis(o)
|
ptrAnalysis(o)
|
||||||
|
|
||||||
if arbitrarySite == nil {
|
if arbitrarySite == nil {
|
||||||
return nil, o.errorf(call.Lparen, "this call site is unreachable in this analysis")
|
return nil, fmt.Errorf("this call site is unreachable in this analysis")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Compute union of callees across all contexts.
|
// Compute union of callees across all contexts.
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package oracle
|
package oracle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
|
||||||
"code.google.com/p/go.tools/oracle/serial"
|
"code.google.com/p/go.tools/oracle/serial"
|
||||||
|
@ -20,17 +21,17 @@ import (
|
||||||
func callers(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
func callers(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
||||||
pkg := o.prog.Package(qpos.info.Pkg)
|
pkg := o.prog.Package(qpos.info.Pkg)
|
||||||
if pkg == nil {
|
if pkg == nil {
|
||||||
return nil, o.errorf(qpos.path[0], "no SSA package")
|
return nil, fmt.Errorf("no SSA package")
|
||||||
}
|
}
|
||||||
if !ssa.HasEnclosingFunction(pkg, qpos.path) {
|
if !ssa.HasEnclosingFunction(pkg, qpos.path) {
|
||||||
return nil, o.errorf(qpos.path[0], "this position is not inside a function")
|
return nil, fmt.Errorf("this position is not inside a function")
|
||||||
}
|
}
|
||||||
|
|
||||||
buildSSA(o)
|
buildSSA(o)
|
||||||
|
|
||||||
target := ssa.EnclosingFunction(pkg, qpos.path)
|
target := ssa.EnclosingFunction(pkg, qpos.path)
|
||||||
if target == nil {
|
if target == nil {
|
||||||
return nil, o.errorf(qpos.path[0], "no SSA function built for this location (dead code?)")
|
return nil, fmt.Errorf("no SSA function built for this location (dead code?)")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the pointer analysis, recording each
|
// Run the pointer analysis, recording each
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package oracle
|
package oracle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"go/token"
|
"go/token"
|
||||||
|
|
||||||
"code.google.com/p/go.tools/oracle/serial"
|
"code.google.com/p/go.tools/oracle/serial"
|
||||||
|
@ -25,19 +26,18 @@ import (
|
||||||
func callstack(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
func callstack(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
||||||
pkg := o.prog.Package(qpos.info.Pkg)
|
pkg := o.prog.Package(qpos.info.Pkg)
|
||||||
if pkg == nil {
|
if pkg == nil {
|
||||||
return nil, o.errorf(qpos.path[0], "no SSA package")
|
return nil, fmt.Errorf("no SSA package")
|
||||||
}
|
}
|
||||||
|
|
||||||
if !ssa.HasEnclosingFunction(pkg, qpos.path) {
|
if !ssa.HasEnclosingFunction(pkg, qpos.path) {
|
||||||
return nil, o.errorf(qpos.path[0], "this position is not inside a function")
|
return nil, fmt.Errorf("this position is not inside a function")
|
||||||
}
|
}
|
||||||
|
|
||||||
buildSSA(o)
|
buildSSA(o)
|
||||||
|
|
||||||
target := ssa.EnclosingFunction(pkg, qpos.path)
|
target := ssa.EnclosingFunction(pkg, qpos.path)
|
||||||
if target == nil {
|
if target == nil {
|
||||||
return nil, o.errorf(qpos.path[0],
|
return nil, fmt.Errorf("no SSA function built for this location (dead code?)")
|
||||||
"no SSA function built for this location (dead code?)")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the pointer analysis and build the complete call graph.
|
// Run the pointer analysis and build the complete call graph.
|
||||||
|
|
|
@ -351,7 +351,7 @@ func describeValue(o *Oracle, qpos *QueryPos, path []ast.Node) (*describeValueRe
|
||||||
switch n := path[0].(type) {
|
switch n := path[0].(type) {
|
||||||
case *ast.ValueSpec:
|
case *ast.ValueSpec:
|
||||||
// ambiguous ValueSpec containing multiple names
|
// ambiguous ValueSpec containing multiple names
|
||||||
return nil, o.errorf(n, "multiple value specification")
|
return nil, fmt.Errorf("multiple value specification")
|
||||||
case *ast.Ident:
|
case *ast.Ident:
|
||||||
obj = qpos.info.ObjectOf(n)
|
obj = qpos.info.ObjectOf(n)
|
||||||
expr = n
|
expr = n
|
||||||
|
@ -359,7 +359,7 @@ func describeValue(o *Oracle, qpos *QueryPos, path []ast.Node) (*describeValueRe
|
||||||
expr = n
|
expr = n
|
||||||
default:
|
default:
|
||||||
// Is this reachable?
|
// Is this reachable?
|
||||||
return nil, o.errorf(n, "unexpected AST for expr: %T", n)
|
return nil, fmt.Errorf("unexpected AST for expr: %T", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
typ := qpos.info.TypeOf(expr)
|
typ := qpos.info.TypeOf(expr)
|
||||||
|
@ -649,7 +649,7 @@ func describeType(o *Oracle, qpos *QueryPos, path []ast.Node) (*describeTypeResu
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Unreachable?
|
// Unreachable?
|
||||||
return nil, o.errorf(n, "unexpected AST for type: %T", n)
|
return nil, fmt.Errorf("unexpected AST for type: %T", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
return &describeTypeResult{
|
return &describeTypeResult{
|
||||||
|
@ -737,7 +737,7 @@ func describePackage(o *Oracle, qpos *QueryPos, path []ast.Node) (*describePacka
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Unreachable?
|
// Unreachable?
|
||||||
return nil, o.errorf(n, "unexpected AST for package: %T", n)
|
return nil, fmt.Errorf("unexpected AST for package: %T", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
var members []*describeMember
|
var members []*describeMember
|
||||||
|
|
|
@ -52,7 +52,7 @@ func freevars(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
||||||
obj := qpos.info.ObjectOf(n)
|
obj := qpos.info.ObjectOf(n)
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
return nil // TODO(adonovan): fix: this fails for *types.Label.
|
return nil // TODO(adonovan): fix: this fails for *types.Label.
|
||||||
panic(o.errorf(n, "no types.Object for ast.Ident"))
|
panic("no types.Object for ast.Ident")
|
||||||
}
|
}
|
||||||
if _, ok := obj.(*types.PkgName); ok {
|
if _, ok := obj.(*types.PkgName); ok {
|
||||||
return nil // imported package
|
return nil // imported package
|
||||||
|
|
|
@ -18,7 +18,6 @@ package oracle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/build"
|
"go/build"
|
||||||
|
@ -257,7 +256,7 @@ func newOracle(imp *importer.Importer, args []string, ptalog io.Writer, needs in
|
||||||
|
|
||||||
// Create SSA packages.
|
// Create SSA packages.
|
||||||
if err := o.prog.CreatePackages(imp); err != nil {
|
if err := o.prog.CreatePackages(imp); err != nil {
|
||||||
return nil, o.errorf(nil, "%s", err)
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial packages (specified on command line)
|
// Initial packages (specified on command line)
|
||||||
|
@ -270,7 +269,7 @@ func newOracle(imp *importer.Importer, args []string, ptalog io.Writer, needs in
|
||||||
// should build a single synthetic testmain package,
|
// should build a single synthetic testmain package,
|
||||||
// not synthetic main functions to many packages.
|
// not synthetic main functions to many packages.
|
||||||
if initialPkg.CreateTestMainFunction() == nil {
|
if initialPkg.CreateTestMainFunction() == nil {
|
||||||
return nil, o.errorf(nil, "analysis scope has no main() entry points")
|
return nil, fmt.Errorf("analysis scope has no main() entry points")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
o.config.Mains = append(o.config.Mains, initialPkg)
|
o.config.Mains = append(o.config.Mains, initialPkg)
|
||||||
|
@ -324,7 +323,7 @@ func ParseQueryPos(imp *importer.Importer, pos string, needExact bool) (*QueryPo
|
||||||
}
|
}
|
||||||
info, path, exact := imp.PathEnclosingInterval(start, end)
|
info, path, exact := imp.PathEnclosingInterval(start, end)
|
||||||
if path == nil {
|
if path == nil {
|
||||||
return nil, errors.New("no syntax here")
|
return nil, fmt.Errorf("no syntax here")
|
||||||
}
|
}
|
||||||
if needExact && !exact {
|
if needExact && !exact {
|
||||||
return nil, fmt.Errorf("ambiguous selection within %s", importer.NodeDescription(path[0]))
|
return nil, fmt.Errorf("ambiguous selection within %s", importer.NodeDescription(path[0]))
|
||||||
|
@ -537,13 +536,6 @@ func (o *Oracle) fprintf(w io.Writer, pos interface{}, format string, args ...in
|
||||||
io.WriteString(w, "\n")
|
io.WriteString(w, "\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
// errorf is like fprintf, but returns a formatted error string.
|
|
||||||
func (o *Oracle) errorf(pos interface{}, format string, args ...interface{}) error {
|
|
||||||
var buf bytes.Buffer
|
|
||||||
o.fprintf(&buf, pos, format, args...)
|
|
||||||
return errors.New(buf.String())
|
|
||||||
}
|
|
||||||
|
|
||||||
// printNode returns the pretty-printed syntax of n.
|
// printNode returns the pretty-printed syntax of n.
|
||||||
func (o *Oracle) printNode(n ast.Node) string {
|
func (o *Oracle) printNode(n ast.Node) string {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package oracle
|
package oracle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/token"
|
"go/token"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -25,7 +26,7 @@ import (
|
||||||
func peers(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
func peers(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
||||||
arrowPos := findArrow(qpos)
|
arrowPos := findArrow(qpos)
|
||||||
if arrowPos == token.NoPos {
|
if arrowPos == token.NoPos {
|
||||||
return nil, o.errorf(qpos.path[0], "there is no send/receive here")
|
return nil, fmt.Errorf("there is no send/receive here")
|
||||||
}
|
}
|
||||||
|
|
||||||
buildSSA(o)
|
buildSSA(o)
|
||||||
|
@ -49,7 +50,7 @@ func peers(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if queryOp.ch == nil {
|
if queryOp.ch == nil {
|
||||||
return nil, o.errorf(arrowPos, "ssa.Instruction for send/receive not found")
|
return nil, fmt.Errorf("ssa.Instruction for send/receive not found")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Discard operations of wrong channel element type.
|
// Discard operations of wrong channel element type.
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
package oracle
|
package oracle
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"go/ast"
|
"go/ast"
|
||||||
"go/token"
|
"go/token"
|
||||||
"sort"
|
"sort"
|
||||||
|
@ -19,13 +20,13 @@ import (
|
||||||
func referrers(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
func referrers(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
||||||
id, _ := qpos.path[0].(*ast.Ident)
|
id, _ := qpos.path[0].(*ast.Ident)
|
||||||
if id == nil {
|
if id == nil {
|
||||||
return nil, o.errorf(qpos, "no identifier here")
|
return nil, fmt.Errorf("no identifier here")
|
||||||
}
|
}
|
||||||
|
|
||||||
obj := qpos.info.ObjectOf(id)
|
obj := qpos.info.ObjectOf(id)
|
||||||
if obj == nil {
|
if obj == nil {
|
||||||
// Happens for y in "switch y := x.(type)", but I think that's all.
|
// Happens for y in "switch y := x.(type)", but I think that's all.
|
||||||
return nil, o.errorf(qpos, "no object for identifier")
|
return nil, fmt.Errorf("no object for identifier")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over all go/types' resolver facts for the entire program.
|
// Iterate over all go/types' resolver facts for the entire program.
|
||||||
|
|
|
@ -68,22 +68,18 @@ value may point to these labels:
|
||||||
-------- @callees callees-err-no-call --------
|
-------- @callees callees-err-no-call --------
|
||||||
|
|
||||||
Error: there is no function call here
|
Error: there is no function call here
|
||||||
|
|
||||||
-------- @callees callees-err-builtin --------
|
-------- @callees callees-err-builtin --------
|
||||||
|
|
||||||
Error: this is a call to the built-in 'print' operator
|
Error: this is a call to the built-in 'print' operator
|
||||||
|
|
||||||
-------- @callees callees-err-conversion --------
|
-------- @callees callees-err-conversion --------
|
||||||
|
|
||||||
Error: this is a type conversion, not a function call
|
Error: this is a type conversion, not a function call
|
||||||
|
|
||||||
-------- @callees callees-err-bad-selection --------
|
-------- @callees callees-err-bad-selection --------
|
||||||
|
|
||||||
Error: ambiguous selection within function call (or conversion)
|
Error: ambiguous selection within function call (or conversion)
|
||||||
-------- @callees callees-err-deadcode1 --------
|
-------- @callees callees-err-deadcode1 --------
|
||||||
|
|
||||||
Error: this call site is unreachable in this analysis
|
Error: this call site is unreachable in this analysis
|
||||||
|
|
||||||
-------- @callees callees-err-nil-func --------
|
-------- @callees callees-err-nil-func --------
|
||||||
dynamic function call on nil value
|
dynamic function call on nil value
|
||||||
|
|
||||||
|
@ -93,7 +89,6 @@ dynamic method call on nil value
|
||||||
-------- @callees callees-err-deadcode2 --------
|
-------- @callees callees-err-deadcode2 --------
|
||||||
|
|
||||||
Error: this call site is unreachable in this analysis
|
Error: this call site is unreachable in this analysis
|
||||||
|
|
||||||
-------- @callstack callstack-err-deadcode --------
|
-------- @callstack callstack-err-deadcode --------
|
||||||
main.deadcode is unreachable in this analysis scope
|
main.deadcode is unreachable in this analysis scope
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue