1 // Copyright 2019 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
16 labelNone labelType = iota
22 // wantLabelCompletion returns true if we want (only) label
23 // completions at the position.
24 func (c *completer) wantLabelCompletion() labelType {
25 if _, ok := c.path[0].(*ast.Ident); ok && len(c.path) > 1 {
26 // We want a label if we are an *ast.Ident child of a statement
27 // that accepts a label, e.g. "break Lo<>".
28 return takesLabel(c.path[1])
34 // takesLabel returns the corresponding labelType if n is a statement
35 // that accepts a label, otherwise labelNone.
36 func takesLabel(n ast.Node) labelType {
37 if bs, ok := n.(*ast.BranchStmt); ok {
50 // labels adds completion items for labels defined in the enclosing
52 func (c *completer) labels(lt labelType) {
53 if c.enclosingFunc == nil {
57 addLabel := func(score float64, l *ast.LabeledStmt) {
58 labelObj := c.pkg.GetTypesInfo().ObjectOf(l.Label)
60 c.deepState.enqueue(candidate{obj: labelObj, score: score})
65 case labelBreak, labelContinue:
66 // "break" and "continue" only accept labels from enclosing statements.
68 for i, p := range c.path {
69 switch p := p.(type) {
71 // Labels are function scoped, so don't continue out of functions.
73 case *ast.LabeledStmt:
74 switch p.Stmt.(type) {
75 case *ast.ForStmt, *ast.RangeStmt:
76 // Loop labels can be used for "break" or "continue".
77 addLabel(highScore*math.Pow(.99, float64(i)), p)
78 case *ast.SwitchStmt, *ast.SelectStmt, *ast.TypeSwitchStmt:
79 // Switch and select labels can be used only for "break".
81 addLabel(highScore*math.Pow(.99, float64(i)), p)
87 // Goto accepts any label in the same function not in a nested
88 // block. It also doesn't take labels that would jump across
89 // variable definitions, but ignore that case for now.
90 ast.Inspect(c.enclosingFunc.body, func(n ast.Node) bool {
95 switch n := n.(type) {
96 // Only search into block-like nodes enclosing our "goto".
97 // This prevents us from finding labels in nested blocks.
98 case *ast.BlockStmt, *ast.CommClause, *ast.CaseClause:
99 for _, p := range c.path {
105 case *ast.LabeledStmt:
106 addLabel(highScore, n)