// The position base is used to determine the "relative" position, that is the
// filename and line number relative to the position base. If the base refers
// to the current file, there is no difference between absolute and relative
-// positions. If it refers to a //line pragma, a relative position is relative
-// to that pragma. A position base in turn contains the position at which it
+// positions. If it refers to a //line directive, a relative position is relative
+// to that directive. A position base in turn contains the position at which it
// was introduced in the current file.
type Pos struct {
base *PosBase
// RelFilename returns the filename recorded with the position's base.
func (p Pos) RelFilename() string { return p.base.Filename() }
-// RelLine returns the line number relative to the positions's base.
+// RelLine returns the line number relative to the position's base.
func (p Pos) RelLine() uint { b := p.base; return b.Line() + p.Line() - b.Pos().Line() }
+// RelCol returns the column number relative to the position's base.
+func (p Pos) RelCol() uint {
+ b := p.Base()
+ if p.Line() == b.Pos().Line() {
+ // p on same line as p's base => column is relative to p's base
+ return b.Col() + p.Col() - b.Pos().Col()
+ }
+ return p.Col()
+}
+
// AbsFilename() returns the absolute filename recorded with the position's base.
func (p Pos) AbsFilename() string { return p.base.AbsFilename() }
return format(p.Filename(), p.Line(), p.Col(), showCol)
}
+ // TODO(gri): Column information should be printed if a line
+ // directive explicitly specified a column, per issue #22662.
+
// base is relative
// Print the column only for the original position since the
// relative position's column information may be bogus (it's
// ----------------------------------------------------------------------------
// PosBase
-// A PosBase encodes a filename and base line number.
-// Typically, each file and line pragma introduce a PosBase.
+// A PosBase encodes a filename and base position.
+// Typically, each file and line directive introduce a PosBase.
// A nil *PosBase is a ready to use file PosBase for an unnamed
// file with line numbers starting at 1.
type PosBase struct {
- pos Pos
+ pos Pos // position at which the relative position is (line, col)
filename string // file name used to open source file, for error messages
absFilename string // absolute file name, for PC-Line tables
symFilename string // cached symbol file name, to avoid repeated string concatenation
- line uint // relative line number at pos
+ line, col uint // relative line, column number at pos
inl int // inlining index (see cmd/internal/obj/inl.go)
}
return nil
}
-// NewLinePragmaBase returns a new *PosBase for a line pragma of the form
-// //line filename:line
+// NewLinePragmaBase returns a new *PosBase for a line directive of the form
+// //line filename:line:col
+// /*line filename:line:col*/
// at position pos.
-func NewLinePragmaBase(pos Pos, filename, absFilename string, line uint) *PosBase {
- return &PosBase{pos, filename, absFilename, FileSymPrefix + absFilename, line - 1, -1}
+func NewLinePragmaBase(pos Pos, filename, absFilename string, line, col uint) *PosBase {
+ return &PosBase{pos, filename, absFilename, FileSymPrefix + absFilename, line, col, -1}
}
// NewInliningBase returns a copy of the old PosBase with the given inlining
return 0
}
+// Col returns the column number recorded with the base.
+// If b == nil, the result is 0.
+func (b *PosBase) Col() uint {
+ if b != nil {
+ return b.col
+ }
+ return 0
+}
+
// InliningIndex returns the index into the global inlining
// tree recorded with the base. If b == nil or the base has
// not been inlined, the result is < 0.
func TestPos(t *testing.T) {
f0 := NewFileBase("", "")
f1 := NewFileBase("f1", "f1")
- f2 := NewLinePragmaBase(Pos{}, "f2", "f2", 10)
- f3 := NewLinePragmaBase(MakePos(f1, 10, 1), "f3", "f3", 100)
- f4 := NewLinePragmaBase(MakePos(f3, 10, 1), "f4", "f4", 100)
+ f2 := NewLinePragmaBase(Pos{}, "f2", "f2", 10, 0)
+ f3 := NewLinePragmaBase(MakePos(f1, 10, 1), "f3", "f3", 100, 1)
+ f4 := NewLinePragmaBase(MakePos(f3, 10, 1), "f4", "f4", 100, 1)
+
+ // line directives with non-1 columns
+ f5 := NewLinePragmaBase(MakePos(f1, 5, 5), "f5", "f5", 10, 1)
// line directives from issue #19392
fp := NewFileBase("p.go", "p.go")
- fc := NewLinePragmaBase(MakePos(fp, 3, 0), "c.go", "c.go", 10)
- ft := NewLinePragmaBase(MakePos(fp, 6, 0), "t.go", "t.go", 20)
- fv := NewLinePragmaBase(MakePos(fp, 9, 0), "v.go", "v.go", 30)
- ff := NewLinePragmaBase(MakePos(fp, 12, 0), "f.go", "f.go", 40)
+ fc := NewLinePragmaBase(MakePos(fp, 4, 1), "c.go", "c.go", 10, 1)
+ ft := NewLinePragmaBase(MakePos(fp, 7, 1), "t.go", "t.go", 20, 1)
+ fv := NewLinePragmaBase(MakePos(fp, 10, 1), "v.go", "v.go", 30, 1)
+ ff := NewLinePragmaBase(MakePos(fp, 13, 1), "f.go", "f.go", 40, 1)
for _, test := range []struct {
pos Pos
line, col uint
// relative info
- relFilename string
- relLine uint
+ relFilename string
+ relLine, relCol uint
}{
- {Pos{}, "<unknown line number>", "", 0, 0, "", 0},
- {MakePos(nil, 2, 3), ":2:3", "", 2, 3, "", 2},
- {MakePos(f0, 2, 3), ":2:3", "", 2, 3, "", 2},
- {MakePos(f1, 1, 1), "f1:1:1", "f1", 1, 1, "f1", 1},
- {MakePos(f2, 7, 10), "f2:16[:7:10]", "", 7, 10, "f2", 16},
- {MakePos(f3, 12, 7), "f3:101[f1:12:7]", "f1", 12, 7, "f3", 101},
- {MakePos(f4, 25, 1), "f4:114[f3:25:1]", "f3", 25, 1, "f4", 114},
+ {Pos{}, "<unknown line number>", "", 0, 0, "", 0, 0},
+ {MakePos(nil, 2, 3), ":2:3", "", 2, 3, "", 2, 3},
+ {MakePos(f0, 2, 3), ":2:3", "", 2, 3, "", 2, 3},
+ {MakePos(f1, 1, 1), "f1:1:1", "f1", 1, 1, "f1", 1, 1},
+ {MakePos(f2, 7, 10), "f2:17[:7:10]", "", 7, 10, "f2", 17, 10},
+ {MakePos(f3, 12, 7), "f3:102[f1:12:7]", "f1", 12, 7, "f3", 102, 7},
+ {MakePos(f4, 25, 1), "f4:115[f3:25:1]", "f3", 25, 1, "f4", 115, 1},
+
+ // line directives with non-1 columns
+ {MakePos(f5, 5, 5), "f5:10[f1:5:5]", "f1", 5, 5, "f5", 10, 1},
+ {MakePos(f5, 5, 10), "f5:10[f1:5:10]", "f1", 5, 10, "f5", 10, 6},
+ {MakePos(f5, 6, 10), "f5:11[f1:6:10]", "f1", 6, 10, "f5", 11, 10},
// positions from issue #19392
- {MakePos(fc, 4, 0), "c.go:10[p.go:4:0]", "p.go", 4, 0, "c.go", 10},
- {MakePos(ft, 7, 0), "t.go:20[p.go:7:0]", "p.go", 7, 0, "t.go", 20},
- {MakePos(fv, 10, 0), "v.go:30[p.go:10:0]", "p.go", 10, 0, "v.go", 30},
- {MakePos(ff, 13, 0), "f.go:40[p.go:13:0]", "p.go", 13, 0, "f.go", 40},
+ {MakePos(fc, 4, 1), "c.go:10[p.go:4:1]", "p.go", 4, 1, "c.go", 10, 1},
+ {MakePos(ft, 7, 1), "t.go:20[p.go:7:1]", "p.go", 7, 1, "t.go", 20, 1},
+ {MakePos(fv, 10, 1), "v.go:30[p.go:10:1]", "p.go", 10, 1, "v.go", 30, 1},
+ {MakePos(ff, 13, 1), "f.go:40[p.go:13:1]", "p.go", 13, 1, "f.go", 40, 1},
} {
pos := test.pos
if got := pos.String(); got != test.string {
if got := pos.RelLine(); got != test.relLine {
t.Errorf("%s: got relLine %d; want %d", test.string, got, test.relLine)
}
+ if got := pos.RelCol(); got != test.relCol {
+ t.Errorf("%s: got relCol %d; want %d", test.string, got, test.relCol)
+ }
}
}