Skip to content

Commit 3b8c118

Browse files
committed
resolve comment
1 parent b6dbcdb commit 3b8c118

File tree

3 files changed

+151
-148
lines changed

3 files changed

+151
-148
lines changed

go/analysis/passes/printf/printf.go

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -492,16 +492,16 @@ func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, name string
492492
return
493493
}
494494

495-
maxArgNum := firstArg
495+
maxArgIndex := firstArg
496496
anyIndex := false
497497
// Check formats against args.
498498
for _, directive := range directives {
499499
if (directive.Prec != nil && directive.Prec.Index != -1) ||
500500
(directive.Width != nil && directive.Width.Index != -1) ||
501-
(directive.Verb != nil && directive.Verb.Index != -1) {
501+
(directive.Verb.Index != -1) {
502502
anyIndex = true
503503
}
504-
if !okPrintfArg(pass, call, &maxArgNum, name, directive) { // One error per format is enough.
504+
if !okPrintfArg(pass, call, &maxArgIndex, firstArg, name, directive) { // One error per format is enough.
505505
return
506506
}
507507
if directive.Verb.Verb == 'w' {
@@ -513,16 +513,16 @@ func checkPrintf(pass *analysis.Pass, kind Kind, call *ast.CallExpr, name string
513513
}
514514
}
515515
// Dotdotdot is hard.
516-
if call.Ellipsis.IsValid() && maxArgNum >= len(call.Args)-1 {
516+
if call.Ellipsis.IsValid() && maxArgIndex >= len(call.Args)-1 {
517517
return
518518
}
519519
// If any formats are indexed, extra arguments are ignored.
520520
if anyIndex {
521521
return
522522
}
523523
// There should be no leftover arguments.
524-
if maxArgNum != len(call.Args) {
525-
expect := maxArgNum - firstArg
524+
if maxArgIndex != len(call.Args) {
525+
expect := maxArgIndex - firstArg
526526
numArgs := len(call.Args) - firstArg
527527
pass.ReportRangef(call, "%s call needs %v but has %v", name, count(expect, "arg"), count(numArgs, "arg"))
528528
}
@@ -591,7 +591,7 @@ var printVerbs = []printVerb{
591591
// okPrintfArg compares the FormatDirective to the arguments actually present,
592592
// reporting any discrepancies it can discern. If the final argument is ellipsissed,
593593
// there's little it can do for that.
594-
func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, maxArgNum *int, name string, directive *fmtstr.FormatDirective) (ok bool) {
594+
func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, maxArgIndex *int, firstArg int, name string, directive *fmtstr.FormatDirective) (ok bool) {
595595
verb := directive.Verb.Verb
596596
var v printVerb
597597
found := false
@@ -606,8 +606,8 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, maxArgNum *int, name s
606606
// Could verb's arg implement fmt.Formatter?
607607
// Skip check for the %w verb, which requires an error.
608608
formatter := false
609-
if v.typ != argError && directive.Verb.ArgNum < len(call.Args) {
610-
if tv, ok := pass.TypesInfo.Types[call.Args[directive.Verb.ArgNum]]; ok {
609+
if v.typ != argError && directive.Verb.ArgIndex < len(call.Args) {
610+
if tv, ok := pass.TypesInfo.Types[call.Args[directive.Verb.ArgIndex]]; ok {
611611
formatter = isFormatter(tv.Type)
612612
}
613613
}
@@ -629,22 +629,23 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, maxArgNum *int, name s
629629
}
630630
}
631631
}
632-
var argNums []int
633-
if directive.Width != nil && directive.Width.ArgNum != -1 {
634-
argNums = append(argNums, directive.Width.ArgNum)
632+
633+
var argIndexes []int
634+
// First check for *.
635+
if directive.Width != nil && directive.Width.ArgIndex != -1 {
636+
argIndexes = append(argIndexes, directive.Width.ArgIndex)
635637
}
636-
if directive.Prec != nil && directive.Prec.ArgNum != -1 {
637-
argNums = append(argNums, directive.Prec.ArgNum)
638+
if directive.Prec != nil && directive.Prec.ArgIndex != -1 {
639+
argIndexes = append(argIndexes, directive.Prec.ArgIndex)
638640
}
639-
640-
// Verb is good. If len(argNums)>0, we have something like %.*s and all
641-
// args in argNums must be an integer.
642-
for i := 0; i < len(argNums); i++ {
643-
argNum := argNums[i]
644-
if !argCanBeChecked(pass, call, argNums[i], directive, name) {
641+
// If len(argIndexes)>0, we have something like %.*s and all
642+
// indexes in argIndexes must be an integer.
643+
for i := 0; i < len(argIndexes); i++ {
644+
argIndex := argIndexes[i]
645+
if !argCanBeChecked(pass, call, argIndex, firstArg, directive, name) {
645646
return
646647
}
647-
arg := call.Args[argNum]
648+
arg := call.Args[argIndex]
648649
if reason, ok := matchArgType(pass, argInt, arg); !ok {
649650
details := ""
650651
if reason != "" {
@@ -656,25 +657,28 @@ func okPrintfArg(pass *analysis.Pass, call *ast.CallExpr, maxArgNum *int, name s
656657
}
657658

658659
// Collect to update maxArgNum in one loop.
659-
if directive.Verb != nil && directive.Verb.ArgNum != -1 && verb != '%' {
660-
argNums = append(argNums, directive.Verb.ArgNum)
660+
if directive.Verb.ArgIndex != -1 && verb != '%' {
661+
argIndexes = append(argIndexes, directive.Verb.ArgIndex)
661662
}
662-
for _, n := range argNums {
663-
if n >= *maxArgNum {
664-
*maxArgNum = n + 1
663+
for _, index := range argIndexes {
664+
if index >= *maxArgIndex {
665+
*maxArgIndex = index + 1
665666
}
666667
}
667668

669+
// Special case for '%', go will print "fmt.Printf("%10.2%%dhello", 4)"
670+
// as "%4hello", discard any runes between the two '%'s, and treat the verb '%'
671+
// as an ordinary rune, so early return to skip the type check.
668672
if verb == '%' || formatter {
669673
return true
670674
}
671675

672676
// Now check verb's type.
673-
argNum := argNums[len(argNums)-1]
674-
if !argCanBeChecked(pass, call, argNums[len(argNums)-1], directive, name) {
677+
verbArgIndex := directive.Verb.ArgIndex
678+
if !argCanBeChecked(pass, call, verbArgIndex, firstArg, directive, name) {
675679
return false
676680
}
677-
arg := call.Args[argNum]
681+
arg := call.Args[verbArgIndex]
678682
if isFunctionValue(pass, arg) && verb != 'p' && verb != 'T' {
679683
pass.ReportRangef(call, "%s format %s arg %s is a func value, not called", name, directive.Format, analysisutil.Format(pass.Fset, arg))
680684
return false
@@ -777,24 +781,24 @@ func isFunctionValue(pass *analysis.Pass, e ast.Expr) bool {
777781
// argCanBeChecked reports whether the specified argument is statically present;
778782
// it may be beyond the list of arguments or in a terminal slice... argument, which
779783
// means we can't see it.
780-
func argCanBeChecked(pass *analysis.Pass, call *ast.CallExpr, argNum int, directive *fmtstr.FormatDirective, name string) bool {
781-
if argNum <= 0 {
784+
func argCanBeChecked(pass *analysis.Pass, call *ast.CallExpr, argIndex, firstArg int, directive *fmtstr.FormatDirective, name string) bool {
785+
if argIndex <= 0 {
782786
// Shouldn't happen, so catch it with prejudice.
783-
panic("negative arg num")
787+
panic("negative argIndex")
784788
}
785-
if argNum < len(call.Args)-1 {
789+
if argIndex < len(call.Args)-1 {
786790
return true // Always OK.
787791
}
788792
if call.Ellipsis.IsValid() {
789793
return false // We just can't tell; there could be many more arguments.
790794
}
791-
if argNum < len(call.Args) {
795+
if argIndex < len(call.Args) {
792796
return true
793797
}
794798
// There are bad indexes in the format or there are fewer arguments than the format needs.
795799
// This is the argument number relative to the format: Printf("%s", "hi") will give 1 for the "hi".
796-
arg := argNum - directive.FirstArg + 1 // People think of arguments as 1-indexed.
797-
pass.ReportRangef(call, "%s format %s reads arg #%d, but call has %v", name, directive.Format, arg, count(len(call.Args)-directive.FirstArg, "arg"))
800+
arg := argIndex - firstArg + 1 // People think of arguments as 1-indexed.
801+
pass.ReportRangef(call, "%s format %s reads arg #%d, but call has %v", name, directive.Format, arg, count(len(call.Args)-firstArg, "arg"))
798802
return false
799803
}
800804

gopls/internal/golang/highlight.go

Lines changed: 21 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func Highlight(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, po
5151
}
5252
}
5353
}
54-
result, err := highlightPath(path, pgf.File, pkg.TypesInfo(), pos)
54+
result, err := highlightPath(pkg.TypesInfo(), path, pos)
5555
if err != nil {
5656
return nil, err
5757
}
@@ -71,7 +71,7 @@ func Highlight(ctx context.Context, snapshot *cache.Snapshot, fh file.Handle, po
7171

7272
// highlightPath returns ranges to highlight for the given enclosing path,
7373
// which should be the result of astutil.PathEnclosingInterval.
74-
func highlightPath(path []ast.Node, file *ast.File, info *types.Info, pos token.Pos) (map[posRange]protocol.DocumentHighlightKind, error) {
74+
func highlightPath(info *types.Info, path []ast.Node, pos token.Pos) (map[posRange]protocol.DocumentHighlightKind, error) {
7575
result := make(map[posRange]protocol.DocumentHighlightKind)
7676

7777
// Inside a printf-style call, printf("...%v...", arg)?
@@ -88,6 +88,7 @@ func highlightPath(path []ast.Node, file *ast.File, info *types.Info, pos token.
8888
}
8989
}
9090

91+
file := path[len(path)-1].(*ast.File)
9192
switch node := path[0].(type) {
9293
case *ast.BasicLit:
9394
// Import path string literal?
@@ -162,17 +163,17 @@ func highlightPrintf(info *types.Info, call *ast.CallExpr, formatPos token.Pos,
162163
return
163164
}
164165

165-
highlight := func(start, end token.Pos, argNum int) bool {
166+
// highlightPair highlights the directive and its potential argument pair if the cursor is within either range.
167+
highlightPair := func(start, end token.Pos, argIndex int) bool {
166168
var (
167169
rangeStart = formatPos + token.Pos(start) + 1 // add offset for leading '"'
168170
rangeEnd = formatPos + token.Pos(end) + 1 // add offset for leading '"'
169171
arg ast.Expr // may not exist
170172
)
171-
if len(call.Args) > argNum {
172-
arg = call.Args[argNum]
173+
if len(call.Args) > argIndex {
174+
arg = call.Args[argIndex]
173175
}
174176

175-
// Highlight the directive and its potential argument if the cursor is within etheir range.
176177
if (cursorPos >= rangeStart && cursorPos < rangeEnd) || (arg != nil && cursorPos >= arg.Pos() && cursorPos < arg.End()) {
177178
highlightRange(result, rangeStart, rangeEnd, protocol.Write)
178179
if arg != nil {
@@ -192,26 +193,28 @@ func highlightPrintf(info *types.Info, call *ast.CallExpr, formatPos token.Pos,
192193
anyAsterisk := false
193194
for _, directive := range directives {
194195
width, prec, verb := directive.Width, directive.Prec, directive.Verb
195-
if (prec != nil && prec.Kind != fmtstr.Literal) ||
196-
(width != nil && width.Kind != fmtstr.Literal) {
196+
// Try highlight Width if there is a *.
197+
if width != nil && width.ArgIndex != -1 {
197198
anyAsterisk = true
199+
if highlightPair(token.Pos(width.Range.Start), token.Pos(width.Range.End), width.ArgIndex) {
200+
return
201+
}
198202
}
199203

200-
// Try highlight Width.
201-
if width != nil && width.ArgNum != -1 && highlight(token.Pos(width.Range.Start), token.Pos(width.Range.End), width.ArgNum) {
202-
return
203-
}
204-
205-
// Try highlight Prec.
206-
if prec != nil && prec.ArgNum != -1 && highlight(token.Pos(prec.Range.Start), token.Pos(prec.Range.End), prec.ArgNum) {
207-
return
204+
// Try highlight Precision if there is a *.
205+
if prec != nil && prec.ArgIndex != -1 {
206+
anyAsterisk = true
207+
if highlightPair(token.Pos(prec.Range.Start), token.Pos(prec.Range.End), prec.ArgIndex) {
208+
return
209+
}
208210
}
209211

210212
// Try highlight Verb.
211213
if verb.Verb != '%' {
212-
if anyAsterisk && highlight(token.Pos(verb.Range.Start), token.Pos(verb.Range.End), verb.ArgNum) {
214+
// If any * is found inside directive, narrow the highlight range.
215+
if anyAsterisk && highlightPair(token.Pos(verb.Range.Start), token.Pos(verb.Range.End), verb.ArgIndex) {
213216
return
214-
} else if highlight(token.Pos(directive.Range.Start), token.Pos(directive.Range.End), verb.ArgNum) {
217+
} else if highlightPair(token.Pos(directive.Range.Start), token.Pos(directive.Range.End), verb.ArgIndex) {
215218
return
216219
}
217220
}

0 commit comments

Comments
 (0)