X-Git-Url: https://git.josue.xyz/?a=blobdiff_plain;f=.config%2Fcoc%2Fextensions%2Fcoc-go-data%2Ftools%2Fpkg%2Fmod%2Fgolang.org%2Fx%2Ftools%40v0.0.0-20201105173854-bc9fc8d8c4bc%2Finternal%2Flsp%2Fcache%2Fanalysis.go;fp=.config%2Fcoc%2Fextensions%2Fcoc-go-data%2Ftools%2Fpkg%2Fmod%2Fgolang.org%2Fx%2Ftools%40v0.0.0-20201105173854-bc9fc8d8c4bc%2Finternal%2Flsp%2Fcache%2Fanalysis.go;h=872f1d23e915264717287bd71605f19c4eee8d8a;hb=4d07c77cf4d78cab8639e13ddc3c22495e585b0b;hp=0000000000000000000000000000000000000000;hpb=b3950616b54221c40a7dab9099bda675007e5b6e;p=dotfiles%2F.git diff --git a/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/internal/lsp/cache/analysis.go b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/internal/lsp/cache/analysis.go new file mode 100644 index 00000000..872f1d23 --- /dev/null +++ b/.config/coc/extensions/coc-go-data/tools/pkg/mod/golang.org/x/tools@v0.0.0-20201105173854-bc9fc8d8c4bc/internal/lsp/cache/analysis.go @@ -0,0 +1,392 @@ +// Copyright 2019 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package cache + +import ( + "context" + "fmt" + "go/ast" + "go/types" + "reflect" + "sort" + "sync" + + "golang.org/x/sync/errgroup" + "golang.org/x/tools/go/analysis" + "golang.org/x/tools/internal/analysisinternal" + "golang.org/x/tools/internal/event" + "golang.org/x/tools/internal/lsp/debug/tag" + "golang.org/x/tools/internal/lsp/source" + "golang.org/x/tools/internal/memoize" + errors "golang.org/x/xerrors" +) + +func (s *snapshot) Analyze(ctx context.Context, id string, analyzers ...*analysis.Analyzer) ([]*source.Error, error) { + var roots []*actionHandle + + for _, a := range analyzers { + ah, err := s.actionHandle(ctx, packageID(id), a) + if err != nil { + return nil, err + } + roots = append(roots, ah) + } + + // Check if the context has been canceled before running the analyses. + if ctx.Err() != nil { + return nil, ctx.Err() + } + + var results []*source.Error + for _, ah := range roots { + diagnostics, _, err := ah.analyze(ctx, s) + if err != nil { + return nil, err + } + results = append(results, diagnostics...) + } + return results, nil +} + +type actionHandleKey string + +// An action represents one unit of analysis work: the application of +// one analysis to one package. Actions form a DAG, both within a +// package (as different analyzers are applied, either in sequence or +// parallel), and across packages (as dependencies are analyzed). +type actionHandle struct { + handle *memoize.Handle + + analyzer *analysis.Analyzer + pkg *pkg +} + +type actionData struct { + diagnostics []*source.Error + result interface{} + objectFacts map[objectFactKey]analysis.Fact + packageFacts map[packageFactKey]analysis.Fact + err error +} + +type objectFactKey struct { + obj types.Object + typ reflect.Type +} + +type packageFactKey struct { + pkg *types.Package + typ reflect.Type +} + +func (s *snapshot) actionHandle(ctx context.Context, id packageID, a *analysis.Analyzer) (*actionHandle, error) { + ph := s.getPackage(id, source.ParseFull) + if ph == nil { + return nil, errors.Errorf("no package for %s", id) + } + act := s.getActionHandle(id, ph.mode, a) + if act != nil { + return act, nil + } + if len(ph.key) == 0 { + return nil, errors.Errorf("no key for package %s", id) + } + pkg, err := ph.check(ctx, s) + if err != nil { + return nil, err + } + act = &actionHandle{ + analyzer: a, + pkg: pkg, + } + var deps []*actionHandle + // Add a dependency on each required analyzers. + for _, req := range a.Requires { + reqActionHandle, err := s.actionHandle(ctx, id, req) + if err != nil { + return nil, err + } + deps = append(deps, reqActionHandle) + } + + // TODO(golang/go#35089): Re-enable this when we doesn't use ParseExported + // mode for dependencies. In the meantime, disable analysis for dependencies, + // since we don't get anything useful out of it. + if false { + // An analysis that consumes/produces facts + // must run on the package's dependencies too. + if len(a.FactTypes) > 0 { + importIDs := make([]string, 0, len(ph.m.deps)) + for _, importID := range ph.m.deps { + importIDs = append(importIDs, string(importID)) + } + sort.Strings(importIDs) // for determinism + for _, importID := range importIDs { + depActionHandle, err := s.actionHandle(ctx, packageID(importID), a) + if err != nil { + return nil, err + } + deps = append(deps, depActionHandle) + } + } + } + + h := s.generation.Bind(buildActionKey(a, ph), func(ctx context.Context, arg memoize.Arg) interface{} { + snapshot := arg.(*snapshot) + // Analyze dependencies first. + results, err := execAll(ctx, snapshot, deps) + if err != nil { + return &actionData{ + err: err, + } + } + return runAnalysis(ctx, snapshot, a, pkg, results) + }, nil) + act.handle = h + + act = s.addActionHandle(act) + return act, nil +} + +func (act *actionHandle) analyze(ctx context.Context, snapshot *snapshot) ([]*source.Error, interface{}, error) { + d, err := act.handle.Get(ctx, snapshot.generation, snapshot) + if err != nil { + return nil, nil, err + } + data, ok := d.(*actionData) + if !ok { + return nil, nil, errors.Errorf("unexpected type for %s:%s", act.pkg.ID(), act.analyzer.Name) + } + if data == nil { + return nil, nil, errors.Errorf("unexpected nil analysis for %s:%s", act.pkg.ID(), act.analyzer.Name) + } + return data.diagnostics, data.result, data.err +} + +func buildActionKey(a *analysis.Analyzer, ph *packageHandle) actionHandleKey { + return actionHandleKey(hashContents([]byte(fmt.Sprintf("%p %s", a, string(ph.key))))) +} + +func (act *actionHandle) String() string { + return fmt.Sprintf("%s@%s", act.analyzer, act.pkg.PkgPath()) +} + +func execAll(ctx context.Context, snapshot *snapshot, actions []*actionHandle) (map[*actionHandle]*actionData, error) { + var mu sync.Mutex + results := make(map[*actionHandle]*actionData) + + g, ctx := errgroup.WithContext(ctx) + for _, act := range actions { + act := act + g.Go(func() error { + v, err := act.handle.Get(ctx, snapshot.generation, snapshot) + if err != nil { + return err + } + data, ok := v.(*actionData) + if !ok { + return errors.Errorf("unexpected type for %s: %T", act, v) + } + + mu.Lock() + defer mu.Unlock() + results[act] = data + + return nil + }) + } + return results, g.Wait() +} + +func runAnalysis(ctx context.Context, snapshot *snapshot, analyzer *analysis.Analyzer, pkg *pkg, deps map[*actionHandle]*actionData) (data *actionData) { + data = &actionData{ + objectFacts: make(map[objectFactKey]analysis.Fact), + packageFacts: make(map[packageFactKey]analysis.Fact), + } + defer func() { + if r := recover(); r != nil { + event.Log(ctx, fmt.Sprintf("analysis panicked: %s", r), tag.Package.Of(pkg.PkgPath())) + data.err = errors.Errorf("analysis %s for package %s panicked: %v", analyzer.Name, pkg.PkgPath(), r) + } + }() + + // Plumb the output values of the dependencies + // into the inputs of this action. Also facts. + inputs := make(map[*analysis.Analyzer]interface{}) + + for depHandle, depData := range deps { + if depHandle.pkg == pkg { + // Same package, different analysis (horizontal edge): + // in-memory outputs of prerequisite analyzers + // become inputs to this analysis pass. + inputs[depHandle.analyzer] = depData.result + } else if depHandle.analyzer == analyzer { // (always true) + // Same analysis, different package (vertical edge): + // serialized facts produced by prerequisite analysis + // become available to this analysis pass. + for key, fact := range depData.objectFacts { + // Filter out facts related to objects + // that are irrelevant downstream + // (equivalently: not in the compiler export data). + if !exportedFrom(key.obj, depHandle.pkg.types) { + continue + } + data.objectFacts[key] = fact + } + for key, fact := range depData.packageFacts { + // TODO: filter out facts that belong to + // packages not mentioned in the export data + // to prevent side channels. + + data.packageFacts[key] = fact + } + } + } + + var syntax []*ast.File + for _, cgf := range pkg.compiledGoFiles { + syntax = append(syntax, cgf.File) + } + + var diagnostics []*analysis.Diagnostic + + // Run the analysis. + pass := &analysis.Pass{ + Analyzer: analyzer, + Fset: snapshot.view.session.cache.fset, + Files: syntax, + Pkg: pkg.GetTypes(), + TypesInfo: pkg.GetTypesInfo(), + TypesSizes: pkg.GetTypesSizes(), + ResultOf: inputs, + Report: func(d analysis.Diagnostic) { + // Prefix the diagnostic category with the analyzer's name. + if d.Category == "" { + d.Category = analyzer.Name + } else { + d.Category = analyzer.Name + "." + d.Category + } + diagnostics = append(diagnostics, &d) + }, + ImportObjectFact: func(obj types.Object, ptr analysis.Fact) bool { + if obj == nil { + panic("nil object") + } + key := objectFactKey{obj, factType(ptr)} + + if v, ok := data.objectFacts[key]; ok { + reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem()) + return true + } + return false + }, + ExportObjectFact: func(obj types.Object, fact analysis.Fact) { + if obj.Pkg() != pkg.types { + panic(fmt.Sprintf("internal error: in analysis %s of package %s: Fact.Set(%s, %T): can't set facts on objects belonging another package", + analyzer, pkg.ID(), obj, fact)) + } + key := objectFactKey{obj, factType(fact)} + data.objectFacts[key] = fact // clobber any existing entry + }, + ImportPackageFact: func(pkg *types.Package, ptr analysis.Fact) bool { + if pkg == nil { + panic("nil package") + } + key := packageFactKey{pkg, factType(ptr)} + if v, ok := data.packageFacts[key]; ok { + reflect.ValueOf(ptr).Elem().Set(reflect.ValueOf(v).Elem()) + return true + } + return false + }, + ExportPackageFact: func(fact analysis.Fact) { + key := packageFactKey{pkg.types, factType(fact)} + data.packageFacts[key] = fact // clobber any existing entry + }, + AllObjectFacts: func() []analysis.ObjectFact { + facts := make([]analysis.ObjectFact, 0, len(data.objectFacts)) + for k := range data.objectFacts { + facts = append(facts, analysis.ObjectFact{Object: k.obj, Fact: data.objectFacts[k]}) + } + return facts + }, + AllPackageFacts: func() []analysis.PackageFact { + facts := make([]analysis.PackageFact, 0, len(data.packageFacts)) + for k := range data.packageFacts { + facts = append(facts, analysis.PackageFact{Package: k.pkg, Fact: data.packageFacts[k]}) + } + return facts + }, + } + analysisinternal.SetTypeErrors(pass, pkg.typeErrors) + + if pkg.IsIllTyped() { + data.err = errors.Errorf("analysis skipped due to errors in package: %v", pkg.GetErrors()) + return data + } + data.result, data.err = pass.Analyzer.Run(pass) + if data.err != nil { + return data + } + + if got, want := reflect.TypeOf(data.result), pass.Analyzer.ResultType; got != want { + data.err = errors.Errorf( + "internal error: on package %s, analyzer %s returned a result of type %v, but declared ResultType %v", + pass.Pkg.Path(), pass.Analyzer, got, want) + return data + } + + // disallow calls after Run + pass.ExportObjectFact = func(obj types.Object, fact analysis.Fact) { + panic(fmt.Sprintf("%s:%s: Pass.ExportObjectFact(%s, %T) called after Run", analyzer.Name, pkg.PkgPath(), obj, fact)) + } + pass.ExportPackageFact = func(fact analysis.Fact) { + panic(fmt.Sprintf("%s:%s: Pass.ExportPackageFact(%T) called after Run", analyzer.Name, pkg.PkgPath(), fact)) + } + + for _, diag := range diagnostics { + srcErr, err := sourceError(ctx, snapshot, pkg, diag) + if err != nil { + event.Error(ctx, "unable to compute analysis error position", err, tag.Category.Of(diag.Category), tag.Package.Of(pkg.ID())) + continue + } + if ctx.Err() != nil { + data.err = ctx.Err() + return data + } + data.diagnostics = append(data.diagnostics, srcErr) + } + return data +} + +// exportedFrom reports whether obj may be visible to a package that imports pkg. +// This includes not just the exported members of pkg, but also unexported +// constants, types, fields, and methods, perhaps belonging to oether packages, +// that find there way into the API. +// This is an overapproximation of the more accurate approach used by +// gc export data, which walks the type graph, but it's much simpler. +// +// TODO(adonovan): do more accurate filtering by walking the type graph. +func exportedFrom(obj types.Object, pkg *types.Package) bool { + switch obj := obj.(type) { + case *types.Func: + return obj.Exported() && obj.Pkg() == pkg || + obj.Type().(*types.Signature).Recv() != nil + case *types.Var: + return obj.Exported() && obj.Pkg() == pkg || + obj.IsField() + case *types.TypeName, *types.Const: + return true + } + return false // Nil, Builtin, Label, or PkgName +} + +func factType(fact analysis.Fact) reflect.Type { + t := reflect.TypeOf(fact) + if t.Kind() != reflect.Ptr { + panic(fmt.Sprintf("invalid Fact type: got %T, want pointer", t)) + } + return t +}