github.com/powerman/golang-tools@v0.1.11-0.20220410185822-5ad214d8d803/go/ast/inspector/typeof.go (about) 1 // Copyright 2018 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 5 package inspector 6 7 // This file defines func typeOf(ast.Node) uint64. 8 // 9 // The initial map-based implementation was too slow; 10 // see https://go-review.googlesource.com/c/tools/+/135655/1/go/ast/inspector/inspector.go#196 11 12 import ( 13 "go/ast" 14 15 "github.com/powerman/golang-tools/internal/typeparams" 16 ) 17 18 const ( 19 nArrayType = iota 20 nAssignStmt 21 nBadDecl 22 nBadExpr 23 nBadStmt 24 nBasicLit 25 nBinaryExpr 26 nBlockStmt 27 nBranchStmt 28 nCallExpr 29 nCaseClause 30 nChanType 31 nCommClause 32 nComment 33 nCommentGroup 34 nCompositeLit 35 nDeclStmt 36 nDeferStmt 37 nEllipsis 38 nEmptyStmt 39 nExprStmt 40 nField 41 nFieldList 42 nFile 43 nForStmt 44 nFuncDecl 45 nFuncLit 46 nFuncType 47 nGenDecl 48 nGoStmt 49 nIdent 50 nIfStmt 51 nImportSpec 52 nIncDecStmt 53 nIndexExpr 54 nIndexListExpr 55 nInterfaceType 56 nKeyValueExpr 57 nLabeledStmt 58 nMapType 59 nPackage 60 nParenExpr 61 nRangeStmt 62 nReturnStmt 63 nSelectStmt 64 nSelectorExpr 65 nSendStmt 66 nSliceExpr 67 nStarExpr 68 nStructType 69 nSwitchStmt 70 nTypeAssertExpr 71 nTypeSpec 72 nTypeSwitchStmt 73 nUnaryExpr 74 nValueSpec 75 ) 76 77 // typeOf returns a distinct single-bit value that represents the type of n. 78 // 79 // Various implementations were benchmarked with BenchmarkNewInspector: 80 // GOGC=off 81 // - type switch 4.9-5.5ms 2.1ms 82 // - binary search over a sorted list of types 5.5-5.9ms 2.5ms 83 // - linear scan, frequency-ordered list 5.9-6.1ms 2.7ms 84 // - linear scan, unordered list 6.4ms 2.7ms 85 // - hash table 6.5ms 3.1ms 86 // A perfect hash seemed like overkill. 87 // 88 // The compiler's switch statement is the clear winner 89 // as it produces a binary tree in code, 90 // with constant conditions and good branch prediction. 91 // (Sadly it is the most verbose in source code.) 92 // Binary search suffered from poor branch prediction. 93 // 94 func typeOf(n ast.Node) uint64 { 95 // Fast path: nearly half of all nodes are identifiers. 96 if _, ok := n.(*ast.Ident); ok { 97 return 1 << nIdent 98 } 99 100 // These cases include all nodes encountered by ast.Inspect. 101 switch n.(type) { 102 case *ast.ArrayType: 103 return 1 << nArrayType 104 case *ast.AssignStmt: 105 return 1 << nAssignStmt 106 case *ast.BadDecl: 107 return 1 << nBadDecl 108 case *ast.BadExpr: 109 return 1 << nBadExpr 110 case *ast.BadStmt: 111 return 1 << nBadStmt 112 case *ast.BasicLit: 113 return 1 << nBasicLit 114 case *ast.BinaryExpr: 115 return 1 << nBinaryExpr 116 case *ast.BlockStmt: 117 return 1 << nBlockStmt 118 case *ast.BranchStmt: 119 return 1 << nBranchStmt 120 case *ast.CallExpr: 121 return 1 << nCallExpr 122 case *ast.CaseClause: 123 return 1 << nCaseClause 124 case *ast.ChanType: 125 return 1 << nChanType 126 case *ast.CommClause: 127 return 1 << nCommClause 128 case *ast.Comment: 129 return 1 << nComment 130 case *ast.CommentGroup: 131 return 1 << nCommentGroup 132 case *ast.CompositeLit: 133 return 1 << nCompositeLit 134 case *ast.DeclStmt: 135 return 1 << nDeclStmt 136 case *ast.DeferStmt: 137 return 1 << nDeferStmt 138 case *ast.Ellipsis: 139 return 1 << nEllipsis 140 case *ast.EmptyStmt: 141 return 1 << nEmptyStmt 142 case *ast.ExprStmt: 143 return 1 << nExprStmt 144 case *ast.Field: 145 return 1 << nField 146 case *ast.FieldList: 147 return 1 << nFieldList 148 case *ast.File: 149 return 1 << nFile 150 case *ast.ForStmt: 151 return 1 << nForStmt 152 case *ast.FuncDecl: 153 return 1 << nFuncDecl 154 case *ast.FuncLit: 155 return 1 << nFuncLit 156 case *ast.FuncType: 157 return 1 << nFuncType 158 case *ast.GenDecl: 159 return 1 << nGenDecl 160 case *ast.GoStmt: 161 return 1 << nGoStmt 162 case *ast.Ident: 163 return 1 << nIdent 164 case *ast.IfStmt: 165 return 1 << nIfStmt 166 case *ast.ImportSpec: 167 return 1 << nImportSpec 168 case *ast.IncDecStmt: 169 return 1 << nIncDecStmt 170 case *ast.IndexExpr: 171 return 1 << nIndexExpr 172 case *typeparams.IndexListExpr: 173 return 1 << nIndexListExpr 174 case *ast.InterfaceType: 175 return 1 << nInterfaceType 176 case *ast.KeyValueExpr: 177 return 1 << nKeyValueExpr 178 case *ast.LabeledStmt: 179 return 1 << nLabeledStmt 180 case *ast.MapType: 181 return 1 << nMapType 182 case *ast.Package: 183 return 1 << nPackage 184 case *ast.ParenExpr: 185 return 1 << nParenExpr 186 case *ast.RangeStmt: 187 return 1 << nRangeStmt 188 case *ast.ReturnStmt: 189 return 1 << nReturnStmt 190 case *ast.SelectStmt: 191 return 1 << nSelectStmt 192 case *ast.SelectorExpr: 193 return 1 << nSelectorExpr 194 case *ast.SendStmt: 195 return 1 << nSendStmt 196 case *ast.SliceExpr: 197 return 1 << nSliceExpr 198 case *ast.StarExpr: 199 return 1 << nStarExpr 200 case *ast.StructType: 201 return 1 << nStructType 202 case *ast.SwitchStmt: 203 return 1 << nSwitchStmt 204 case *ast.TypeAssertExpr: 205 return 1 << nTypeAssertExpr 206 case *ast.TypeSpec: 207 return 1 << nTypeSpec 208 case *ast.TypeSwitchStmt: 209 return 1 << nTypeSwitchStmt 210 case *ast.UnaryExpr: 211 return 1 << nUnaryExpr 212 case *ast.ValueSpec: 213 return 1 << nValueSpec 214 } 215 return 0 216 } 217 218 func maskOf(nodes []ast.Node) uint64 { 219 if nodes == nil { 220 return 1<<64 - 1 // match all node types 221 } 222 var mask uint64 223 for _, n := range nodes { 224 mask |= typeOf(n) 225 } 226 return mask 227 }