github.com/elek/golangci-lint@v1.42.2-0.20211208090441-c05b7fcb3a9a/pkg/golinters/goanalysis/runner_loadingpackage.go (about) 1 package goanalysis 2 3 import ( 4 "fmt" 5 "go/ast" 6 "go/parser" 7 "go/scanner" 8 "go/types" 9 "os" 10 "reflect" 11 "sync" 12 "sync/atomic" 13 14 "github.com/pkg/errors" 15 "golang.org/x/tools/go/gcexportdata" 16 "golang.org/x/tools/go/packages" 17 18 "github.com/elek/golangci-lint/pkg/golinters/goanalysis/load" 19 "github.com/elek/golangci-lint/pkg/logutils" 20 ) 21 22 const unsafePkgName = "unsafe" 23 24 type loadingPackage struct { 25 pkg *packages.Package 26 imports map[string]*loadingPackage 27 isInitial bool 28 log logutils.Log 29 actions []*action // all actions with this package 30 loadGuard *load.Guard 31 dependents int32 // number of depending on it packages 32 analyzeOnce sync.Once 33 decUseMutex sync.Mutex 34 } 35 36 func (lp *loadingPackage) analyzeRecursive(loadMode LoadMode, loadSem chan struct{}) { 37 lp.analyzeOnce.Do(func() { 38 // Load the direct dependencies, in parallel. 39 var wg sync.WaitGroup 40 wg.Add(len(lp.imports)) 41 for _, imp := range lp.imports { 42 go func(imp *loadingPackage) { 43 imp.analyzeRecursive(loadMode, loadSem) 44 wg.Done() 45 }(imp) 46 } 47 wg.Wait() 48 lp.analyze(loadMode, loadSem) 49 }) 50 } 51 52 func (lp *loadingPackage) analyze(loadMode LoadMode, loadSem chan struct{}) { 53 loadSem <- struct{}{} 54 defer func() { 55 <-loadSem 56 }() 57 58 // Save memory on unused more fields. 59 defer lp.decUse(loadMode < LoadModeWholeProgram) 60 61 if err := lp.loadWithFacts(loadMode); err != nil { 62 werr := errors.Wrapf(err, "failed to load package %s", lp.pkg.Name) 63 // Don't need to write error to errCh, it will be extracted and reported on another layer. 64 // Unblock depending actions and propagate error. 65 for _, act := range lp.actions { 66 close(act.analysisDoneCh) 67 act.err = werr 68 } 69 return 70 } 71 72 var actsWg sync.WaitGroup 73 actsWg.Add(len(lp.actions)) 74 for _, act := range lp.actions { 75 go func(act *action) { 76 defer actsWg.Done() 77 78 act.waitUntilDependingAnalyzersWorked() 79 80 act.analyzeSafe() 81 }(act) 82 } 83 actsWg.Wait() 84 } 85 86 func (lp *loadingPackage) loadFromSource(loadMode LoadMode) error { 87 pkg := lp.pkg 88 89 // Many packages have few files, much fewer than there 90 // are CPU cores. Additionally, parsing each individual file is 91 // very fast. A naive parallel implementation of this loop won't 92 // be faster, and tends to be slower due to extra scheduling, 93 // bookkeeping and potentially false sharing of cache lines. 94 pkg.Syntax = make([]*ast.File, 0, len(pkg.CompiledGoFiles)) 95 for _, file := range pkg.CompiledGoFiles { 96 f, err := parser.ParseFile(pkg.Fset, file, nil, parser.ParseComments) 97 if err != nil { 98 pkg.Errors = append(pkg.Errors, lp.convertError(err)...) 99 continue 100 } 101 pkg.Syntax = append(pkg.Syntax, f) 102 } 103 if len(pkg.Errors) != 0 { 104 pkg.IllTyped = true 105 return nil 106 } 107 108 if loadMode == LoadModeSyntax { 109 return nil 110 } 111 112 // Call NewPackage directly with explicit name. 113 // This avoids skew between golist and go/types when the files' 114 // package declarations are inconsistent. 115 // Subtle: we populate all Types fields with an empty Package 116 // before loading export data so that export data processing 117 // never has to create a types.Package for an indirect dependency, 118 // which would then require that such created packages be explicitly 119 // inserted back into the Import graph as a final step after export data loading. 120 pkg.Types = types.NewPackage(pkg.PkgPath, pkg.Name) 121 122 pkg.IllTyped = true 123 124 pkg.TypesInfo = &types.Info{ 125 Types: make(map[ast.Expr]types.TypeAndValue), 126 Defs: make(map[*ast.Ident]types.Object), 127 Uses: make(map[*ast.Ident]types.Object), 128 Implicits: make(map[ast.Node]types.Object), 129 Scopes: make(map[ast.Node]*types.Scope), 130 Selections: make(map[*ast.SelectorExpr]*types.Selection), 131 } 132 133 importer := func(path string) (*types.Package, error) { 134 if path == unsafePkgName { 135 return types.Unsafe, nil 136 } 137 if path == "C" { 138 // go/packages doesn't tell us that cgo preprocessing 139 // failed. When we subsequently try to parse the package, 140 // we'll encounter the raw C import. 141 return nil, errors.New("cgo preprocessing failed") 142 } 143 imp := pkg.Imports[path] 144 if imp == nil { 145 return nil, nil 146 } 147 if len(imp.Errors) > 0 { 148 return nil, imp.Errors[0] 149 } 150 return imp.Types, nil 151 } 152 tc := &types.Config{ 153 Importer: importerFunc(importer), 154 Error: func(err error) { 155 pkg.Errors = append(pkg.Errors, lp.convertError(err)...) 156 }, 157 } 158 _ = types.NewChecker(tc, pkg.Fset, pkg.Types, pkg.TypesInfo).Files(pkg.Syntax) 159 // Don't handle error here: errors are adding by tc.Error function. 160 161 illTyped := len(pkg.Errors) != 0 162 if !illTyped { 163 for _, imp := range lp.imports { 164 if imp.pkg.IllTyped { 165 illTyped = true 166 break 167 } 168 } 169 } 170 pkg.IllTyped = illTyped 171 return nil 172 } 173 174 func (lp *loadingPackage) loadFromExportData() error { 175 pkg := lp.pkg 176 177 // Call NewPackage directly with explicit name. 178 // This avoids skew between golist and go/types when the files' 179 // package declarations are inconsistent. 180 // Subtle: we populate all Types fields with an empty Package 181 // before loading export data so that export data processing 182 // never has to create a types.Package for an indirect dependency, 183 // which would then require that such created packages be explicitly 184 // inserted back into the Import graph as a final step after export data loading. 185 pkg.Types = types.NewPackage(pkg.PkgPath, pkg.Name) 186 187 pkg.IllTyped = true 188 for path, pkg := range pkg.Imports { 189 if pkg.Types == nil { 190 return fmt.Errorf("dependency %q hasn't been loaded yet", path) 191 } 192 } 193 if pkg.ExportFile == "" { 194 return fmt.Errorf("no export data for %q", pkg.ID) 195 } 196 f, err := os.Open(pkg.ExportFile) 197 if err != nil { 198 return err 199 } 200 defer f.Close() 201 202 r, err := gcexportdata.NewReader(f) 203 if err != nil { 204 return err 205 } 206 207 view := make(map[string]*types.Package) // view seen by gcexportdata 208 seen := make(map[*packages.Package]bool) // all visited packages 209 var visit func(pkgs map[string]*packages.Package) 210 visit = func(pkgs map[string]*packages.Package) { 211 for _, pkg := range pkgs { 212 if !seen[pkg] { 213 seen[pkg] = true 214 view[pkg.PkgPath] = pkg.Types 215 visit(pkg.Imports) 216 } 217 } 218 } 219 visit(pkg.Imports) 220 tpkg, err := gcexportdata.Read(r, pkg.Fset, view, pkg.PkgPath) 221 if err != nil { 222 return err 223 } 224 pkg.Types = tpkg 225 pkg.IllTyped = false 226 return nil 227 } 228 229 func (lp *loadingPackage) loadWithFacts(loadMode LoadMode) error { 230 pkg := lp.pkg 231 232 if pkg.PkgPath == unsafePkgName { 233 // Fill in the blanks to avoid surprises. 234 pkg.Syntax = []*ast.File{} 235 if loadMode >= LoadModeTypesInfo { 236 pkg.Types = types.Unsafe 237 pkg.TypesInfo = new(types.Info) 238 } 239 return nil 240 } 241 242 if pkg.TypesInfo != nil { 243 // Already loaded package, e.g. because another not go/analysis linter required types for deps. 244 // Try load cached facts for it. 245 246 for _, act := range lp.actions { 247 if !act.loadCachedFacts() { 248 // Cached facts loading failed: analyze later the action from source. 249 act.needAnalyzeSource = true 250 factsCacheDebugf("Loading of facts for already loaded %s failed, analyze it from source later", act) 251 act.markDepsForAnalyzingSource() 252 } 253 } 254 return nil 255 } 256 257 if lp.isInitial { 258 // No need to load cached facts: the package will be analyzed from source 259 // because it's the initial. 260 return lp.loadFromSource(loadMode) 261 } 262 263 return lp.loadImportedPackageWithFacts(loadMode) 264 } 265 266 func (lp *loadingPackage) loadImportedPackageWithFacts(loadMode LoadMode) error { 267 pkg := lp.pkg 268 269 // Load package from export data 270 if loadMode >= LoadModeTypesInfo { 271 if err := lp.loadFromExportData(); err != nil { 272 // We asked Go to give us up to date export data, yet 273 // we can't load it. There must be something wrong. 274 // 275 // Attempt loading from source. This should fail (because 276 // otherwise there would be export data); we just want to 277 // get the compile errors. If loading from source succeeds 278 // we discard the result, anyway. Otherwise we'll fail 279 // when trying to reload from export data later. 280 281 // Otherwise it panics because uses already existing (from exported data) types. 282 pkg.Types = types.NewPackage(pkg.PkgPath, pkg.Name) 283 if srcErr := lp.loadFromSource(loadMode); srcErr != nil { 284 return srcErr 285 } 286 // Make sure this package can't be imported successfully 287 pkg.Errors = append(pkg.Errors, packages.Error{ 288 Pos: "-", 289 Msg: fmt.Sprintf("could not load export data: %s", err), 290 Kind: packages.ParseError, 291 }) 292 return errors.Wrap(err, "could not load export data") 293 } 294 } 295 296 needLoadFromSource := false 297 for _, act := range lp.actions { 298 if act.loadCachedFacts() { 299 continue 300 } 301 302 // Cached facts loading failed: analyze later the action from source. 303 factsCacheDebugf("Loading of facts for %s failed, analyze it from source later", act) 304 act.needAnalyzeSource = true // can't be set in parallel 305 needLoadFromSource = true 306 307 act.markDepsForAnalyzingSource() 308 } 309 310 if needLoadFromSource { 311 // Cached facts loading failed: analyze later the action from source. To perform 312 // the analysis we need to load the package from source code. 313 314 // Otherwise it panics because uses already existing (from exported data) types. 315 if loadMode >= LoadModeTypesInfo { 316 pkg.Types = types.NewPackage(pkg.PkgPath, pkg.Name) 317 } 318 return lp.loadFromSource(loadMode) 319 } 320 321 return nil 322 } 323 324 func (lp *loadingPackage) decUse(canClearTypes bool) { 325 lp.decUseMutex.Lock() 326 defer lp.decUseMutex.Unlock() 327 328 for _, act := range lp.actions { 329 pass := act.pass 330 if pass == nil { 331 continue 332 } 333 334 pass.Files = nil 335 pass.TypesInfo = nil 336 pass.TypesSizes = nil 337 pass.ResultOf = nil 338 pass.Pkg = nil 339 pass.OtherFiles = nil 340 pass.AllObjectFacts = nil 341 pass.AllPackageFacts = nil 342 pass.ImportObjectFact = nil 343 pass.ExportObjectFact = nil 344 pass.ImportPackageFact = nil 345 pass.ExportPackageFact = nil 346 act.pass = nil 347 act.deps = nil 348 if act.result != nil { 349 if isMemoryDebug { 350 debugf("%s: decUse: nilling act result of size %d bytes", act, sizeOfValueTreeBytes(act.result)) 351 } 352 act.result = nil 353 } 354 } 355 356 lp.pkg.Syntax = nil 357 lp.pkg.TypesInfo = nil 358 lp.pkg.TypesSizes = nil 359 360 // Can't set lp.pkg.Imports to nil because of loadFromExportData.visit. 361 362 dependents := atomic.AddInt32(&lp.dependents, -1) 363 if dependents != 0 { 364 return 365 } 366 367 if canClearTypes { 368 // canClearTypes is set to true if we can discard type 369 // information after the package and its dependents have been 370 // processed. This is the case when no whole program checkers (unused) are 371 // being run. 372 lp.pkg.Types = nil 373 } 374 lp.pkg = nil 375 376 for _, imp := range lp.imports { 377 imp.decUse(canClearTypes) 378 } 379 lp.imports = nil 380 381 for _, act := range lp.actions { 382 if !lp.isInitial { 383 act.pkg = nil 384 } 385 act.packageFacts = nil 386 act.objectFacts = nil 387 } 388 lp.actions = nil 389 } 390 391 func (lp *loadingPackage) convertError(err error) []packages.Error { 392 var errs []packages.Error 393 // taken from go/packages 394 switch err := err.(type) { 395 case packages.Error: 396 // from driver 397 errs = append(errs, err) 398 399 case *os.PathError: 400 // from parser 401 errs = append(errs, packages.Error{ 402 Pos: err.Path + ":1", 403 Msg: err.Err.Error(), 404 Kind: packages.ParseError, 405 }) 406 407 case scanner.ErrorList: 408 // from parser 409 for _, err := range err { 410 errs = append(errs, packages.Error{ 411 Pos: err.Pos.String(), 412 Msg: err.Msg, 413 Kind: packages.ParseError, 414 }) 415 } 416 417 case types.Error: 418 // from type checker 419 errs = append(errs, packages.Error{ 420 Pos: err.Fset.Position(err.Pos).String(), 421 Msg: err.Msg, 422 Kind: packages.TypeError, 423 }) 424 425 default: 426 // unexpected impoverished error from parser? 427 errs = append(errs, packages.Error{ 428 Pos: "-", 429 Msg: err.Error(), 430 Kind: packages.UnknownError, 431 }) 432 433 // If you see this error message, please file a bug. 434 lp.log.Warnf("Internal error: error %q (%T) without position", err, err) 435 } 436 return errs 437 } 438 439 func (lp *loadingPackage) String() string { 440 return fmt.Sprintf("%s@%s", lp.pkg.PkgPath, lp.pkg.Name) 441 } 442 443 type importerFunc func(path string) (*types.Package, error) 444 445 func (f importerFunc) Import(path string) (*types.Package, error) { return f(path) } 446 447 func sizeOfValueTreeBytes(v interface{}) int { 448 return sizeOfReflectValueTreeBytes(reflect.ValueOf(v), map[uintptr]struct{}{}) 449 } 450 451 func sizeOfReflectValueTreeBytes(rv reflect.Value, visitedPtrs map[uintptr]struct{}) int { 452 switch rv.Kind() { 453 case reflect.Ptr: 454 ptrSize := int(rv.Type().Size()) 455 if rv.IsNil() { 456 return ptrSize 457 } 458 ptr := rv.Pointer() 459 if _, ok := visitedPtrs[ptr]; ok { 460 return 0 461 } 462 visitedPtrs[ptr] = struct{}{} 463 return ptrSize + sizeOfReflectValueTreeBytes(rv.Elem(), visitedPtrs) 464 case reflect.Interface: 465 if rv.IsNil() { 466 return 0 467 } 468 return sizeOfReflectValueTreeBytes(rv.Elem(), visitedPtrs) 469 case reflect.Struct: 470 ret := 0 471 for i := 0; i < rv.NumField(); i++ { 472 ret += sizeOfReflectValueTreeBytes(rv.Field(i), visitedPtrs) 473 } 474 return ret 475 case reflect.Slice, reflect.Array, reflect.Chan: 476 return int(rv.Type().Size()) + rv.Cap()*int(rv.Type().Elem().Size()) 477 case reflect.Map: 478 ret := 0 479 for _, key := range rv.MapKeys() { 480 mv := rv.MapIndex(key) 481 ret += sizeOfReflectValueTreeBytes(key, visitedPtrs) 482 ret += sizeOfReflectValueTreeBytes(mv, visitedPtrs) 483 } 484 return ret 485 case reflect.String: 486 return rv.Len() 487 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, 488 reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, 489 reflect.Uintptr, reflect.Bool, reflect.Float32, reflect.Float64, 490 reflect.Complex64, reflect.Complex128, reflect.Func, reflect.UnsafePointer: 491 return int(rv.Type().Size()) 492 case reflect.Invalid: 493 return 0 494 default: 495 panic("unknown rv of type " + fmt.Sprint(rv)) 496 } 497 }