edge.go (9854B)
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 edge defines identifiers for each field of an ast.Node 6 // struct type that refers to another Node. 7 package edge 8 9 import ( 10 "fmt" 11 "go/ast" 12 "reflect" 13 ) 14 15 // A Kind describes a field of an [ast.Node] struct. 16 type Kind uint8 17 18 // String returns a description of the edge kind. 19 func (k Kind) String() string { 20 if k == Invalid { 21 return "<invalid>" 22 } 23 info := fieldInfos[k] 24 return fmt.Sprintf("%v.%s", info.nodeType.Elem().Name(), info.name) 25 } 26 27 // NodeType returns the pointer-to-struct type of the ast.Node implementation. 28 func (k Kind) NodeType() reflect.Type { return fieldInfos[k].nodeType } 29 30 // FieldName returns the name of the field. 31 func (k Kind) FieldName() string { return fieldInfos[k].name } 32 33 // FieldType returns the declared type of the field. 34 func (k Kind) FieldType() reflect.Type { return fieldInfos[k].fieldType } 35 36 // Get returns the direct child of n identified by (k, idx). 37 // n's type must match k.NodeType(). 38 // idx must be a valid slice index, or -1 for a non-slice. 39 func (k Kind) Get(n ast.Node, idx int) ast.Node { 40 if k.NodeType() != reflect.TypeOf(n) { 41 panic(fmt.Sprintf("%v.Get(%T): invalid node type", k, n)) 42 } 43 v := reflect.ValueOf(n).Elem().Field(fieldInfos[k].index) 44 45 if v.Kind() == reflect.Slice { 46 v = v.Index(idx) // asserts valid idx 47 } else if idx != -1 { 48 panic(fmt.Sprintf("%v, Get(%T, %d): cannot index non-slice", v, n, idx)) 49 } 50 51 out, _ := v.Interface().(ast.Node) // may be nil 52 return out 53 } 54 55 // Each [Kind] is named Type_Field, where Type is the 56 // [ast.Node] struct type and Field is the name of the field 57 const ( 58 Invalid Kind = iota // for nodes at the root of the traversal 59 60 // As of Go1.26 these kinds are sorted alphabetically, but 61 // numbering must be stable, so any new addition of const should 62 // use a new value (be added at the end of the list). 63 64 ArrayType_Elt 65 ArrayType_Len 66 AssignStmt_Lhs 67 AssignStmt_Rhs 68 BinaryExpr_X 69 BinaryExpr_Y 70 BlockStmt_List 71 BranchStmt_Label 72 CallExpr_Args 73 CallExpr_Fun 74 CaseClause_Body 75 CaseClause_List 76 ChanType_Value 77 CommClause_Body 78 CommClause_Comm 79 CommentGroup_List 80 CompositeLit_Elts 81 CompositeLit_Type 82 DeclStmt_Decl 83 DeferStmt_Call 84 Ellipsis_Elt 85 ExprStmt_X 86 FieldList_List 87 Field_Comment 88 Field_Doc 89 Field_Names 90 Field_Tag 91 Field_Type 92 File_Decls 93 File_Doc 94 File_Name 95 ForStmt_Body 96 ForStmt_Cond 97 ForStmt_Init 98 ForStmt_Post 99 FuncDecl_Body 100 FuncDecl_Doc 101 FuncDecl_Name 102 FuncDecl_Recv 103 FuncDecl_Type 104 FuncLit_Body 105 FuncLit_Type 106 FuncType_Params 107 FuncType_Results 108 FuncType_TypeParams 109 GenDecl_Doc 110 GenDecl_Specs 111 GoStmt_Call 112 IfStmt_Body 113 IfStmt_Cond 114 IfStmt_Else 115 IfStmt_Init 116 ImportSpec_Comment 117 ImportSpec_Doc 118 ImportSpec_Name 119 ImportSpec_Path 120 IncDecStmt_X 121 IndexExpr_Index 122 IndexExpr_X 123 IndexListExpr_Indices 124 IndexListExpr_X 125 InterfaceType_Methods 126 KeyValueExpr_Key 127 KeyValueExpr_Value 128 LabeledStmt_Label 129 LabeledStmt_Stmt 130 MapType_Key 131 MapType_Value 132 ParenExpr_X 133 RangeStmt_Body 134 RangeStmt_Key 135 RangeStmt_Value 136 RangeStmt_X 137 ReturnStmt_Results 138 SelectStmt_Body 139 SelectorExpr_Sel 140 SelectorExpr_X 141 SendStmt_Chan 142 SendStmt_Value 143 SliceExpr_High 144 SliceExpr_Low 145 SliceExpr_Max 146 SliceExpr_X 147 StarExpr_X 148 StructType_Fields 149 SwitchStmt_Body 150 SwitchStmt_Init 151 SwitchStmt_Tag 152 TypeAssertExpr_Type 153 TypeAssertExpr_X 154 TypeSpec_Comment 155 TypeSpec_Doc 156 TypeSpec_Name 157 TypeSpec_Type 158 TypeSpec_TypeParams 159 TypeSwitchStmt_Assign 160 TypeSwitchStmt_Body 161 TypeSwitchStmt_Init 162 UnaryExpr_X 163 ValueSpec_Comment 164 ValueSpec_Doc 165 ValueSpec_Names 166 ValueSpec_Type 167 ValueSpec_Values 168 169 maxKind 170 ) 171 172 // Assert that the encoding fits in 7 bits, 173 // as the inspector relies on this. 174 // (We are currently at 104.) 175 var _ = [1 << 7]struct{}{}[maxKind] 176 177 type fieldInfo struct { 178 nodeType reflect.Type // pointer-to-struct type of ast.Node implementation 179 name string 180 index int 181 fieldType reflect.Type 182 } 183 184 func info[N ast.Node](fieldName string) fieldInfo { 185 nodePtrType := reflect.TypeFor[N]() 186 f, ok := nodePtrType.Elem().FieldByName(fieldName) 187 if !ok { 188 panic(fieldName) 189 } 190 return fieldInfo{nodePtrType, fieldName, f.Index[0], f.Type} 191 } 192 193 var fieldInfos = [...]fieldInfo{ 194 Invalid: {}, 195 ArrayType_Elt: info[*ast.ArrayType]("Elt"), 196 ArrayType_Len: info[*ast.ArrayType]("Len"), 197 AssignStmt_Lhs: info[*ast.AssignStmt]("Lhs"), 198 AssignStmt_Rhs: info[*ast.AssignStmt]("Rhs"), 199 BinaryExpr_X: info[*ast.BinaryExpr]("X"), 200 BinaryExpr_Y: info[*ast.BinaryExpr]("Y"), 201 BlockStmt_List: info[*ast.BlockStmt]("List"), 202 BranchStmt_Label: info[*ast.BranchStmt]("Label"), 203 CallExpr_Args: info[*ast.CallExpr]("Args"), 204 CallExpr_Fun: info[*ast.CallExpr]("Fun"), 205 CaseClause_Body: info[*ast.CaseClause]("Body"), 206 CaseClause_List: info[*ast.CaseClause]("List"), 207 ChanType_Value: info[*ast.ChanType]("Value"), 208 CommClause_Body: info[*ast.CommClause]("Body"), 209 CommClause_Comm: info[*ast.CommClause]("Comm"), 210 CommentGroup_List: info[*ast.CommentGroup]("List"), 211 CompositeLit_Elts: info[*ast.CompositeLit]("Elts"), 212 CompositeLit_Type: info[*ast.CompositeLit]("Type"), 213 DeclStmt_Decl: info[*ast.DeclStmt]("Decl"), 214 DeferStmt_Call: info[*ast.DeferStmt]("Call"), 215 Ellipsis_Elt: info[*ast.Ellipsis]("Elt"), 216 ExprStmt_X: info[*ast.ExprStmt]("X"), 217 FieldList_List: info[*ast.FieldList]("List"), 218 Field_Comment: info[*ast.Field]("Comment"), 219 Field_Doc: info[*ast.Field]("Doc"), 220 Field_Names: info[*ast.Field]("Names"), 221 Field_Tag: info[*ast.Field]("Tag"), 222 Field_Type: info[*ast.Field]("Type"), 223 File_Decls: info[*ast.File]("Decls"), 224 File_Doc: info[*ast.File]("Doc"), 225 File_Name: info[*ast.File]("Name"), 226 ForStmt_Body: info[*ast.ForStmt]("Body"), 227 ForStmt_Cond: info[*ast.ForStmt]("Cond"), 228 ForStmt_Init: info[*ast.ForStmt]("Init"), 229 ForStmt_Post: info[*ast.ForStmt]("Post"), 230 FuncDecl_Body: info[*ast.FuncDecl]("Body"), 231 FuncDecl_Doc: info[*ast.FuncDecl]("Doc"), 232 FuncDecl_Name: info[*ast.FuncDecl]("Name"), 233 FuncDecl_Recv: info[*ast.FuncDecl]("Recv"), 234 FuncDecl_Type: info[*ast.FuncDecl]("Type"), 235 FuncLit_Body: info[*ast.FuncLit]("Body"), 236 FuncLit_Type: info[*ast.FuncLit]("Type"), 237 FuncType_Params: info[*ast.FuncType]("Params"), 238 FuncType_Results: info[*ast.FuncType]("Results"), 239 FuncType_TypeParams: info[*ast.FuncType]("TypeParams"), 240 GenDecl_Doc: info[*ast.GenDecl]("Doc"), 241 GenDecl_Specs: info[*ast.GenDecl]("Specs"), 242 GoStmt_Call: info[*ast.GoStmt]("Call"), 243 IfStmt_Body: info[*ast.IfStmt]("Body"), 244 IfStmt_Cond: info[*ast.IfStmt]("Cond"), 245 IfStmt_Else: info[*ast.IfStmt]("Else"), 246 IfStmt_Init: info[*ast.IfStmt]("Init"), 247 ImportSpec_Comment: info[*ast.ImportSpec]("Comment"), 248 ImportSpec_Doc: info[*ast.ImportSpec]("Doc"), 249 ImportSpec_Name: info[*ast.ImportSpec]("Name"), 250 ImportSpec_Path: info[*ast.ImportSpec]("Path"), 251 IncDecStmt_X: info[*ast.IncDecStmt]("X"), 252 IndexExpr_Index: info[*ast.IndexExpr]("Index"), 253 IndexExpr_X: info[*ast.IndexExpr]("X"), 254 IndexListExpr_Indices: info[*ast.IndexListExpr]("Indices"), 255 IndexListExpr_X: info[*ast.IndexListExpr]("X"), 256 InterfaceType_Methods: info[*ast.InterfaceType]("Methods"), 257 KeyValueExpr_Key: info[*ast.KeyValueExpr]("Key"), 258 KeyValueExpr_Value: info[*ast.KeyValueExpr]("Value"), 259 LabeledStmt_Label: info[*ast.LabeledStmt]("Label"), 260 LabeledStmt_Stmt: info[*ast.LabeledStmt]("Stmt"), 261 MapType_Key: info[*ast.MapType]("Key"), 262 MapType_Value: info[*ast.MapType]("Value"), 263 ParenExpr_X: info[*ast.ParenExpr]("X"), 264 RangeStmt_Body: info[*ast.RangeStmt]("Body"), 265 RangeStmt_Key: info[*ast.RangeStmt]("Key"), 266 RangeStmt_Value: info[*ast.RangeStmt]("Value"), 267 RangeStmt_X: info[*ast.RangeStmt]("X"), 268 ReturnStmt_Results: info[*ast.ReturnStmt]("Results"), 269 SelectStmt_Body: info[*ast.SelectStmt]("Body"), 270 SelectorExpr_Sel: info[*ast.SelectorExpr]("Sel"), 271 SelectorExpr_X: info[*ast.SelectorExpr]("X"), 272 SendStmt_Chan: info[*ast.SendStmt]("Chan"), 273 SendStmt_Value: info[*ast.SendStmt]("Value"), 274 SliceExpr_High: info[*ast.SliceExpr]("High"), 275 SliceExpr_Low: info[*ast.SliceExpr]("Low"), 276 SliceExpr_Max: info[*ast.SliceExpr]("Max"), 277 SliceExpr_X: info[*ast.SliceExpr]("X"), 278 StarExpr_X: info[*ast.StarExpr]("X"), 279 StructType_Fields: info[*ast.StructType]("Fields"), 280 SwitchStmt_Body: info[*ast.SwitchStmt]("Body"), 281 SwitchStmt_Init: info[*ast.SwitchStmt]("Init"), 282 SwitchStmt_Tag: info[*ast.SwitchStmt]("Tag"), 283 TypeAssertExpr_Type: info[*ast.TypeAssertExpr]("Type"), 284 TypeAssertExpr_X: info[*ast.TypeAssertExpr]("X"), 285 TypeSpec_Comment: info[*ast.TypeSpec]("Comment"), 286 TypeSpec_Doc: info[*ast.TypeSpec]("Doc"), 287 TypeSpec_Name: info[*ast.TypeSpec]("Name"), 288 TypeSpec_Type: info[*ast.TypeSpec]("Type"), 289 TypeSpec_TypeParams: info[*ast.TypeSpec]("TypeParams"), 290 TypeSwitchStmt_Assign: info[*ast.TypeSwitchStmt]("Assign"), 291 TypeSwitchStmt_Body: info[*ast.TypeSwitchStmt]("Body"), 292 TypeSwitchStmt_Init: info[*ast.TypeSwitchStmt]("Init"), 293 UnaryExpr_X: info[*ast.UnaryExpr]("X"), 294 ValueSpec_Comment: info[*ast.ValueSpec]("Comment"), 295 ValueSpec_Doc: info[*ast.ValueSpec]("Doc"), 296 ValueSpec_Names: info[*ast.ValueSpec]("Names"), 297 ValueSpec_Type: info[*ast.ValueSpec]("Type"), 298 ValueSpec_Values: info[*ast.ValueSpec]("Values"), 299 }