github.com/TBD54566975/ftl@v0.219.0/internal/goast/visitor.go (about)

     1  // Package goast provides a useful visitor for the Go AST.
     2  package goast
     3  
     4  import (
     5  	"fmt"
     6  	. "go/ast" //nolint:all
     7  )
     8  
     9  type VisitorFunc func(node Node, next func() error) error
    10  
    11  // Visit all nodes in the Go AST rooted at node, in depth-first order.
    12  //
    13  // The visitor function can call next() to continue traversal.
    14  //
    15  // Note that this is based on a direct copy of ast.Walk.
    16  func Visit(node Node, v VisitorFunc) error { //nolint:maintidx
    17  	return v(node, func() error {
    18  		// walk children
    19  		// (the order of the cases matches the order
    20  		// of the corresponding node sqltypes in ast.go)
    21  		switch n := node.(type) {
    22  		// Comments and fields
    23  		case *Comment:
    24  			// nothing to do
    25  
    26  		case *CommentGroup:
    27  			for _, c := range n.List {
    28  				if err := Visit(c, v); err != nil {
    29  					return err
    30  				}
    31  			}
    32  
    33  		case *Field:
    34  			if n.Doc != nil {
    35  				if err := Visit(n.Doc, v); err != nil {
    36  					return err
    37  				}
    38  			}
    39  			if err := visitList(n.Names, v); err != nil {
    40  				return err
    41  			}
    42  			if n.Type != nil {
    43  				if err := Visit(n.Type, v); err != nil {
    44  					return err
    45  				}
    46  			}
    47  			if n.Tag != nil {
    48  				if err := Visit(n.Tag, v); err != nil {
    49  					return err
    50  				}
    51  			}
    52  			if n.Comment != nil {
    53  				if err := Visit(n.Comment, v); err != nil {
    54  					return err
    55  				}
    56  			}
    57  
    58  		case *FieldList:
    59  			for _, f := range n.List {
    60  				if err := Visit(f, v); err != nil {
    61  					return err
    62  				}
    63  			}
    64  
    65  		// Expressions
    66  		case *BadExpr, *Ident, *BasicLit:
    67  			// nothing to do
    68  
    69  		case *Ellipsis:
    70  			if n.Elt != nil {
    71  				if err := Visit(n.Elt, v); err != nil {
    72  					return err
    73  				}
    74  			}
    75  
    76  		case *FuncLit:
    77  			if err := Visit(n.Type, v); err != nil {
    78  				return err
    79  			}
    80  			if err := Visit(n.Body, v); err != nil {
    81  				return err
    82  			}
    83  
    84  		case *CompositeLit:
    85  			if n.Type != nil {
    86  				if err := Visit(n.Type, v); err != nil {
    87  					return err
    88  				}
    89  			}
    90  			if err := visitList(n.Elts, v); err != nil {
    91  				return err
    92  			}
    93  
    94  		case *ParenExpr:
    95  			if err := Visit(n.X, v); err != nil {
    96  				return err
    97  			}
    98  
    99  		case *SelectorExpr:
   100  			if err := Visit(n.X, v); err != nil {
   101  				return err
   102  			}
   103  			if err := Visit(n.Sel, v); err != nil {
   104  				return err
   105  			}
   106  
   107  		case *IndexExpr:
   108  			if err := Visit(n.X, v); err != nil {
   109  				return err
   110  			}
   111  			if err := Visit(n.Index, v); err != nil {
   112  				return err
   113  			}
   114  
   115  		case *IndexListExpr:
   116  			if err := Visit(n.X, v); err != nil {
   117  				return err
   118  			}
   119  			for _, index := range n.Indices {
   120  				if err := Visit(index, v); err != nil {
   121  					return err
   122  				}
   123  			}
   124  
   125  		case *SliceExpr:
   126  			if err := Visit(n.X, v); err != nil {
   127  				return err
   128  			}
   129  			if n.Low != nil {
   130  				if err := Visit(n.Low, v); err != nil {
   131  					return err
   132  				}
   133  			}
   134  			if n.High != nil {
   135  				if err := Visit(n.High, v); err != nil {
   136  					return err
   137  				}
   138  			}
   139  			if n.Max != nil {
   140  				if err := Visit(n.Max, v); err != nil {
   141  					return err
   142  				}
   143  			}
   144  
   145  		case *TypeAssertExpr:
   146  			if err := Visit(n.X, v); err != nil {
   147  				return err
   148  			}
   149  			if n.Type != nil {
   150  				if err := Visit(n.Type, v); err != nil {
   151  					return err
   152  				}
   153  			}
   154  
   155  		case *CallExpr:
   156  			if err := Visit(n.Fun, v); err != nil {
   157  				return err
   158  			}
   159  			if err := visitList(n.Args, v); err != nil {
   160  				return err
   161  			}
   162  
   163  		case *StarExpr:
   164  			if err := Visit(n.X, v); err != nil {
   165  				return err
   166  			}
   167  
   168  		case *UnaryExpr:
   169  			if err := Visit(n.X, v); err != nil {
   170  				return err
   171  			}
   172  
   173  		case *BinaryExpr:
   174  			if err := Visit(n.X, v); err != nil {
   175  				return err
   176  			}
   177  			if err := Visit(n.Y, v); err != nil {
   178  				return err
   179  			}
   180  
   181  		case *KeyValueExpr:
   182  			if err := Visit(n.Key, v); err != nil {
   183  				return err
   184  			}
   185  			if err := Visit(n.Value, v); err != nil {
   186  				return err
   187  			}
   188  
   189  		// Types
   190  		case *ArrayType:
   191  			if n.Len != nil {
   192  				if err := Visit(n.Len, v); err != nil {
   193  					return err
   194  				}
   195  			}
   196  			if err := Visit(n.Elt, v); err != nil {
   197  				return err
   198  			}
   199  
   200  		case *StructType:
   201  			if err := Visit(n.Fields, v); err != nil {
   202  				return err
   203  			}
   204  
   205  		case *FuncType:
   206  			if n.TypeParams != nil {
   207  				if err := Visit(n.TypeParams, v); err != nil {
   208  					return err
   209  				}
   210  			}
   211  			if n.Params != nil {
   212  				if err := Visit(n.Params, v); err != nil {
   213  					return err
   214  				}
   215  			}
   216  			if n.Results != nil {
   217  				if err := Visit(n.Results, v); err != nil {
   218  					return err
   219  				}
   220  			}
   221  
   222  		case *InterfaceType:
   223  			if err := Visit(n.Methods, v); err != nil {
   224  				return err
   225  			}
   226  
   227  		case *MapType:
   228  			if err := Visit(n.Key, v); err != nil {
   229  				return err
   230  			}
   231  			if err := Visit(n.Value, v); err != nil {
   232  				return err
   233  			}
   234  
   235  		case *ChanType:
   236  			if err := Visit(n.Value, v); err != nil {
   237  				return err
   238  			}
   239  
   240  		// Statements
   241  		case *BadStmt:
   242  			// nothing to do
   243  
   244  		case *DeclStmt:
   245  			if err := Visit(n.Decl, v); err != nil {
   246  				return err
   247  			}
   248  
   249  		case *EmptyStmt:
   250  			// nothing to do
   251  
   252  		case *LabeledStmt:
   253  			if err := Visit(n.Label, v); err != nil {
   254  				return err
   255  			}
   256  			if err := Visit(n.Stmt, v); err != nil {
   257  				return err
   258  			}
   259  
   260  		case *ExprStmt:
   261  			if err := Visit(n.X, v); err != nil {
   262  				return err
   263  			}
   264  
   265  		case *SendStmt:
   266  			if err := Visit(n.Chan, v); err != nil {
   267  				return err
   268  			}
   269  			if err := Visit(n.Value, v); err != nil {
   270  				return err
   271  			}
   272  
   273  		case *IncDecStmt:
   274  			if err := Visit(n.X, v); err != nil {
   275  				return err
   276  			}
   277  
   278  		case *AssignStmt:
   279  			if err := visitList(n.Lhs, v); err != nil {
   280  				return err
   281  			}
   282  			if err := visitList(n.Rhs, v); err != nil {
   283  				return err
   284  			}
   285  
   286  		case *GoStmt:
   287  			if err := Visit(n.Call, v); err != nil {
   288  				return err
   289  			}
   290  
   291  		case *DeferStmt:
   292  			if err := Visit(n.Call, v); err != nil {
   293  				return err
   294  			}
   295  
   296  		case *ReturnStmt:
   297  			if err := visitList(n.Results, v); err != nil {
   298  				return err
   299  			}
   300  
   301  		case *BranchStmt:
   302  			if n.Label != nil {
   303  				if err := Visit(n.Label, v); err != nil {
   304  					return err
   305  				}
   306  			}
   307  
   308  		case *BlockStmt:
   309  			if err := visitList(n.List, v); err != nil {
   310  				return err
   311  			}
   312  
   313  		case *IfStmt:
   314  			if n.Init != nil {
   315  				if err := Visit(n.Init, v); err != nil {
   316  					return err
   317  				}
   318  			}
   319  			if err := Visit(n.Cond, v); err != nil {
   320  				return err
   321  			}
   322  			if err := Visit(n.Body, v); err != nil {
   323  				return err
   324  			}
   325  			if n.Else != nil {
   326  				if err := Visit(n.Else, v); err != nil {
   327  					return err
   328  				}
   329  			}
   330  
   331  		case *CaseClause:
   332  			if err := visitList(n.List, v); err != nil {
   333  				return err
   334  			}
   335  			if err := visitList(n.Body, v); err != nil {
   336  				return err
   337  			}
   338  
   339  		case *SwitchStmt:
   340  			if n.Init != nil {
   341  				if err := Visit(n.Init, v); err != nil {
   342  					return err
   343  				}
   344  			}
   345  			if n.Tag != nil {
   346  				if err := Visit(n.Tag, v); err != nil {
   347  					return err
   348  				}
   349  			}
   350  			if err := Visit(n.Body, v); err != nil {
   351  				return err
   352  			}
   353  
   354  		case *TypeSwitchStmt:
   355  			if n.Init != nil {
   356  				if err := Visit(n.Init, v); err != nil {
   357  					return err
   358  				}
   359  			}
   360  			if err := Visit(n.Assign, v); err != nil {
   361  				return err
   362  			}
   363  			if err := Visit(n.Body, v); err != nil {
   364  				return err
   365  			}
   366  
   367  		case *CommClause:
   368  			if n.Comm != nil {
   369  				if err := Visit(n.Comm, v); err != nil {
   370  					return err
   371  				}
   372  			}
   373  			if err := visitList(n.Body, v); err != nil {
   374  				return err
   375  			}
   376  
   377  		case *SelectStmt:
   378  			if err := Visit(n.Body, v); err != nil {
   379  				return err
   380  			}
   381  
   382  		case *ForStmt:
   383  			if n.Init != nil {
   384  				if err := Visit(n.Init, v); err != nil {
   385  					return err
   386  				}
   387  			}
   388  			if n.Cond != nil {
   389  				if err := Visit(n.Cond, v); err != nil {
   390  					return err
   391  				}
   392  			}
   393  			if n.Post != nil {
   394  				if err := Visit(n.Post, v); err != nil {
   395  					return err
   396  				}
   397  			}
   398  			if err := Visit(n.Body, v); err != nil {
   399  				return err
   400  			}
   401  
   402  		case *RangeStmt:
   403  			if n.Key != nil {
   404  				if err := Visit(n.Key, v); err != nil {
   405  					return err
   406  				}
   407  			}
   408  			if n.Value != nil {
   409  				if err := Visit(n.Value, v); err != nil {
   410  					return err
   411  				}
   412  			}
   413  			if err := Visit(n.X, v); err != nil {
   414  				return err
   415  			}
   416  			if err := Visit(n.Body, v); err != nil {
   417  				return err
   418  			}
   419  
   420  		// Declarations
   421  		case *ImportSpec:
   422  			if n.Doc != nil {
   423  				if err := Visit(n.Doc, v); err != nil {
   424  					return err
   425  				}
   426  			}
   427  			if n.Name != nil {
   428  				if err := Visit(n.Name, v); err != nil {
   429  					return err
   430  				}
   431  			}
   432  			if err := Visit(n.Path, v); err != nil {
   433  				return err
   434  			}
   435  			if n.Comment != nil {
   436  				if err := Visit(n.Comment, v); err != nil {
   437  					return err
   438  				}
   439  			}
   440  
   441  		case *ValueSpec:
   442  			if n.Doc != nil {
   443  				if err := Visit(n.Doc, v); err != nil {
   444  					return err
   445  				}
   446  			}
   447  			if err := visitList(n.Names, v); err != nil {
   448  				return err
   449  			}
   450  			if n.Type != nil {
   451  				if err := Visit(n.Type, v); err != nil {
   452  					return err
   453  				}
   454  			}
   455  			if err := visitList(n.Values, v); err != nil {
   456  				return err
   457  			}
   458  			if n.Comment != nil {
   459  				if err := Visit(n.Comment, v); err != nil {
   460  					return err
   461  				}
   462  			}
   463  
   464  		case *TypeSpec:
   465  			if n.Doc != nil {
   466  				if err := Visit(n.Doc, v); err != nil {
   467  					return err
   468  				}
   469  			}
   470  			if err := Visit(n.Name, v); err != nil {
   471  				return err
   472  			}
   473  			if n.TypeParams != nil {
   474  				if err := Visit(n.TypeParams, v); err != nil {
   475  					return err
   476  				}
   477  			}
   478  			if err := Visit(n.Type, v); err != nil {
   479  				return err
   480  			}
   481  			if n.Comment != nil {
   482  				if err := Visit(n.Comment, v); err != nil {
   483  					return err
   484  				}
   485  			}
   486  
   487  		case *BadDecl:
   488  			// nothing to do
   489  
   490  		case *GenDecl:
   491  			if n.Doc != nil {
   492  				if err := Visit(n.Doc, v); err != nil {
   493  					return err
   494  				}
   495  			}
   496  			for _, s := range n.Specs {
   497  				if err := Visit(s, v); err != nil {
   498  					return err
   499  				}
   500  			}
   501  
   502  		case *FuncDecl:
   503  			if n.Doc != nil {
   504  				if err := Visit(n.Doc, v); err != nil {
   505  					return err
   506  				}
   507  			}
   508  			if n.Recv != nil {
   509  				if err := Visit(n.Recv, v); err != nil {
   510  					return err
   511  				}
   512  			}
   513  			if err := Visit(n.Name, v); err != nil {
   514  				return err
   515  			}
   516  			if err := Visit(n.Type, v); err != nil {
   517  				return err
   518  			}
   519  			if n.Body != nil {
   520  				if err := Visit(n.Body, v); err != nil {
   521  					return err
   522  				}
   523  			}
   524  
   525  		// Files and packages
   526  		case *File:
   527  			if n.Doc != nil {
   528  				if err := Visit(n.Doc, v); err != nil {
   529  					return err
   530  				}
   531  			}
   532  			if err := Visit(n.Name, v); err != nil {
   533  				return err
   534  			}
   535  			if err := visitList(n.Decls, v); err != nil {
   536  				return err
   537  			}
   538  			// don't walk n.Comments - they have been
   539  			// visited already through the individual
   540  			// nodes
   541  
   542  		case *Package:
   543  			for _, f := range n.Files {
   544  				if err := Visit(f, v); err != nil {
   545  					return err
   546  				}
   547  			}
   548  		default:
   549  			panic(fmt.Sprintf("ast.Walk: unexpected node type %T", n))
   550  		}
   551  
   552  		return nil
   553  	})
   554  }
   555  
   556  func visitList[T Node](list []T, v VisitorFunc) error {
   557  	for _, x := range list {
   558  		if err := Visit(x, v); err != nil {
   559  			return err
   560  		}
   561  	}
   562  	return nil
   563  }