From 1bd56024c6204c5d493f13273473cf5b3e0e8194 Mon Sep 17 00:00:00 2001 From: Suzy Mueller Date: Fri, 26 Jul 2019 18:17:04 -0400 Subject: [PATCH] internal/lsp: format files in packages with errors Packages with errors may still contain files that can be formatted. Try to format the source of the files in packages that have errors. This change will still not format files with parse errors. Updates golang/go#31291 Change-Id: Ia5168d7908948d201eac7f2ee28534022a2d4eb0 Reviewed-on: https://go-review.googlesource.com/c/tools/+/187757 Run-TryBot: Suzy Mueller Reviewed-by: Rebecca Stambler --- internal/lsp/source/format.go | 20 ++++++++++++++++++- .../noparse_format/parse_format.go.golden | 9 +++++++++ .../noparse_format/parse_format.go.in | 5 +++++ internal/lsp/tests/tests.go | 2 +- 4 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 internal/lsp/testdata/noparse_format/parse_format.go.golden create mode 100644 internal/lsp/testdata/noparse_format/parse_format.go.in diff --git a/internal/lsp/source/format.go b/internal/lsp/source/format.go index e9f12d2c61..7a52cbcb71 100644 --- a/internal/lsp/source/format.go +++ b/internal/lsp/source/format.go @@ -31,7 +31,15 @@ func Format(ctx context.Context, f GoFile, rng span.Range) ([]TextEdit, error) { } pkg := f.GetPackage(ctx) if hasListErrors(pkg.GetErrors()) || hasParseErrors(pkg.GetErrors()) { - return nil, fmt.Errorf("%s has parse errors, not formatting", f.URI()) + // Even if this package has list or parse errors, this file may not + // have any parse errors and can still be formatted. Using format.Node + // on an ast with errors may result in code being added or removed. + // Attempt to format the source of this file instead. + formatted, err := formatSource(ctx, f) + if err != nil { + return nil, err + } + return computeTextEdits(ctx, f, string(formatted)), nil } path, exact := astutil.PathEnclosingInterval(file, rng.Start, rng.End) if !exact || len(path) == 0 { @@ -52,6 +60,16 @@ func Format(ctx context.Context, f GoFile, rng span.Range) ([]TextEdit, error) { return computeTextEdits(ctx, f, buf.String()), nil } +func formatSource(ctx context.Context, file File) ([]byte, error) { + ctx, done := trace.StartSpan(ctx, "source.formatSource") + defer done() + data, _, err := file.Handle(ctx).Read(ctx) + if err != nil { + return nil, err + } + return format.Source(data) +} + // Imports formats a file using the goimports tool. func Imports(ctx context.Context, view View, f GoFile, rng span.Range) ([]TextEdit, error) { ctx, done := trace.StartSpan(ctx, "source.Imports") diff --git a/internal/lsp/testdata/noparse_format/parse_format.go.golden b/internal/lsp/testdata/noparse_format/parse_format.go.golden new file mode 100644 index 0000000000..474ad90bb2 --- /dev/null +++ b/internal/lsp/testdata/noparse_format/parse_format.go.golden @@ -0,0 +1,9 @@ +-- gofmt -- +package noparse_format //@format("package") + +func _() { + f() +} + +-- gofmt-d -- + diff --git a/internal/lsp/testdata/noparse_format/parse_format.go.in b/internal/lsp/testdata/noparse_format/parse_format.go.in new file mode 100644 index 0000000000..4b98cf8d01 --- /dev/null +++ b/internal/lsp/testdata/noparse_format/parse_format.go.in @@ -0,0 +1,5 @@ +package noparse_format //@format("package") + +func _() { +f() +} \ No newline at end of file diff --git a/internal/lsp/tests/tests.go b/internal/lsp/tests/tests.go index 767d817546..d649864ba7 100644 --- a/internal/lsp/tests/tests.go +++ b/internal/lsp/tests/tests.go @@ -29,7 +29,7 @@ const ( ExpectedCompletionsCount = 144 ExpectedCompletionSnippetCount = 15 ExpectedDiagnosticsCount = 17 - ExpectedFormatCount = 5 + ExpectedFormatCount = 6 ExpectedImportCount = 2 ExpectedDefinitionsCount = 38 ExpectedTypeDefinitionsCount = 2