Skip to content

Commit

Permalink
lsp: remove various go logic/handling
Browse files Browse the repository at this point in the history
Not detailing these changes here because the removed code is generally
speaking useless in the context of CUE, and remained up until this point
as a guide on how to think about things in a CUE context

Signed-off-by: Paul Jolly <[email protected]>
Change-Id: Ie9b2033922f7525e3b23be0bdc791dfe1a02bb1c
Reviewed-on: https://review.gerrithub.io/c/cue-lang/cue/+/1206613
Unity-Result: CUE porcuepine <[email protected]>
TryBot-Result: CUEcueckoo <[email protected]>
Reviewed-by: Daniel Martí <[email protected]>
  • Loading branch information
myitcv committed Jan 3, 2025
1 parent 8210970 commit 9d9632a
Show file tree
Hide file tree
Showing 26 changed files with 24 additions and 6,428 deletions.
149 changes: 5 additions & 144 deletions internal/golangorgx/gopls/cache/check.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"regexp"
"runtime"
"sort"
"strings"
"sync"
"sync/atomic"

Expand All @@ -30,13 +29,10 @@ import (
"cuelang.org/go/internal/golangorgx/tools/event"
"cuelang.org/go/internal/golangorgx/tools/event/tag"
"cuelang.org/go/internal/golangorgx/tools/gcimporter"
"cuelang.org/go/internal/golangorgx/tools/packagesinternal"
"cuelang.org/go/internal/golangorgx/tools/tokeninternal"
"cuelang.org/go/internal/golangorgx/tools/typesinternal"
"cuelang.org/go/internal/golangorgx/tools/versions"
"golang.org/x/mod/module"
"golang.org/x/sync/errgroup"
"golang.org/x/tools/go/ast/astutil"
)

// Various optimizations that should not affect correctness.
Expand Down Expand Up @@ -1115,12 +1111,11 @@ func (b *packageHandleBuilder) buildPackageHandle(ctx context.Context, n *handle
return
}
n.ph = &packageHandle{
mp: n.mp,
loadDiagnostics: computeLoadDiagnostics(ctx, b.s, n.mp),
localInputs: inputs,
localKey: localPackageKey(inputs),
refs: refs,
validated: true,
mp: n.mp,
localInputs: inputs,
localKey: localPackageKey(inputs),
refs: refs,
validated: true,
}
}

Expand Down Expand Up @@ -1634,140 +1629,6 @@ func (b *typeCheckBatch) typesConfig(ctx context.Context, inputs typeCheckInputs
return cfg
}

// depsErrors creates diagnostics for each metadata error (e.g. import cycle).
// These may be attached to import declarations in the transitive source files
// of pkg, or to 'requires' declarations in the package's go.mod file.
//
// TODO(rfindley): move this to load.go
func depsErrors(ctx context.Context, snapshot *Snapshot, mp *metadata.Package) ([]*Diagnostic, error) {
// Select packages that can't be found, and were imported in non-workspace packages.
// Workspace packages already show their own errors.
var relevantErrors []*packagesinternal.PackageError
for _, depsError := range mp.DepsErrors {
// Up to Go 1.15, the missing package was included in the stack, which
// was presumably a bug. We want the next one up.
directImporterIdx := len(depsError.ImportStack) - 1
if directImporterIdx < 0 {
continue
}

directImporter := depsError.ImportStack[directImporterIdx]
if snapshot.isWorkspacePackage(PackageID(directImporter)) {
continue
}
relevantErrors = append(relevantErrors, depsError)
}

// Don't build the import index for nothing.
if len(relevantErrors) == 0 {
return nil, nil
}

// Subsequent checks require Go files.
if len(mp.CompiledGoFiles) == 0 {
return nil, nil
}

// Build an index of all imports in the package.
type fileImport struct {
cgf *ParsedGoFile
imp *ast.ImportSpec
}
allImports := map[string][]fileImport{}
for _, uri := range mp.CompiledGoFiles {
pgf, err := parseGoURI(ctx, snapshot, uri, ParseHeader)
if err != nil {
return nil, err
}
fset := tokeninternal.FileSetFor(pgf.Tok)
// TODO(adonovan): modify Imports() to accept a single token.File (cgf.Tok).
for _, group := range astutil.Imports(fset, pgf.File) {
for _, imp := range group {
if imp.Path == nil {
continue
}
path := strings.Trim(imp.Path.Value, `"`)
allImports[path] = append(allImports[path], fileImport{pgf, imp})
}
}
}

// Apply a diagnostic to any import involved in the error, stopping once
// we reach the workspace.
var errors []*Diagnostic
for _, depErr := range relevantErrors {
for i := len(depErr.ImportStack) - 1; i >= 0; i-- {
item := depErr.ImportStack[i]
if snapshot.isWorkspacePackage(PackageID(item)) {
break
}

for _, imp := range allImports[item] {
rng, err := imp.cgf.NodeRange(imp.imp)
if err != nil {
return nil, err
}
diag := &Diagnostic{
URI: imp.cgf.URI,
Range: rng,
Severity: protocol.SeverityError,
Source: TypeError,
Message: fmt.Sprintf("error while importing %v: %v", item, depErr.Err),
SuggestedFixes: goGetQuickFixes(mp.Module != nil, imp.cgf.URI, item),
}
if !bundleQuickFixes(diag) {
bug.Reportf("failed to bundle fixes for diagnostic %q", diag.Message)
}
errors = append(errors, diag)
}
}
}

modFile, err := nearestModFile(ctx, mp.CompiledGoFiles[0], snapshot)
if err != nil {
return nil, err
}
pm, err := parseModURI(ctx, snapshot, modFile)
if err != nil {
return nil, err
}

// Add a diagnostic to the module that contained the lowest-level import of
// the missing package.
for _, depErr := range relevantErrors {
for i := len(depErr.ImportStack) - 1; i >= 0; i-- {
item := depErr.ImportStack[i]
mp := snapshot.Metadata(PackageID(item))
if mp == nil || mp.Module == nil {
continue
}
modVer := module.Version{Path: mp.Module.Path, Version: mp.Module.Version}
reference := findModuleReference(pm.File, modVer)
if reference == nil {
continue
}
rng, err := pm.Mapper.OffsetRange(reference.Start.Byte, reference.End.Byte)
if err != nil {
return nil, err
}
diag := &Diagnostic{
URI: pm.URI,
Range: rng,
Severity: protocol.SeverityError,
Source: TypeError,
Message: fmt.Sprintf("error while importing %v: %v", item, depErr.Err),
SuggestedFixes: goGetQuickFixes(true, pm.URI, item),
}
if !bundleQuickFixes(diag) {
bug.Reportf("failed to bundle fixes for diagnostic %q", diag.Message)
}
errors = append(errors, diag)
break
}
}
return errors, nil
}

// missingPkgError returns an error message for a missing package that varies
// based on the user's workspace mode.
func missingPkgError(from PackageID, pkgPath string, moduleMode bool) error {
Expand Down
150 changes: 0 additions & 150 deletions internal/golangorgx/gopls/cache/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,13 @@ package cache
// golang.Diagnostic form, and suggesting quick fixes.

import (
"context"
"fmt"
"go/parser"
"go/scanner"
"go/token"
"path/filepath"
"regexp"
"strconv"
"strings"

"cuelang.org/go/internal/golangorgx/gopls/cache/metadata"
"cuelang.org/go/internal/golangorgx/gopls/file"
"cuelang.org/go/internal/golangorgx/gopls/protocol"
"cuelang.org/go/internal/golangorgx/gopls/protocol/command"
"cuelang.org/go/internal/golangorgx/gopls/settings"
Expand All @@ -29,78 +24,6 @@ import (
"golang.org/x/tools/go/packages"
)

// goPackagesErrorDiagnostics translates the given go/packages Error into a
// diagnostic, using the provided metadata and filesource.
//
// The slice of diagnostics may be empty.
func goPackagesErrorDiagnostics(ctx context.Context, e packages.Error, mp *metadata.Package, fs file.Source) ([]*Diagnostic, error) {
if diag, err := parseGoListImportCycleError(ctx, e, mp, fs); err != nil {
return nil, err
} else if diag != nil {
return []*Diagnostic{diag}, nil
}

// Parse error location and attempt to convert to protocol form.
loc, err := func() (protocol.Location, error) {
filename, line, col8 := parseGoListError(e, mp.LoadDir)
uri := protocol.URIFromPath(filename)

fh, err := fs.ReadFile(ctx, uri)
if err != nil {
return protocol.Location{}, err
}
content, err := fh.Content()
if err != nil {
return protocol.Location{}, err
}
mapper := protocol.NewMapper(uri, content)
posn, err := mapper.LineCol8Position(line, col8)
if err != nil {
return protocol.Location{}, err
}
return protocol.Location{
URI: uri,
Range: protocol.Range{
Start: posn,
End: posn,
},
}, nil
}()

// TODO(rfindley): in some cases the go command outputs invalid spans, for
// example (from TestGoListErrors):
//
// package a
// import
//
// In this case, the go command will complain about a.go:2:8, which is after
// the trailing newline but still considered to be on the second line, most
// likely because *token.File lacks information about newline termination.
//
// We could do better here by handling that case.
if err != nil {
// Unable to parse a valid position.
// Apply the error to all files to be safe.
var diags []*Diagnostic
for _, uri := range mp.CompiledGoFiles {
diags = append(diags, &Diagnostic{
URI: uri,
Severity: protocol.SeverityError,
Source: ListError,
Message: e.Msg,
})
}
return diags, nil
}
return []*Diagnostic{{
URI: loc.URI,
Range: loc.Range,
Severity: protocol.SeverityError,
Source: ListError,
Message: e.Msg,
}}, nil
}

func parseErrorDiagnostics(pkg *syntaxPackage, errList scanner.ErrorList) ([]*Diagnostic, error) {
// The first parser error is likely the root cause of the problem.
if errList.Len() <= 0 {
Expand Down Expand Up @@ -383,76 +306,3 @@ func splitFileLineCol(s string) (file string, line, col8 int) {

return s, n2, n1 // "filename:line:col"
}

// parseGoListImportCycleError attempts to parse the given go/packages error as
// an import cycle, returning a diagnostic if successful.
//
// If the error is not detected as an import cycle error, it returns nil, nil.
func parseGoListImportCycleError(ctx context.Context, e packages.Error, mp *metadata.Package, fs file.Source) (*Diagnostic, error) {
re := regexp.MustCompile(`(.*): import stack: \[(.+)\]`)
matches := re.FindStringSubmatch(strings.TrimSpace(e.Msg))
if len(matches) < 3 {
return nil, nil
}
msg := matches[1]
importList := strings.Split(matches[2], " ")
// Since the error is relative to the current package. The import that is causing
// the import cycle error is the second one in the list.
if len(importList) < 2 {
return nil, nil
}
// Imports have quotation marks around them.
circImp := strconv.Quote(importList[1])
for _, uri := range mp.CompiledGoFiles {
pgf, err := parseGoURI(ctx, fs, uri, ParseHeader)
if err != nil {
return nil, err
}
// Search file imports for the import that is causing the import cycle.
for _, imp := range pgf.File.Imports {
if imp.Path.Value == circImp {
rng, err := pgf.NodeMappedRange(imp)
if err != nil {
return nil, nil
}

return &Diagnostic{
URI: pgf.URI,
Range: rng.Range(),
Severity: protocol.SeverityError,
Source: ListError,
Message: msg,
}, nil
}
}
}
return nil, nil
}

// parseGoURI is a helper to parse the Go file at the given URI from the file
// source fs. The resulting syntax and token.File belong to an ephemeral,
// encapsulated FileSet, so this file stands only on its own: it's not suitable
// to use in a list of file of a package, for example.
//
// It returns an error if the file could not be read.
//
// TODO(rfindley): eliminate this helper.
func parseGoURI(ctx context.Context, fs file.Source, uri protocol.DocumentURI, mode parser.Mode) (*ParsedGoFile, error) {
fh, err := fs.ReadFile(ctx, uri)
if err != nil {
return nil, err
}
return parseGoImpl(ctx, token.NewFileSet(), fh, mode, false)
}

// parseModURI is a helper to parse the Mod file at the given URI from the file
// source fs.
//
// It returns an error if the file could not be read.
func parseModURI(ctx context.Context, fs file.Source, uri protocol.DocumentURI) (*ParsedModule, error) {
fh, err := fs.ReadFile(ctx, uri)
if err != nil {
return nil, err
}
return parseModImpl(ctx, fh)
}
Loading

0 comments on commit 9d9632a

Please sign in to comment.