| // Copyright 2015 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. | 
 |  | 
 | // This file defines the check for unused results of calls to certain | 
 | // pure functions. | 
 |  | 
 | package main | 
 |  | 
 | import ( | 
 | 	"flag" | 
 | 	"go/ast" | 
 | 	"go/token" | 
 | 	"go/types" | 
 | 	"strings" | 
 | ) | 
 |  | 
 | var unusedFuncsFlag = flag.String("unusedfuncs", | 
 | 	"errors.New,fmt.Errorf,fmt.Sprintf,fmt.Sprint,sort.Reverse", | 
 | 	"comma-separated list of functions whose results must be used") | 
 |  | 
 | var unusedStringMethodsFlag = flag.String("unusedstringmethods", | 
 | 	"Error,String", | 
 | 	"comma-separated list of names of methods of type func() string whose results must be used") | 
 |  | 
 | func init() { | 
 | 	register("unusedresult", | 
 | 		"check for unused result of calls to functions in -unusedfuncs list and methods in -unusedstringmethods list", | 
 | 		checkUnusedResult, | 
 | 		exprStmt) | 
 | } | 
 |  | 
 | // func() string | 
 | var sigNoArgsStringResult = types.NewSignature(nil, nil, | 
 | 	types.NewTuple(types.NewVar(token.NoPos, nil, "", types.Typ[types.String])), | 
 | 	false) | 
 |  | 
 | var unusedFuncs = make(map[string]bool) | 
 | var unusedStringMethods = make(map[string]bool) | 
 |  | 
 | func initUnusedFlags() { | 
 | 	commaSplit := func(s string, m map[string]bool) { | 
 | 		if s != "" { | 
 | 			for _, name := range strings.Split(s, ",") { | 
 | 				if len(name) == 0 { | 
 | 					flag.Usage() | 
 | 				} | 
 | 				m[name] = true | 
 | 			} | 
 | 		} | 
 | 	} | 
 | 	commaSplit(*unusedFuncsFlag, unusedFuncs) | 
 | 	commaSplit(*unusedStringMethodsFlag, unusedStringMethods) | 
 | } | 
 |  | 
 | func checkUnusedResult(f *File, n ast.Node) { | 
 | 	call, ok := unparen(n.(*ast.ExprStmt).X).(*ast.CallExpr) | 
 | 	if !ok { | 
 | 		return // not a call statement | 
 | 	} | 
 | 	fun := unparen(call.Fun) | 
 |  | 
 | 	if f.pkg.types[fun].IsType() { | 
 | 		return // a conversion, not a call | 
 | 	} | 
 |  | 
 | 	selector, ok := fun.(*ast.SelectorExpr) | 
 | 	if !ok { | 
 | 		return // neither a method call nor a qualified ident | 
 | 	} | 
 |  | 
 | 	sel, ok := f.pkg.selectors[selector] | 
 | 	if ok && sel.Kind() == types.MethodVal { | 
 | 		// method (e.g. foo.String()) | 
 | 		obj := sel.Obj().(*types.Func) | 
 | 		sig := sel.Type().(*types.Signature) | 
 | 		if types.Identical(sig, sigNoArgsStringResult) { | 
 | 			if unusedStringMethods[obj.Name()] { | 
 | 				f.Badf(call.Lparen, "result of (%s).%s call not used", | 
 | 					sig.Recv().Type(), obj.Name()) | 
 | 			} | 
 | 		} | 
 | 	} else if !ok { | 
 | 		// package-qualified function (e.g. fmt.Errorf) | 
 | 		obj := f.pkg.uses[selector.Sel] | 
 | 		if obj, ok := obj.(*types.Func); ok { | 
 | 			qname := obj.Pkg().Path() + "." + obj.Name() | 
 | 			if unusedFuncs[qname] { | 
 | 				f.Badf(call.Lparen, "result of %v call not used", qname) | 
 | 			} | 
 | 		} | 
 | 	} | 
 | } |