Source file src/cmd/vendor/golang.org/x/tools/internal/astutil/purge.go

     1  // Copyright 2023 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 astutil provides various AST utility functions for gopls.
     6  package astutil
     7  
     8  import (
     9  	"bytes"
    10  	"go/scanner"
    11  	"go/token"
    12  )
    13  
    14  // PurgeFuncBodies returns a copy of src in which the contents of each
    15  // outermost {...} region except struct and interface types have been
    16  // deleted. This reduces the amount of work required to parse the
    17  // top-level declarations.
    18  //
    19  // PurgeFuncBodies does not preserve newlines or position information.
    20  // Also, if the input is invalid, parsing the output of
    21  // PurgeFuncBodies may result in a different tree due to its effects
    22  // on parser error recovery.
    23  func PurgeFuncBodies(src []byte) []byte {
    24  	// Destroy the content of any {...}-bracketed regions that are
    25  	// not immediately preceded by a "struct" or "interface"
    26  	// token.  That includes function bodies, composite literals,
    27  	// switch/select bodies, and all blocks of statements.
    28  	// This will lead to non-void functions that don't have return
    29  	// statements, which of course is a type error, but that's ok.
    30  
    31  	var out bytes.Buffer
    32  	file := token.NewFileSet().AddFile("", -1, len(src))
    33  	var sc scanner.Scanner
    34  	sc.Init(file, src, nil, 0)
    35  	var prev token.Token
    36  	var cursor int         // last consumed src offset
    37  	var braces []token.Pos // stack of unclosed braces or -1 for struct/interface type
    38  	for {
    39  		pos, tok, _ := sc.Scan()
    40  		if tok == token.EOF {
    41  			break
    42  		}
    43  		switch tok {
    44  		case token.COMMENT:
    45  			// TODO(adonovan): opt: skip, to save an estimated 20% of time.
    46  
    47  		case token.LBRACE:
    48  			if prev == token.STRUCT || prev == token.INTERFACE {
    49  				pos = -1
    50  			}
    51  			braces = append(braces, pos)
    52  
    53  		case token.RBRACE:
    54  			if last := len(braces) - 1; last >= 0 {
    55  				top := braces[last]
    56  				braces = braces[:last]
    57  				if top < 0 {
    58  					// struct/interface type: leave alone
    59  				} else if len(braces) == 0 { // toplevel only
    60  					// Delete {...} body.
    61  					start := file.Offset(top)
    62  					end := file.Offset(pos)
    63  					out.Write(src[cursor : start+len("{")])
    64  					cursor = end
    65  				}
    66  			}
    67  		}
    68  		prev = tok
    69  	}
    70  	out.Write(src[cursor:])
    71  	return out.Bytes()
    72  }
    73  

View as plain text