Source file src/cmd/vendor/golang.org/x/tools/internal/astutil/stringlit.go

     1  // Copyright 2025 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.
     4  
     5  package astutil
     6  
     7  import (
     8  	"fmt"
     9  	"go/ast"
    10  	"go/token"
    11  	"strconv"
    12  	"unicode/utf8"
    13  )
    14  
    15  // RangeInStringLiteral calculates the positional range within a string literal
    16  // corresponding to the specified start and end byte offsets within the logical string.
    17  func RangeInStringLiteral(lit *ast.BasicLit, start, end int) (token.Pos, token.Pos, error) {
    18  	startPos, err := PosInStringLiteral(lit, start)
    19  	if err != nil {
    20  		return 0, 0, fmt.Errorf("start: %v", err)
    21  	}
    22  	endPos, err := PosInStringLiteral(lit, end)
    23  	if err != nil {
    24  		return 0, 0, fmt.Errorf("end: %v", err)
    25  	}
    26  	return startPos, endPos, nil
    27  }
    28  
    29  // PosInStringLiteral returns the position within a string literal
    30  // corresponding to the specified byte offset within the logical
    31  // string that it denotes.
    32  func PosInStringLiteral(lit *ast.BasicLit, offset int) (token.Pos, error) {
    33  	raw := lit.Value
    34  
    35  	value, err := strconv.Unquote(raw)
    36  	if err != nil {
    37  		return 0, err
    38  	}
    39  	if !(0 <= offset && offset <= len(value)) {
    40  		return 0, fmt.Errorf("invalid offset")
    41  	}
    42  
    43  	// remove quotes
    44  	quote := raw[0] // '"' or '`'
    45  	raw = raw[1 : len(raw)-1]
    46  
    47  	var (
    48  		i   = 0                // byte index within logical value
    49  		pos = lit.ValuePos + 1 // position within literal
    50  	)
    51  	for raw != "" && i < offset {
    52  		r, _, rest, _ := strconv.UnquoteChar(raw, quote) // can't fail
    53  		sz := len(raw) - len(rest)                       // length of literal char in raw bytes
    54  		pos += token.Pos(sz)
    55  		raw = raw[sz:]
    56  		i += utf8.RuneLen(r)
    57  	}
    58  	return pos, nil
    59  }
    60  

View as plain text