golang.org/x/tools/gopls@v0.15.3/internal/cache/constraints.go (about) 1 // Copyright 2022 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 cache 6 7 import ( 8 "go/ast" 9 "go/build/constraint" 10 "go/parser" 11 "go/token" 12 ) 13 14 // isStandaloneFile reports whether a file with the given contents should be 15 // considered a 'standalone main file', meaning a package that consists of only 16 // a single file. 17 func isStandaloneFile(src []byte, standaloneTags []string) bool { 18 f, err := parser.ParseFile(token.NewFileSet(), "", src, parser.PackageClauseOnly|parser.ParseComments) 19 if err != nil { 20 return false 21 } 22 23 if f.Name == nil || f.Name.Name != "main" { 24 return false 25 } 26 27 found := false 28 walkConstraints(f, func(c constraint.Expr) bool { 29 if tag, ok := c.(*constraint.TagExpr); ok { 30 for _, t := range standaloneTags { 31 if t == tag.Tag { 32 found = true 33 return false 34 } 35 } 36 } 37 return true 38 }) 39 40 return found 41 } 42 43 // walkConstraints calls f for each constraint expression in the file, until 44 // all constraints are exhausted or f returns false. 45 func walkConstraints(file *ast.File, f func(constraint.Expr) bool) { 46 for _, cg := range file.Comments { 47 // Even with PackageClauseOnly the parser consumes the semicolon following 48 // the package clause, so we must guard against comments that come after 49 // the package name. 50 if cg.Pos() > file.Name.Pos() { 51 continue 52 } 53 for _, comment := range cg.List { 54 if c, err := constraint.Parse(comment.Text); err == nil { 55 if !f(c) { 56 return 57 } 58 } 59 } 60 } 61 }