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