internal/lsp/source: improve completion for "range" and "<-"

Now that we understand object "kind" for builtin generic functions, we
can apply it to a couple more places as well:

// prefer rangeable object kinds
for i := range <> {
}

// prefer channels
<- <>

Change-Id: If9cfba3a06b3abde073a9d397000bb3f3b0e9853
Reviewed-on: https://go-review.googlesource.com/c/tools/+/214678
Run-TryBot: Muir Manders <muir@mnd.rs>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Rebecca Stambler <rstambler@golang.org>
diff --git a/internal/lsp/source/completion.go b/internal/lsp/source/completion.go
index 4a08655..62e0f38 100644
--- a/internal/lsp/source/completion.go
+++ b/internal/lsp/source/completion.go
@@ -1290,7 +1290,6 @@
 				}
 				if tv, ok := c.pkg.GetTypesInfo().Types[node.Lhs[i]]; ok {
 					inf.objType = tv.Type
-					break Nodes
 				}
 			}
 			return inf
@@ -1298,7 +1297,7 @@
 			if node.Type != nil && c.pos > node.Type.End() {
 				inf.objType = c.pkg.GetTypesInfo().TypeOf(node.Type)
 			}
-			break Nodes
+			return inf
 		case *ast.CallExpr:
 			// Only consider CallExpr args if position falls between parens.
 			if node.Lparen <= c.pos && c.pos <= node.Rparen {
@@ -1387,7 +1386,6 @@
 				if resultIdx := indexExprAtPos(c.pos, node.Results); resultIdx < len(node.Results) {
 					if resultIdx < sig.Results().Len() {
 						inf.objType = sig.Results().At(resultIdx).Type()
-						break Nodes
 					}
 				}
 			}
@@ -1396,7 +1394,6 @@
 			if swtch, ok := findSwitchStmt(c.path[i+1:], c.pos, node).(*ast.SwitchStmt); ok {
 				if tv, ok := c.pkg.GetTypesInfo().Types[swtch.Tag]; ok {
 					inf.objType = tv.Type
-					break Nodes
 				}
 			}
 			return inf
@@ -1404,7 +1401,6 @@
 			// Make sure position falls within the brackets (e.g. "foo[a:<>]").
 			if node.Lbrack < c.pos && c.pos <= node.Rbrack {
 				inf.objType = types.Typ[types.Int]
-				break Nodes
 			}
 			return inf
 		case *ast.IndexExpr:
@@ -1416,10 +1412,7 @@
 						inf.objType = t.Key()
 					case *types.Slice, *types.Array:
 						inf.objType = types.Typ[types.Int]
-					default:
-						return inf
 					}
-					break Nodes
 				}
 			}
 			return inf
@@ -1429,11 +1422,18 @@
 				if tv, ok := c.pkg.GetTypesInfo().Types[node.Chan]; ok {
 					if ch, ok := tv.Type.Underlying().(*types.Chan); ok {
 						inf.objType = ch.Elem()
-						break Nodes
 					}
 				}
 			}
 			return inf
+		case *ast.RangeStmt:
+			if nodeContains(node.X, c.pos) {
+				inf.objKind |= kindSlice | kindArray | kindMap | kindString
+				if node.Value == nil {
+					inf.objKind |= kindChan
+				}
+			}
+			return inf
 		case *ast.StarExpr:
 			inf.modifiers = append(inf.modifiers, typeModifier{mod: star})
 		case *ast.UnaryExpr:
@@ -1442,6 +1442,7 @@
 				inf.modifiers = append(inf.modifiers, typeModifier{mod: address})
 			case token.ARROW:
 				inf.modifiers = append(inf.modifiers, typeModifier{mod: chanRead})
+				inf.objKind |= kindChan
 			}
 		default:
 			if breaksExpectedTypeInference(node) {
diff --git a/internal/lsp/testdata/builtins/builtin_args.go b/internal/lsp/testdata/builtins/builtin_args.go
index 9652b0b..040d7e3 100644
--- a/internal/lsp/testdata/builtins/builtin_args.go
+++ b/internal/lsp/testdata/builtins/builtin_args.go
@@ -2,26 +2,26 @@
 
 func _() {
 	var (
-		slice_    []int          //@item(builtinSlice, "slice_", "[]int", "var")
-		map_      map[string]int //@item(builtinMap, "map_", "map[string]int", "var")
-		string_   string         //@item(builtinString, "string_", "string", "var")
-		array_    [0]int         //@item(builtinArray, "array_", "[0]int", "var")
-		arrayPtr_ *[0]int        //@item(builtinArrayPtr, "arrayPtr_", "*[0]int", "var")
-		chan_     chan int       //@item(builtinChan, "chan_", "chan int", "var")
-		ptr_      *int           //@item(builtinPtr, "ptr_", "*int", "var")
-		int_      int            //@item(builtinInt, "int_", "int", "var")
+		aSlice    []int          //@item(builtinSlice, "aSlice", "[]int", "var")
+		aMap      map[string]int //@item(builtinMap, "aMap", "map[string]int", "var")
+		aString   string         //@item(builtinString, "aString", "string", "var")
+		aArray    [0]int         //@item(builtinArray, "aArray", "[0]int", "var")
+		aArrayPtr *[0]int        //@item(builtinArrayPtr, "aArrayPtr", "*[0]int", "var")
+		aChan     chan int       //@item(builtinChan, "aChan", "chan int", "var")
+		aPtr      *int           //@item(builtinPtr, "aPtr", "*int", "var")
+		aInt      int            //@item(builtinInt, "aInt", "int", "var")
 	)
 
 	close() //@rank(")", builtinChan, builtinSlice)
 
 	append() //@rank(")", builtinSlice, builtinChan)
 
-	copy()          //@rank(")", builtinSlice, builtinChan)
-	copy(slice_, s) //@rank(")", builtinSlice, builtinString)
-	copy(s, slice_) //@rank(",", builtinSlice, builtinString)
+	copy()           //@rank(")", builtinSlice, builtinChan)
+	copy(aSlice, aS) //@rank(")", builtinSlice, builtinString)
+	copy(aS, aSlice) //@rank(",", builtinSlice, builtinString)
 
-	delete()        //@rank(")", builtinMap, builtinChan)
-	delete(map_, s) //@rank(")", builtinString, builtinSlice)
+	delete()         //@rank(")", builtinMap, builtinChan)
+	delete(aMap, aS) //@rank(")", builtinString, builtinSlice)
 
 	len() //@rank(")", builtinSlice, builtinInt),rank(")", builtinMap, builtinInt),rank(")", builtinString, builtinInt),rank(")", builtinArray, builtinInt),rank(")", builtinArrayPtr, builtinPtr),rank(")", builtinChan, builtinInt)
 
@@ -34,4 +34,12 @@
 	type myStruct struct{}  //@item(builtinStructType, "myStruct", "struct{...}", "struct")
 	new()                   //@rank(")", builtinStructType, builtinInt)
 	var _ *myStruct = new() //@rank(")", builtinStructType, int)
+
+	for k := range a { //@rank(" {", builtinSlice, builtinInt),rank(" {", builtinString, builtinInt),rank(" {", builtinChan, builtinInt),rank(" {", builtinArray, builtinInt),rank(" {", builtinArrayPtr, builtinInt),rank(" {", builtinMap, builtinInt),
+	}
+
+	for k, v := range a { //@rank(" {", builtinSlice, builtinChan)
+	}
+
+	<-a //@rank(" //", builtinChan, builtinInt)
 }
diff --git a/internal/lsp/testdata/summary.txt.golden b/internal/lsp/testdata/summary.txt.golden
index 4c60c56..ee564e3 100644
--- a/internal/lsp/testdata/summary.txt.golden
+++ b/internal/lsp/testdata/summary.txt.golden
@@ -4,7 +4,7 @@
 UnimportedCompletionsCount = 9
 DeepCompletionsCount = 5
 FuzzyCompletionsCount = 8
-RankedCompletionsCount = 55
+RankedCompletionsCount = 63
 CaseSensitiveCompletionsCount = 4
 DiagnosticsCount = 35
 FoldingRangesCount = 2