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