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  }