edge.go raw

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