internal/lsp: allow narrower scope for convenience CodeActions

Code actions that apply convenience fixes were filtered by the start
line so it wasn't possible to narrow the scope to a specific range.

This change allows clients to send a specific range (or cursor position)
to filter all fixes where the range doesn't intersect with the provided
range. It also widens the diagnostic returned by fillstruct analysis.

The idea is to provide a way to narrow the scope without breaking
clients that do want to ask for code actions using the entire line.

Updates golang/go#40438

Change-Id: Ifd984a092a4a3bf0b3a2a5426d3e65023ba4eebc
Reviewed-on: https://go-review.googlesource.com/c/tools/+/244519
Run-TryBot: Pontus Leitzler <leitzler@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/analysis/fillstruct/fillstruct.go b/internal/lsp/analysis/fillstruct/fillstruct.go
index 0727ad3..047458a 100644
--- a/internal/lsp/analysis/fillstruct/fillstruct.go
+++ b/internal/lsp/analysis/fillstruct/fillstruct.go
@@ -115,8 +115,8 @@
 		}
 		pass.Report(analysis.Diagnostic{
 			Message: fmt.Sprintf("Fill %s with default values", name),
-			Pos:     expr.Lbrace,
-			End:     expr.Rbrace,
+			Pos:     expr.Pos(),
+			End:     expr.End(),
 		})
 	})
 	return nil, nil
diff --git a/internal/lsp/code_action.go b/internal/lsp/code_action.go
index ade13f9..090567f 100644
--- a/internal/lsp/code_action.go
+++ b/internal/lsp/code_action.go
@@ -364,7 +364,8 @@
 		if d.URI != uri {
 			continue
 		}
-		if d.Range.Start.Line != rng.Start.Line {
+
+		if !protocol.Intersect(d.Range, rng) {
 			continue
 		}
 		action, err := diagnosticToCommandCodeAction(ctx, snapshot, d, nil, protocol.RefactorRewrite)
diff --git a/internal/lsp/protocol/span.go b/internal/lsp/protocol/span.go
index 8363d5c..51f6137 100644
--- a/internal/lsp/protocol/span.go
+++ b/internal/lsp/protocol/span.go
@@ -130,6 +130,14 @@
 	return 0
 }
 
+func Intersect(a, b Range) bool {
+	if a.Start.Line > b.End.Line || a.End.Line < b.Start.Line {
+		return false
+	}
+	return !((a.Start.Line == b.End.Line) && a.Start.Character > b.End.Character ||
+		(a.End.Line == b.Start.Line) && a.End.Character < b.Start.Character)
+}
+
 func (r Range) Format(f fmt.State, _ rune) {
 	fmt.Fprintf(f, "%v:%v-%v:%v", r.Start.Line, r.Start.Character, r.End.Line, r.End.Character)
 }