1// Copyright 2019 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 5package cache 6 7import ( 8 "go/ast" 9 "go/scanner" 10 "go/types" 11 12 "golang.org/x/mod/module" 13 "golang.org/x/tools/internal/lsp/source" 14 "golang.org/x/tools/internal/span" 15 errors "golang.org/x/xerrors" 16) 17 18// pkg contains the type information needed by the source package. 19type pkg struct { 20 m *metadata 21 mode source.ParseMode 22 goFiles []*source.ParsedGoFile 23 compiledGoFiles []*source.ParsedGoFile 24 diagnostics []*source.Diagnostic 25 imports map[packagePath]*pkg 26 version *module.Version 27 parseErrors []scanner.ErrorList 28 typeErrors []types.Error 29 types *types.Package 30 typesInfo *types.Info 31 typesSizes types.Sizes 32 hasFixedFiles bool 33} 34 35// Declare explicit types for package paths, names, and IDs to ensure that we 36// never use an ID where a path belongs, and vice versa. If we confused these, 37// it would result in confusing errors because package IDs often look like 38// package paths. 39type ( 40 packageID string 41 packagePath string 42 packageName string 43) 44 45// Declare explicit types for files and directories to distinguish between the two. 46type ( 47 fileURI span.URI 48 moduleLoadScope string 49 viewLoadScope span.URI 50) 51 52func (p *pkg) ID() string { 53 return string(p.m.id) 54} 55 56func (p *pkg) Name() string { 57 return string(p.m.name) 58} 59 60func (p *pkg) PkgPath() string { 61 return string(p.m.pkgPath) 62} 63 64func (p *pkg) ParseMode() source.ParseMode { 65 return p.mode 66} 67 68func (p *pkg) CompiledGoFiles() []*source.ParsedGoFile { 69 return p.compiledGoFiles 70} 71 72func (p *pkg) File(uri span.URI) (*source.ParsedGoFile, error) { 73 for _, cgf := range p.compiledGoFiles { 74 if cgf.URI == uri { 75 return cgf, nil 76 } 77 } 78 for _, gf := range p.goFiles { 79 if gf.URI == uri { 80 return gf, nil 81 } 82 } 83 return nil, errors.Errorf("no parsed file for %s in %v", uri, p.m.id) 84} 85 86func (p *pkg) GetSyntax() []*ast.File { 87 var syntax []*ast.File 88 for _, pgf := range p.compiledGoFiles { 89 syntax = append(syntax, pgf.File) 90 } 91 return syntax 92} 93 94func (p *pkg) GetTypes() *types.Package { 95 return p.types 96} 97 98func (p *pkg) GetTypesInfo() *types.Info { 99 return p.typesInfo 100} 101 102func (p *pkg) GetTypesSizes() types.Sizes { 103 return p.typesSizes 104} 105 106func (p *pkg) IsIllTyped() bool { 107 return p.types == nil || p.typesInfo == nil || p.typesSizes == nil 108} 109 110func (p *pkg) ForTest() string { 111 return string(p.m.forTest) 112} 113 114func (p *pkg) GetImport(pkgPath string) (source.Package, error) { 115 if imp := p.imports[packagePath(pkgPath)]; imp != nil { 116 return imp, nil 117 } 118 // Don't return a nil pointer because that still satisfies the interface. 119 return nil, errors.Errorf("no imported package for %s", pkgPath) 120} 121 122func (p *pkg) MissingDependencies() []string { 123 // We don't invalidate metadata for import deletions, so check the package 124 // imports via the *types.Package. Only use metadata if p.types is nil. 125 if p.types == nil { 126 var md []string 127 for i := range p.m.missingDeps { 128 md = append(md, string(i)) 129 } 130 return md 131 } 132 var md []string 133 for _, pkg := range p.types.Imports() { 134 if _, ok := p.m.missingDeps[packagePath(pkg.Path())]; ok { 135 md = append(md, pkg.Path()) 136 } 137 } 138 return md 139} 140 141func (p *pkg) Imports() []source.Package { 142 var result []source.Package 143 for _, imp := range p.imports { 144 result = append(result, imp) 145 } 146 return result 147} 148 149func (p *pkg) Version() *module.Version { 150 return p.version 151} 152 153func (p *pkg) HasListOrParseErrors() bool { 154 return len(p.m.errors) != 0 || len(p.parseErrors) != 0 155} 156 157func (p *pkg) HasTypeErrors() bool { 158 return len(p.typeErrors) != 0 159} 160