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