internal/lsp: suggest "fallthrough" only inside switches

Change-Id: I3a6ddbc12e068da151699a1d0377670695dcf5aa
Reviewed-on: https://go-review.googlesource.com/c/tools/+/210358
Run-TryBot: Iskander Sharipov <quasilyte@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/source/completion_keywords.go b/internal/lsp/source/completion_keywords.go
index ef787b7..526de65 100644
--- a/internal/lsp/source/completion_keywords.go
+++ b/internal/lsp/source/completion_keywords.go
@@ -55,14 +55,22 @@
 
 	// Filter out keywords depending on scope
 	// Skip the first one because we want to look at the enclosing scopes
-	for _, n := range c.path[1:] {
+	path := c.path[1:]
+	for i, n := range path {
 		switch node := n.(type) {
 		case *ast.CaseClause:
 			// only recommend "fallthrough" and "break" within the bodies of a case clause
 			if c.pos > node.Colon {
 				valid[BREAK] = stdScore
-				// TODO: "fallthrough" is only valid in switch statements
-				valid[FALLTHROUGH] = stdScore
+				// "fallthrough" is only valid in switch statements.
+				// A case clause is always nested within a block statement in a switch statement,
+				// that block statement is nested within either a TypeSwitchStmt or a SwitchStmt.
+				if i+2 >= len(path) {
+					continue
+				}
+				if _, ok := path[i+2].(*ast.SwitchStmt); ok {
+					valid[FALLTHROUGH] = stdScore
+				}
 			}
 		case *ast.CommClause:
 			if c.pos > node.Colon {
diff --git a/internal/lsp/testdata/keywords/keywords.go b/internal/lsp/testdata/keywords/keywords.go
index ce3bfdc..5fda68d 100644
--- a/internal/lsp/testdata/keywords/keywords.go
+++ b/internal/lsp/testdata/keywords/keywords.go
@@ -17,7 +17,7 @@
 	case int:
 		b //@complete(" //", break)
 	case int32:
-		f //@complete(" //", fallthrough, for)
+		f //@complete(" //", for)
 		d //@complete(" //", default, defer)
 		r //@complete(" //", return)
 		c //@complete(" //", case, const)