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