GoPLS Viewer

Home|gopls/cmd/guru/pos.go
1// Copyright 2013 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
5package main
6
7// This file defines utilities for working with file positions.
8
9import (
10    "fmt"
11    "go/build"
12    "go/parser"
13    "go/token"
14    "os"
15    "path/filepath"
16    "strconv"
17    "strings"
18
19    "golang.org/x/tools/go/ast/astutil"
20    "golang.org/x/tools/go/buildutil"
21)
22
23// parseOctothorpDecimal returns the numeric value if s matches "#%d",
24// otherwise -1.
25func parseOctothorpDecimal(s stringint {
26    if s != "" && s[0] == '#' {
27        if serr := strconv.ParseInt(s[1:], 1032); err == nil {
28            return int(s)
29        }
30    }
31    return -1
32}
33
34// parsePos parses a string of the form "file:pos" or
35// file:start,end" where pos, start, end match #%d and represent byte
36// offsets, and returns its components.
37//
38// (Numbers without a '#' prefix are reserved for future use,
39// e.g. to indicate line/column positions.)
40func parsePos(pos string) (filename stringstartOffsetendOffset interr error) {
41    if pos == "" {
42        err = fmt.Errorf("no source position specified")
43        return
44    }
45
46    colon := strings.LastIndex(pos":")
47    if colon < 0 {
48        err = fmt.Errorf("bad position syntax %q"pos)
49        return
50    }
51    filenameoffset := pos[:colon], pos[colon+1:]
52    startOffset = -1
53    endOffset = -1
54    if comma := strings.Index(offset","); comma < 0 {
55        // e.g. "foo.go:#123"
56        startOffset = parseOctothorpDecimal(offset)
57        endOffset = startOffset
58    } else {
59        // e.g. "foo.go:#123,#456"
60        startOffset = parseOctothorpDecimal(offset[:comma])
61        endOffset = parseOctothorpDecimal(offset[comma+1:])
62    }
63    if startOffset < 0 || endOffset < 0 {
64        err = fmt.Errorf("invalid offset %q in query position"offset)
65        return
66    }
67    return
68}
69
70// fileOffsetToPos translates the specified file-relative byte offsets
71// into token.Pos form.  It returns an error if the file was not found
72// or the offsets were out of bounds.
73func fileOffsetToPos(file *token.FilestartOffsetendOffset int) (startend token.Poserr error) {
74    // Range check [start..end], inclusive of both end-points.
75
76    if 0 <= startOffset && startOffset <= file.Size() {
77        start = file.Pos(int(startOffset))
78    } else {
79        err = fmt.Errorf("start position is beyond end of file")
80        return
81    }
82
83    if 0 <= endOffset && endOffset <= file.Size() {
84        end = file.Pos(int(endOffset))
85    } else {
86        err = fmt.Errorf("end position is beyond end of file")
87        return
88    }
89
90    return
91}
92
93// sameFile returns true if x and y have the same basename and denote
94// the same file.
95func sameFile(xy stringbool {
96    if filepath.Base(x) == filepath.Base(y) { // (optimisation)
97        if xierr := os.Stat(x); err == nil {
98            if yierr := os.Stat(y); err == nil {
99                return os.SameFile(xiyi)
100            }
101        }
102    }
103    return false
104}
105
106// fastQueryPos parses the position string and returns a queryPos.
107// It parses only a single file and does not run the type checker.
108func fastQueryPos(ctxt *build.Contextpos string) (*queryPoserror) {
109    filenamestartOffsetendOffseterr := parsePos(pos)
110    if err != nil {
111        return nilerr
112    }
113
114    // Parse the file, opening it the file via the build.Context
115    // so that we observe the effects of the -modified flag.
116    fset := token.NewFileSet()
117    cwd_ := os.Getwd()
118    ferr := buildutil.ParseFile(fsetctxtnilcwdfilenameparser.Mode(0))
119    // ParseFile usually returns a partial file along with an error.
120    // Only fail if there is no file.
121    if f == nil {
122        return nilerr
123    }
124    if !f.Pos().IsValid() {
125        return nilfmt.Errorf("%s is not a Go source file"filename)
126    }
127
128    startenderr := fileOffsetToPos(fset.File(f.Pos()), startOffsetendOffset)
129    if err != nil {
130        return nilerr
131    }
132
133    pathexact := astutil.PathEnclosingInterval(fstartend)
134    if path == nil {
135        return nilfmt.Errorf("no syntax here")
136    }
137
138    return &queryPos{fsetstartendpathexactnil}, nil
139}
140
MembersX
parsePos
parsePos.pos
sameFile.BlockStmt.BlockStmt.yi
fastQueryPos.filename
fastQueryPos.startOffset
fastQueryPos.cwd
fastQueryPos.f
parsePos.filename
fileOffsetToPos
sameFile.BlockStmt.xi
fastQueryPos.err
fastQueryPos.path
parsePos.err
fastQueryPos.end
sameFile.BlockStmt.err
parseOctothorpDecimal
parseOctothorpDecimal.BlockStmt.s
parseOctothorpDecimal.BlockStmt.err
parsePos.startOffset
parsePos.endOffset
parsePos.comma
fileOffsetToPos.endOffset
sameFile.BlockStmt.BlockStmt.err
fastQueryPos
fastQueryPos.pos
fastQueryPos.endOffset
fileOffsetToPos.end
fileOffsetToPos.err
sameFile
fastQueryPos.fset
fastQueryPos.exact
parsePos.colon
fileOffsetToPos.startOffset
fileOffsetToPos.start
sameFile.x
fastQueryPos.ctxt
parseOctothorpDecimal.s
fileOffsetToPos.file
fastQueryPos._
fastQueryPos.start
sameFile.y
Members
X