src

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

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 }