src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

walk.go (7924B)


      1 // Copyright 2025 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 is a fork of ast.Inspect to reduce unnecessary dynamic
      8 // calls and to gather edge information.
      9 //
     10 // Consistency with the original is ensured by TestInspectAllNodes.
     11 
     12 import (
     13 	"fmt"
     14 	"go/ast"
     15 
     16 	"golang.org/x/tools/go/ast/edge"
     17 )
     18 
     19 func walkList[N ast.Node](v *visitor, ek edge.Kind, list []N) {
     20 	for i, node := range list {
     21 		walk(v, ek, i, node)
     22 	}
     23 }
     24 
     25 func walk(v *visitor, ek edge.Kind, index int, node ast.Node) {
     26 	v.push(ek, index, node)
     27 
     28 	// walk children
     29 	// (the order of the cases matches the order
     30 	// of the corresponding node types in ast.go)
     31 	switch n := node.(type) {
     32 	// Comments and fields
     33 	case *ast.Comment:
     34 		// nothing to do
     35 
     36 	case *ast.CommentGroup:
     37 		walkList(v, edge.CommentGroup_List, n.List)
     38 
     39 	case *ast.Field:
     40 		if n.Doc != nil {
     41 			walk(v, edge.Field_Doc, -1, n.Doc)
     42 		}
     43 		walkList(v, edge.Field_Names, n.Names)
     44 		if n.Type != nil {
     45 			walk(v, edge.Field_Type, -1, n.Type)
     46 		}
     47 		if n.Tag != nil {
     48 			walk(v, edge.Field_Tag, -1, n.Tag)
     49 		}
     50 		if n.Comment != nil {
     51 			walk(v, edge.Field_Comment, -1, n.Comment)
     52 		}
     53 
     54 	case *ast.FieldList:
     55 		walkList(v, edge.FieldList_List, n.List)
     56 
     57 	// Expressions
     58 	case *ast.BadExpr, *ast.Ident, *ast.BasicLit:
     59 		// nothing to do
     60 
     61 	case *ast.Ellipsis:
     62 		if n.Elt != nil {
     63 			walk(v, edge.Ellipsis_Elt, -1, n.Elt)
     64 		}
     65 
     66 	case *ast.FuncLit:
     67 		walk(v, edge.FuncLit_Type, -1, n.Type)
     68 		walk(v, edge.FuncLit_Body, -1, n.Body)
     69 
     70 	case *ast.CompositeLit:
     71 		if n.Type != nil {
     72 			walk(v, edge.CompositeLit_Type, -1, n.Type)
     73 		}
     74 		walkList(v, edge.CompositeLit_Elts, n.Elts)
     75 
     76 	case *ast.ParenExpr:
     77 		walk(v, edge.ParenExpr_X, -1, n.X)
     78 
     79 	case *ast.SelectorExpr:
     80 		walk(v, edge.SelectorExpr_X, -1, n.X)
     81 		walk(v, edge.SelectorExpr_Sel, -1, n.Sel)
     82 
     83 	case *ast.IndexExpr:
     84 		walk(v, edge.IndexExpr_X, -1, n.X)
     85 		walk(v, edge.IndexExpr_Index, -1, n.Index)
     86 
     87 	case *ast.IndexListExpr:
     88 		walk(v, edge.IndexListExpr_X, -1, n.X)
     89 		walkList(v, edge.IndexListExpr_Indices, n.Indices)
     90 
     91 	case *ast.SliceExpr:
     92 		walk(v, edge.SliceExpr_X, -1, n.X)
     93 		if n.Low != nil {
     94 			walk(v, edge.SliceExpr_Low, -1, n.Low)
     95 		}
     96 		if n.High != nil {
     97 			walk(v, edge.SliceExpr_High, -1, n.High)
     98 		}
     99 		if n.Max != nil {
    100 			walk(v, edge.SliceExpr_Max, -1, n.Max)
    101 		}
    102 
    103 	case *ast.TypeAssertExpr:
    104 		walk(v, edge.TypeAssertExpr_X, -1, n.X)
    105 		if n.Type != nil {
    106 			walk(v, edge.TypeAssertExpr_Type, -1, n.Type)
    107 		}
    108 
    109 	case *ast.CallExpr:
    110 		walk(v, edge.CallExpr_Fun, -1, n.Fun)
    111 		walkList(v, edge.CallExpr_Args, n.Args)
    112 
    113 	case *ast.StarExpr:
    114 		walk(v, edge.StarExpr_X, -1, n.X)
    115 
    116 	case *ast.UnaryExpr:
    117 		walk(v, edge.UnaryExpr_X, -1, n.X)
    118 
    119 	case *ast.BinaryExpr:
    120 		walk(v, edge.BinaryExpr_X, -1, n.X)
    121 		walk(v, edge.BinaryExpr_Y, -1, n.Y)
    122 
    123 	case *ast.KeyValueExpr:
    124 		walk(v, edge.KeyValueExpr_Key, -1, n.Key)
    125 		walk(v, edge.KeyValueExpr_Value, -1, n.Value)
    126 
    127 	// Types
    128 	case *ast.ArrayType:
    129 		if n.Len != nil {
    130 			walk(v, edge.ArrayType_Len, -1, n.Len)
    131 		}
    132 		walk(v, edge.ArrayType_Elt, -1, n.Elt)
    133 
    134 	case *ast.StructType:
    135 		walk(v, edge.StructType_Fields, -1, n.Fields)
    136 
    137 	case *ast.FuncType:
    138 		if n.TypeParams != nil {
    139 			walk(v, edge.FuncType_TypeParams, -1, n.TypeParams)
    140 		}
    141 		if n.Params != nil {
    142 			walk(v, edge.FuncType_Params, -1, n.Params)
    143 		}
    144 		if n.Results != nil {
    145 			walk(v, edge.FuncType_Results, -1, n.Results)
    146 		}
    147 
    148 	case *ast.InterfaceType:
    149 		walk(v, edge.InterfaceType_Methods, -1, n.Methods)
    150 
    151 	case *ast.MapType:
    152 		walk(v, edge.MapType_Key, -1, n.Key)
    153 		walk(v, edge.MapType_Value, -1, n.Value)
    154 
    155 	case *ast.ChanType:
    156 		walk(v, edge.ChanType_Value, -1, n.Value)
    157 
    158 	// Statements
    159 	case *ast.BadStmt:
    160 		// nothing to do
    161 
    162 	case *ast.DeclStmt:
    163 		walk(v, edge.DeclStmt_Decl, -1, n.Decl)
    164 
    165 	case *ast.EmptyStmt:
    166 		// nothing to do
    167 
    168 	case *ast.LabeledStmt:
    169 		walk(v, edge.LabeledStmt_Label, -1, n.Label)
    170 		walk(v, edge.LabeledStmt_Stmt, -1, n.Stmt)
    171 
    172 	case *ast.ExprStmt:
    173 		walk(v, edge.ExprStmt_X, -1, n.X)
    174 
    175 	case *ast.SendStmt:
    176 		walk(v, edge.SendStmt_Chan, -1, n.Chan)
    177 		walk(v, edge.SendStmt_Value, -1, n.Value)
    178 
    179 	case *ast.IncDecStmt:
    180 		walk(v, edge.IncDecStmt_X, -1, n.X)
    181 
    182 	case *ast.AssignStmt:
    183 		walkList(v, edge.AssignStmt_Lhs, n.Lhs)
    184 		walkList(v, edge.AssignStmt_Rhs, n.Rhs)
    185 
    186 	case *ast.GoStmt:
    187 		walk(v, edge.GoStmt_Call, -1, n.Call)
    188 
    189 	case *ast.DeferStmt:
    190 		walk(v, edge.DeferStmt_Call, -1, n.Call)
    191 
    192 	case *ast.ReturnStmt:
    193 		walkList(v, edge.ReturnStmt_Results, n.Results)
    194 
    195 	case *ast.BranchStmt:
    196 		if n.Label != nil {
    197 			walk(v, edge.BranchStmt_Label, -1, n.Label)
    198 		}
    199 
    200 	case *ast.BlockStmt:
    201 		walkList(v, edge.BlockStmt_List, n.List)
    202 
    203 	case *ast.IfStmt:
    204 		if n.Init != nil {
    205 			walk(v, edge.IfStmt_Init, -1, n.Init)
    206 		}
    207 		walk(v, edge.IfStmt_Cond, -1, n.Cond)
    208 		walk(v, edge.IfStmt_Body, -1, n.Body)
    209 		if n.Else != nil {
    210 			walk(v, edge.IfStmt_Else, -1, n.Else)
    211 		}
    212 
    213 	case *ast.CaseClause:
    214 		walkList(v, edge.CaseClause_List, n.List)
    215 		walkList(v, edge.CaseClause_Body, n.Body)
    216 
    217 	case *ast.SwitchStmt:
    218 		if n.Init != nil {
    219 			walk(v, edge.SwitchStmt_Init, -1, n.Init)
    220 		}
    221 		if n.Tag != nil {
    222 			walk(v, edge.SwitchStmt_Tag, -1, n.Tag)
    223 		}
    224 		walk(v, edge.SwitchStmt_Body, -1, n.Body)
    225 
    226 	case *ast.TypeSwitchStmt:
    227 		if n.Init != nil {
    228 			walk(v, edge.TypeSwitchStmt_Init, -1, n.Init)
    229 		}
    230 		walk(v, edge.TypeSwitchStmt_Assign, -1, n.Assign)
    231 		walk(v, edge.TypeSwitchStmt_Body, -1, n.Body)
    232 
    233 	case *ast.CommClause:
    234 		if n.Comm != nil {
    235 			walk(v, edge.CommClause_Comm, -1, n.Comm)
    236 		}
    237 		walkList(v, edge.CommClause_Body, n.Body)
    238 
    239 	case *ast.SelectStmt:
    240 		walk(v, edge.SelectStmt_Body, -1, n.Body)
    241 
    242 	case *ast.ForStmt:
    243 		if n.Init != nil {
    244 			walk(v, edge.ForStmt_Init, -1, n.Init)
    245 		}
    246 		if n.Cond != nil {
    247 			walk(v, edge.ForStmt_Cond, -1, n.Cond)
    248 		}
    249 		if n.Post != nil {
    250 			walk(v, edge.ForStmt_Post, -1, n.Post)
    251 		}
    252 		walk(v, edge.ForStmt_Body, -1, n.Body)
    253 
    254 	case *ast.RangeStmt:
    255 		if n.Key != nil {
    256 			walk(v, edge.RangeStmt_Key, -1, n.Key)
    257 		}
    258 		if n.Value != nil {
    259 			walk(v, edge.RangeStmt_Value, -1, n.Value)
    260 		}
    261 		walk(v, edge.RangeStmt_X, -1, n.X)
    262 		walk(v, edge.RangeStmt_Body, -1, n.Body)
    263 
    264 	// Declarations
    265 	case *ast.ImportSpec:
    266 		if n.Doc != nil {
    267 			walk(v, edge.ImportSpec_Doc, -1, n.Doc)
    268 		}
    269 		if n.Name != nil {
    270 			walk(v, edge.ImportSpec_Name, -1, n.Name)
    271 		}
    272 		walk(v, edge.ImportSpec_Path, -1, n.Path)
    273 		if n.Comment != nil {
    274 			walk(v, edge.ImportSpec_Comment, -1, n.Comment)
    275 		}
    276 
    277 	case *ast.ValueSpec:
    278 		if n.Doc != nil {
    279 			walk(v, edge.ValueSpec_Doc, -1, n.Doc)
    280 		}
    281 		walkList(v, edge.ValueSpec_Names, n.Names)
    282 		if n.Type != nil {
    283 			walk(v, edge.ValueSpec_Type, -1, n.Type)
    284 		}
    285 		walkList(v, edge.ValueSpec_Values, n.Values)
    286 		if n.Comment != nil {
    287 			walk(v, edge.ValueSpec_Comment, -1, n.Comment)
    288 		}
    289 
    290 	case *ast.TypeSpec:
    291 		if n.Doc != nil {
    292 			walk(v, edge.TypeSpec_Doc, -1, n.Doc)
    293 		}
    294 		walk(v, edge.TypeSpec_Name, -1, n.Name)
    295 		if n.TypeParams != nil {
    296 			walk(v, edge.TypeSpec_TypeParams, -1, n.TypeParams)
    297 		}
    298 		walk(v, edge.TypeSpec_Type, -1, n.Type)
    299 		if n.Comment != nil {
    300 			walk(v, edge.TypeSpec_Comment, -1, n.Comment)
    301 		}
    302 
    303 	case *ast.BadDecl:
    304 		// nothing to do
    305 
    306 	case *ast.GenDecl:
    307 		if n.Doc != nil {
    308 			walk(v, edge.GenDecl_Doc, -1, n.Doc)
    309 		}
    310 		walkList(v, edge.GenDecl_Specs, n.Specs)
    311 
    312 	case *ast.FuncDecl:
    313 		if n.Doc != nil {
    314 			walk(v, edge.FuncDecl_Doc, -1, n.Doc)
    315 		}
    316 		if n.Recv != nil {
    317 			walk(v, edge.FuncDecl_Recv, -1, n.Recv)
    318 		}
    319 		walk(v, edge.FuncDecl_Name, -1, n.Name)
    320 		walk(v, edge.FuncDecl_Type, -1, n.Type)
    321 		if n.Body != nil {
    322 			walk(v, edge.FuncDecl_Body, -1, n.Body)
    323 		}
    324 
    325 	case *ast.File:
    326 		if n.Doc != nil {
    327 			walk(v, edge.File_Doc, -1, n.Doc)
    328 		}
    329 		walk(v, edge.File_Name, -1, n.Name)
    330 		walkList(v, edge.File_Decls, n.Decls)
    331 		// don't walk n.Comments - they have been
    332 		// visited already through the individual
    333 		// nodes
    334 
    335 	default:
    336 		// (includes *ast.Package)
    337 		panic(fmt.Sprintf("Walk: unexpected node type %T", n))
    338 	}
    339 
    340 	v.pop(node)
    341 }