analysis.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428
  1. // Copyright 2020 The Go Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style
  3. // license that can be found in the LICENSE file.
  4. // Package analysisinternal exposes internal-only fields from go/analysis.
  5. package analysisinternal
  6. import (
  7. "bytes"
  8. "fmt"
  9. "go/ast"
  10. "go/token"
  11. "go/types"
  12. "strings"
  13. "golang.org/x/tools/go/ast/astutil"
  14. "golang.org/x/tools/internal/lsp/fuzzy"
  15. )
  16. // Flag to gate diagnostics for fuzz tests in 1.18.
  17. var DiagnoseFuzzTests bool = false
  18. var (
  19. GetTypeErrors func(p interface{}) []types.Error
  20. SetTypeErrors func(p interface{}, errors []types.Error)
  21. )
  22. func TypeErrorEndPos(fset *token.FileSet, src []byte, start token.Pos) token.Pos {
  23. // Get the end position for the type error.
  24. offset, end := fset.PositionFor(start, false).Offset, start
  25. if offset >= len(src) {
  26. return end
  27. }
  28. if width := bytes.IndexAny(src[offset:], " \n,():;[]+-*"); width > 0 {
  29. end = start + token.Pos(width)
  30. }
  31. return end
  32. }
  33. func ZeroValue(fset *token.FileSet, f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
  34. under := typ
  35. if n, ok := typ.(*types.Named); ok {
  36. under = n.Underlying()
  37. }
  38. switch u := under.(type) {
  39. case *types.Basic:
  40. switch {
  41. case u.Info()&types.IsNumeric != 0:
  42. return &ast.BasicLit{Kind: token.INT, Value: "0"}
  43. case u.Info()&types.IsBoolean != 0:
  44. return &ast.Ident{Name: "false"}
  45. case u.Info()&types.IsString != 0:
  46. return &ast.BasicLit{Kind: token.STRING, Value: `""`}
  47. default:
  48. panic("unknown basic type")
  49. }
  50. case *types.Chan, *types.Interface, *types.Map, *types.Pointer, *types.Signature, *types.Slice, *types.Array:
  51. return ast.NewIdent("nil")
  52. case *types.Struct:
  53. texpr := TypeExpr(fset, f, pkg, typ) // typ because we want the name here.
  54. if texpr == nil {
  55. return nil
  56. }
  57. return &ast.CompositeLit{
  58. Type: texpr,
  59. }
  60. }
  61. return nil
  62. }
  63. // IsZeroValue checks whether the given expression is a 'zero value' (as determined by output of
  64. // analysisinternal.ZeroValue)
  65. func IsZeroValue(expr ast.Expr) bool {
  66. switch e := expr.(type) {
  67. case *ast.BasicLit:
  68. return e.Value == "0" || e.Value == `""`
  69. case *ast.Ident:
  70. return e.Name == "nil" || e.Name == "false"
  71. default:
  72. return false
  73. }
  74. }
  75. func TypeExpr(fset *token.FileSet, f *ast.File, pkg *types.Package, typ types.Type) ast.Expr {
  76. switch t := typ.(type) {
  77. case *types.Basic:
  78. switch t.Kind() {
  79. case types.UnsafePointer:
  80. return &ast.SelectorExpr{X: ast.NewIdent("unsafe"), Sel: ast.NewIdent("Pointer")}
  81. default:
  82. return ast.NewIdent(t.Name())
  83. }
  84. case *types.Pointer:
  85. x := TypeExpr(fset, f, pkg, t.Elem())
  86. if x == nil {
  87. return nil
  88. }
  89. return &ast.UnaryExpr{
  90. Op: token.MUL,
  91. X: x,
  92. }
  93. case *types.Array:
  94. elt := TypeExpr(fset, f, pkg, t.Elem())
  95. if elt == nil {
  96. return nil
  97. }
  98. return &ast.ArrayType{
  99. Len: &ast.BasicLit{
  100. Kind: token.INT,
  101. Value: fmt.Sprintf("%d", t.Len()),
  102. },
  103. Elt: elt,
  104. }
  105. case *types.Slice:
  106. elt := TypeExpr(fset, f, pkg, t.Elem())
  107. if elt == nil {
  108. return nil
  109. }
  110. return &ast.ArrayType{
  111. Elt: elt,
  112. }
  113. case *types.Map:
  114. key := TypeExpr(fset, f, pkg, t.Key())
  115. value := TypeExpr(fset, f, pkg, t.Elem())
  116. if key == nil || value == nil {
  117. return nil
  118. }
  119. return &ast.MapType{
  120. Key: key,
  121. Value: value,
  122. }
  123. case *types.Chan:
  124. dir := ast.ChanDir(t.Dir())
  125. if t.Dir() == types.SendRecv {
  126. dir = ast.SEND | ast.RECV
  127. }
  128. value := TypeExpr(fset, f, pkg, t.Elem())
  129. if value == nil {
  130. return nil
  131. }
  132. return &ast.ChanType{
  133. Dir: dir,
  134. Value: value,
  135. }
  136. case *types.Signature:
  137. var params []*ast.Field
  138. for i := 0; i < t.Params().Len(); i++ {
  139. p := TypeExpr(fset, f, pkg, t.Params().At(i).Type())
  140. if p == nil {
  141. return nil
  142. }
  143. params = append(params, &ast.Field{
  144. Type: p,
  145. Names: []*ast.Ident{
  146. {
  147. Name: t.Params().At(i).Name(),
  148. },
  149. },
  150. })
  151. }
  152. var returns []*ast.Field
  153. for i := 0; i < t.Results().Len(); i++ {
  154. r := TypeExpr(fset, f, pkg, t.Results().At(i).Type())
  155. if r == nil {
  156. return nil
  157. }
  158. returns = append(returns, &ast.Field{
  159. Type: r,
  160. })
  161. }
  162. return &ast.FuncType{
  163. Params: &ast.FieldList{
  164. List: params,
  165. },
  166. Results: &ast.FieldList{
  167. List: returns,
  168. },
  169. }
  170. case *types.Named:
  171. if t.Obj().Pkg() == nil {
  172. return ast.NewIdent(t.Obj().Name())
  173. }
  174. if t.Obj().Pkg() == pkg {
  175. return ast.NewIdent(t.Obj().Name())
  176. }
  177. pkgName := t.Obj().Pkg().Name()
  178. // If the file already imports the package under another name, use that.
  179. for _, group := range astutil.Imports(fset, f) {
  180. for _, cand := range group {
  181. if strings.Trim(cand.Path.Value, `"`) == t.Obj().Pkg().Path() {
  182. if cand.Name != nil && cand.Name.Name != "" {
  183. pkgName = cand.Name.Name
  184. }
  185. }
  186. }
  187. }
  188. if pkgName == "." {
  189. return ast.NewIdent(t.Obj().Name())
  190. }
  191. return &ast.SelectorExpr{
  192. X: ast.NewIdent(pkgName),
  193. Sel: ast.NewIdent(t.Obj().Name()),
  194. }
  195. case *types.Struct:
  196. return ast.NewIdent(t.String())
  197. case *types.Interface:
  198. return ast.NewIdent(t.String())
  199. default:
  200. return nil
  201. }
  202. }
  203. type TypeErrorPass string
  204. const (
  205. NoNewVars TypeErrorPass = "nonewvars"
  206. NoResultValues TypeErrorPass = "noresultvalues"
  207. UndeclaredName TypeErrorPass = "undeclaredname"
  208. )
  209. // StmtToInsertVarBefore returns the ast.Stmt before which we can safely insert a new variable.
  210. // Some examples:
  211. //
  212. // Basic Example:
  213. // z := 1
  214. // y := z + x
  215. // If x is undeclared, then this function would return `y := z + x`, so that we
  216. // can insert `x := ` on the line before `y := z + x`.
  217. //
  218. // If stmt example:
  219. // if z == 1 {
  220. // } else if z == y {}
  221. // If y is undeclared, then this function would return `if z == 1 {`, because we cannot
  222. // insert a statement between an if and an else if statement. As a result, we need to find
  223. // the top of the if chain to insert `y := ` before.
  224. func StmtToInsertVarBefore(path []ast.Node) ast.Stmt {
  225. enclosingIndex := -1
  226. for i, p := range path {
  227. if _, ok := p.(ast.Stmt); ok {
  228. enclosingIndex = i
  229. break
  230. }
  231. }
  232. if enclosingIndex == -1 {
  233. return nil
  234. }
  235. enclosingStmt := path[enclosingIndex]
  236. switch enclosingStmt.(type) {
  237. case *ast.IfStmt:
  238. // The enclosingStmt is inside of the if declaration,
  239. // We need to check if we are in an else-if stmt and
  240. // get the base if statement.
  241. return baseIfStmt(path, enclosingIndex)
  242. case *ast.CaseClause:
  243. // Get the enclosing switch stmt if the enclosingStmt is
  244. // inside of the case statement.
  245. for i := enclosingIndex + 1; i < len(path); i++ {
  246. if node, ok := path[i].(*ast.SwitchStmt); ok {
  247. return node
  248. } else if node, ok := path[i].(*ast.TypeSwitchStmt); ok {
  249. return node
  250. }
  251. }
  252. }
  253. if len(path) <= enclosingIndex+1 {
  254. return enclosingStmt.(ast.Stmt)
  255. }
  256. // Check if the enclosing statement is inside another node.
  257. switch expr := path[enclosingIndex+1].(type) {
  258. case *ast.IfStmt:
  259. // Get the base if statement.
  260. return baseIfStmt(path, enclosingIndex+1)
  261. case *ast.ForStmt:
  262. if expr.Init == enclosingStmt || expr.Post == enclosingStmt {
  263. return expr
  264. }
  265. }
  266. return enclosingStmt.(ast.Stmt)
  267. }
  268. // baseIfStmt walks up the if/else-if chain until we get to
  269. // the top of the current if chain.
  270. func baseIfStmt(path []ast.Node, index int) ast.Stmt {
  271. stmt := path[index]
  272. for i := index + 1; i < len(path); i++ {
  273. if node, ok := path[i].(*ast.IfStmt); ok && node.Else == stmt {
  274. stmt = node
  275. continue
  276. }
  277. break
  278. }
  279. return stmt.(ast.Stmt)
  280. }
  281. // WalkASTWithParent walks the AST rooted at n. The semantics are
  282. // similar to ast.Inspect except it does not call f(nil).
  283. func WalkASTWithParent(n ast.Node, f func(n ast.Node, parent ast.Node) bool) {
  284. var ancestors []ast.Node
  285. ast.Inspect(n, func(n ast.Node) (recurse bool) {
  286. if n == nil {
  287. ancestors = ancestors[:len(ancestors)-1]
  288. return false
  289. }
  290. var parent ast.Node
  291. if len(ancestors) > 0 {
  292. parent = ancestors[len(ancestors)-1]
  293. }
  294. ancestors = append(ancestors, n)
  295. return f(n, parent)
  296. })
  297. }
  298. // FindMatchingIdents finds all identifiers in 'node' that match any of the given types.
  299. // 'pos' represents the position at which the identifiers may be inserted. 'pos' must be within
  300. // the scope of each of identifier we select. Otherwise, we will insert a variable at 'pos' that
  301. // is unrecognized.
  302. func FindMatchingIdents(typs []types.Type, node ast.Node, pos token.Pos, info *types.Info, pkg *types.Package) map[types.Type][]*ast.Ident {
  303. matches := map[types.Type][]*ast.Ident{}
  304. // Initialize matches to contain the variable types we are searching for.
  305. for _, typ := range typs {
  306. if typ == nil {
  307. continue
  308. }
  309. matches[typ] = []*ast.Ident{}
  310. }
  311. seen := map[types.Object]struct{}{}
  312. ast.Inspect(node, func(n ast.Node) bool {
  313. if n == nil {
  314. return false
  315. }
  316. // Prevent circular definitions. If 'pos' is within an assignment statement, do not
  317. // allow any identifiers in that assignment statement to be selected. Otherwise,
  318. // we could do the following, where 'x' satisfies the type of 'f0':
  319. //
  320. // x := fakeStruct{f0: x}
  321. //
  322. assignment, ok := n.(*ast.AssignStmt)
  323. if ok && pos > assignment.Pos() && pos <= assignment.End() {
  324. return false
  325. }
  326. if n.End() > pos {
  327. return n.Pos() <= pos
  328. }
  329. ident, ok := n.(*ast.Ident)
  330. if !ok || ident.Name == "_" {
  331. return true
  332. }
  333. obj := info.Defs[ident]
  334. if obj == nil || obj.Type() == nil {
  335. return true
  336. }
  337. if _, ok := obj.(*types.TypeName); ok {
  338. return true
  339. }
  340. // Prevent duplicates in matches' values.
  341. if _, ok = seen[obj]; ok {
  342. return true
  343. }
  344. seen[obj] = struct{}{}
  345. // Find the scope for the given position. Then, check whether the object
  346. // exists within the scope.
  347. innerScope := pkg.Scope().Innermost(pos)
  348. if innerScope == nil {
  349. return true
  350. }
  351. _, foundObj := innerScope.LookupParent(ident.Name, pos)
  352. if foundObj != obj {
  353. return true
  354. }
  355. // The object must match one of the types that we are searching for.
  356. if idents, ok := matches[obj.Type()]; ok {
  357. matches[obj.Type()] = append(idents, ast.NewIdent(ident.Name))
  358. }
  359. // If the object type does not exactly match any of the target types, greedily
  360. // find the first target type that the object type can satisfy.
  361. for typ := range matches {
  362. if obj.Type() == typ {
  363. continue
  364. }
  365. if equivalentTypes(obj.Type(), typ) {
  366. matches[typ] = append(matches[typ], ast.NewIdent(ident.Name))
  367. }
  368. }
  369. return true
  370. })
  371. return matches
  372. }
  373. func equivalentTypes(want, got types.Type) bool {
  374. if want == got || types.Identical(want, got) {
  375. return true
  376. }
  377. // Code segment to help check for untyped equality from (golang/go#32146).
  378. if rhs, ok := want.(*types.Basic); ok && rhs.Info()&types.IsUntyped > 0 {
  379. if lhs, ok := got.Underlying().(*types.Basic); ok {
  380. return rhs.Info()&types.IsConstType == lhs.Info()&types.IsConstType
  381. }
  382. }
  383. return types.AssignableTo(want, got)
  384. }
  385. // FindBestMatch employs fuzzy matching to evaluate the similarity of each given identifier to the
  386. // given pattern. We return the identifier whose name is most similar to the pattern.
  387. func FindBestMatch(pattern string, idents []*ast.Ident) ast.Expr {
  388. fuzz := fuzzy.NewMatcher(pattern)
  389. var bestFuzz ast.Expr
  390. highScore := float32(0) // minimum score is 0 (no match)
  391. for _, ident := range idents {
  392. // TODO: Improve scoring algorithm.
  393. score := fuzz.Score(ident.Name)
  394. if score > highScore {
  395. highScore = score
  396. bestFuzz = ident
  397. } else if score == 0 {
  398. // Order matters in the fuzzy matching algorithm. If we find no match
  399. // when matching the target to the identifier, try matching the identifier
  400. // to the target.
  401. revFuzz := fuzzy.NewMatcher(ident.Name)
  402. revScore := revFuzz.Score(pattern)
  403. if revScore > highScore {
  404. highScore = revScore
  405. bestFuzz = ident
  406. }
  407. }
  408. }
  409. return bestFuzz
  410. }