Skip to content

Commit 96dd7b5

Browse files
committed
fix: get accurate symbol offset
1 parent a429cb3 commit 96dd7b5

File tree

9 files changed

+111
-59
lines changed

9 files changed

+111
-59
lines changed

src/compress/golang/plugin/parse/ctx.go

Lines changed: 57 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,22 +33,16 @@ var errSysImport = fmt.Errorf("sys import")
3333

3434
// The go file's context. Used to pass information between ast node handlers
3535
type fileContext struct {
36-
repoDir string
37-
filePath string
38-
module *Module
39-
pkgPath PkgPath
40-
bs []byte
41-
fset *token.FileSet
42-
imports *importInfo
43-
pkgTypeInfo *types.Info
44-
deps map[string]*packages.Package
45-
}
46-
47-
func (ctx *fileContext) FileLine(node ast.Node) FileLine {
48-
pos := ctx.fset.Position((node).Pos())
49-
rel, _ := filepath.Rel(ctx.repoDir, pos.Filename)
50-
end := ctx.fset.Position((node).End())
51-
return FileLine{File: rel, Line: pos.Line, StartOffset: pos.Offset, EndOffset: end.Offset}
36+
repoDir string
37+
filePath string
38+
module *Module
39+
pkgPath PkgPath
40+
bs []byte
41+
fset *token.FileSet
42+
imports *importInfo
43+
pkgTypeInfo *types.Info
44+
deps map[string]*packages.Package
45+
collectComment bool
5246
}
5347

5448
func isExternalID(id *Identity, curmod string) bool {
@@ -164,13 +158,56 @@ func (ctx *fileContext) GetMod(impt string) (string, error) {
164158
return "", fmt.Errorf("not found mod: %s", impt)
165159
}
166160

161+
func (ctx *fileContext) FileLine(node ast.Node) FileLine {
162+
pos := ctx.fset.Position((node).Pos())
163+
rel, _ := filepath.Rel(ctx.repoDir, pos.Filename)
164+
end := ctx.fset.Position((node).End())
165+
ret := FileLine{File: rel, Line: pos.Line, StartOffset: pos.Offset, EndOffset: end.Offset}
166+
if _, ok := node.(*ast.TypeSpec); ok {
167+
// NOTICE: type spec is not the start of the type definition
168+
// so we need to adjust the offset = len("type ")
169+
ret.StartOffset -= 5
170+
}
171+
if ctx.collectComment {
172+
fset := ctx.fset
173+
switch v := node.(type) {
174+
case *ast.Field:
175+
if v.Doc != nil {
176+
ret.StartOffset = fset.Position(v.Doc.Pos()).Offset
177+
}
178+
case *ast.GenDecl:
179+
if v.Doc != nil {
180+
ret.StartOffset = fset.Position(v.Doc.Pos()).Offset
181+
}
182+
case *ast.TypeSpec:
183+
if v.Doc != nil {
184+
ret.StartOffset = fset.Position(v.Doc.Pos()).Offset
185+
}
186+
case *ast.ValueSpec:
187+
if v.Doc != nil {
188+
ret.StartOffset = fset.Position(v.Doc.Pos()).Offset
189+
}
190+
case *ast.FuncDecl:
191+
if v.Doc != nil {
192+
ret.StartOffset = fset.Position(v.Doc.Pos()).Offset
193+
}
194+
}
195+
}
196+
return ret
197+
}
198+
167199
func (ctx *fileContext) GetRawContent(node ast.Node) []byte {
168-
return GetRawContent(ctx.fset, ctx.bs, node)
200+
return GetRawContent(ctx.fset, ctx.bs, node, ctx.collectComment)
169201
}
170202

171-
func GetRawContent(fset *token.FileSet, file []byte, node ast.Node) []byte {
203+
func GetRawContent(fset *token.FileSet, file []byte, node ast.Node, collectComment bool) []byte {
172204
var doc = bytes.Buffer{}
173205
switch v := node.(type) {
206+
case *ast.Field:
207+
if collectComment && v.Doc != nil {
208+
doc.Write(file[fset.Position(v.Doc.Pos()).Offset:fset.Position(v.Doc.End()).Offset])
209+
doc.WriteByte('\n')
210+
}
174211
case *ast.GenDecl:
175212
if collectComment && v.Doc != nil {
176213
doc.Write(file[fset.Position(v.Doc.Pos()).Offset:fset.Position(v.Doc.End()).Offset])
@@ -181,6 +218,8 @@ func GetRawContent(fset *token.FileSet, file []byte, node ast.Node) []byte {
181218
doc.Write(file[fset.Position(v.Doc.Pos()).Offset:fset.Position(v.Doc.End()).Offset])
182219
doc.WriteByte('\n')
183220
}
221+
// NOTICE: type spec is not the start of the type definition
222+
// so we need to add "type "
184223
doc.WriteString("type ")
185224
case *ast.ValueSpec:
186225
if collectComment && v.Doc != nil {

src/compress/golang/plugin/parse/file.go

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,9 @@ func (p *GoParser) parseFile(ctx *fileContext, f *ast.File) error {
4242
// fileFuncs[f.Name] = f
4343
cont = ct
4444
} else if decl, ok := node.(*ast.GenDecl); ok {
45-
var doc string
46-
if collectComment && decl.Doc != nil {
47-
doc = string(ctx.GetRawContent(decl.Doc)) + "\n"
45+
var doc *ast.CommentGroup
46+
if ctx.collectComment && decl.Doc != nil {
47+
doc = decl.Doc
4848
}
4949
var ct = true
5050
switch decl.Tok {
@@ -87,7 +87,7 @@ func (p *GoParser) newVar(mod string, pkg string, name string, isConst bool) *Va
8787
return p.repo.SetVar(ret.Identity, ret)
8888
}
8989

90-
func (p *GoParser) parseVar(ctx *fileContext, vspec *ast.ValueSpec, isConst bool, lastType *Identity, lastValue *float64, doc string) (*Identity, *float64) {
90+
func (p *GoParser) parseVar(ctx *fileContext, vspec *ast.ValueSpec, isConst bool, lastType *Identity, lastValue *float64, doc *ast.CommentGroup) (*Identity, *float64) {
9191
var typ *Identity
9292
var val *ast.Expr
9393
for i, name := range vspec.Names {
@@ -137,12 +137,15 @@ func (p *GoParser) parseVar(ctx *fileContext, vspec *ast.ValueSpec, isConst bool
137137
}
138138
}
139139

140-
if collectComment {
141-
if vspec.Doc != nil {
142-
doc += string(ctx.GetRawContent(vspec.Doc)) + "\n"
143-
}
144-
v.Content = doc + v.Content
140+
var comment string
141+
if ctx.collectComment && doc != nil {
142+
comment += string(ctx.GetRawContent(doc)) + "\n"
143+
}
144+
if ctx.collectComment && vspec.Doc != nil {
145+
comment += string(ctx.GetRawContent(vspec.Doc)) + "\n"
146+
v.FileLine.StartOffset = ctx.fset.Position(vspec.Pos()).Offset
145147
}
148+
v.Content = comment + v.Content
146149

147150
var finalVal string
148151
if val != nil {
@@ -425,7 +428,7 @@ set_func:
425428
return f, false
426429
}
427430

428-
func (p *GoParser) parseType(ctx *fileContext, typDecl *ast.TypeSpec, doc string) (st *Type, ct bool) {
431+
func (p *GoParser) parseType(ctx *fileContext, typDecl *ast.TypeSpec, doc *ast.CommentGroup) (st *Type, ct bool) {
429432
switch decl := typDecl.Type.(type) {
430433
case *ast.StructType:
431434
st, ct = p.parseStruct(ctx, typDecl.Name.Name, typDecl.Name, decl)
@@ -435,8 +438,6 @@ func (p *GoParser) parseType(ctx *fileContext, typDecl *ast.TypeSpec, doc string
435438
// typedef, ex: type Str StructA
436439
st = p.newType(ctx.module.Name, ctx.pkgPath, typDecl.Name.Name)
437440
st.TypeKind = TypeKindNamed
438-
st.Content = string(ctx.GetRawContent(typDecl))
439-
st.FileLine = ctx.FileLine(typDecl)
440441
p.collectTypes(ctx, typDecl.Type, st, typDecl.Assign.IsValid())
441442
ct = false
442443
// check if it implements any parser.interfaces
@@ -446,18 +447,18 @@ func (p *GoParser) parseType(ctx *fileContext, typDecl *ast.TypeSpec, doc string
446447
}
447448
}
448449
}
449-
if collectComment {
450-
st.Content = doc + string(ctx.GetRawContent(typDecl))
451-
} else {
452-
st.Content = string(ctx.GetRawContent(typDecl))
450+
451+
st.FileLine = ctx.FileLine(typDecl)
452+
st.Content = string(ctx.GetRawContent(typDecl))
453+
if ctx.collectComment && doc != nil {
454+
st.Content = string(ctx.GetRawContent(doc)) + "\n" + string(ctx.GetRawContent(typDecl))
453455
}
454456
return
455457
}
456458

457459
// parse a ast.StructType node and renturn allocated *Struct
458460
func (p *GoParser) parseStruct(ctx *fileContext, struName string, name *ast.Ident, struDecl *ast.StructType) (*Type, bool) {
459461
st := p.newType(ctx.module.Name, ctx.pkgPath, struName)
460-
st.FileLine = ctx.FileLine(struDecl)
461462
st.TypeKind = TypeKindStruct
462463
if struDecl.Fields == nil {
463464
return st, false
@@ -497,7 +498,6 @@ func (p *GoParser) parseInterface(ctx *fileContext, name *ast.Ident, decl *ast.I
497498
}
498499

499500
st := p.newType(ctx.module.Name, ctx.pkgPath, name.Name)
500-
st.FileLine = ctx.FileLine(decl)
501501
st.TypeKind = TypeKindInterface
502502

503503
for _, fieldDecl := range decl.Methods.List {
@@ -515,11 +515,7 @@ func (p *GoParser) parseInterface(ctx *fileContext, name *ast.Ident, decl *ast.I
515515
}
516516
st.Methods[fieldDecl.Names[0].Name] = id
517517
fn := p.newFunc(ctx.module.Name, ctx.pkgPath, id.Name)
518-
var doc string
519-
if collectComment && fieldDecl.Doc != nil {
520-
doc = string(ctx.GetRawContent(fieldDecl.Doc)) + "\n"
521-
}
522-
fn.Content = doc + string(ctx.GetRawContent(fieldDecl))
518+
fn.Content = string(ctx.GetRawContent(fieldDecl))
523519
fn.FileLine = ctx.FileLine(fieldDecl)
524520
fn.IsMethod = true
525521
fn.IsInterfaceMethod = true

src/compress/golang/plugin/parse/go_ast.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func Main() {
6666
if excludes != "" {
6767
exs = strings.Split(excludes, ",")
6868
}
69-
p := NewParser(homeDir, homeDir, WithReferCodeDepth(referCodeDepth), WithExcludes(exs))
69+
p := NewParser(homeDir, homeDir, WithReferCodeDepth(referCodeDepth), WithExcludes(exs), WithCollectComment(collectComment))
7070

7171
var out interface{}
7272

src/compress/golang/plugin/parse/go_ast_test.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ func Test_goParser_GeMainOnDepends(t *testing.T) {
4040
homePageDir: "../../../../../tmp/cloudwego/kitex",
4141
opts: Options{
4242
ReferCodeDepth: 1,
43+
CollectComment: true,
4344
},
4445
},
4546
},

src/compress/golang/plugin/parse/option.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
type Options struct {
2424
ReferCodeDepth int
2525
Excludes []*regexp.Regexp
26+
CollectComment bool
2627
}
2728

2829
type Option func(options *Options)
@@ -45,3 +46,9 @@ func WithExcludes(excludes []string) Option {
4546
}
4647
}
4748
}
49+
50+
func WithCollectComment(collect bool) Option {
51+
return func(options *Options) {
52+
options.CollectComment = collect
53+
}
54+
}

src/compress/golang/plugin/parse/parser.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ func (p *GoParser) searchOnFile(file *ast.File, fset *token.FileSet, fcontent []
305305
if dname == name {
306306
ids = append(ids, newIdentity(mod, pkg, name))
307307
fn := p.newFunc(mod, pkg, name)
308-
fn.Content = string(GetRawContent(fset, fcontent, decl))
308+
fn.Content = string(GetRawContent(fset, fcontent, decl, p.opts.CollectComment))
309309
fn.File = getRelativeOrBasePath(p.homePageDir, fset, decl.Pos())
310310
fn.Line = fset.Position(decl.Pos()).Line
311311
fn.IsMethod = decl.Recv != nil
@@ -334,7 +334,7 @@ func (p *GoParser) searchOnFile(file *ast.File, fset *token.FileSet, fcontent []
334334
var st *Type
335335
if spec.Name.Name == name {
336336
st = p.newType(mod, pkg, spec.Name.Name)
337-
st.Content = string(GetRawContent(fset, fcontent, spec))
337+
st.Content = string(GetRawContent(fset, fcontent, spec, p.opts.CollectComment))
338338
st.File = getRelativeOrBasePath(p.homePageDir, fset, decl.Pos())
339339
st.Line = fset.Position(decl.Pos()).Line
340340
st.TypeKind = getTypeKind(spec.Type)
@@ -351,7 +351,7 @@ func (p *GoParser) searchOnFile(file *ast.File, fset *token.FileSet, fcontent []
351351
// collect the method
352352
ids = append(ids, newIdentity(mod, pkg, name))
353353
fn := p.newFunc(mod, pkg, name)
354-
fn.Content = string(GetRawContent(fset, fcontent, m))
354+
fn.Content = string(GetRawContent(fset, fcontent, m, p.opts.CollectComment))
355355
fn.File = getRelativeOrBasePath(p.homePageDir, fset, decl.Pos())
356356
fn.Line = fset.Position(decl.Pos()).Line
357357
fn.IsMethod = true
@@ -382,7 +382,7 @@ func (p *GoParser) searchOnFile(file *ast.File, fset *token.FileSet, fcontent []
382382
if n.Name == name {
383383
ids = append(ids, newIdentity(mod, pkg, name))
384384
v := p.newVar(mod, pkg, name, decl.Tok == token.CONST)
385-
v.Content = string(GetRawContent(fset, fcontent, spec))
385+
v.Content = string(GetRawContent(fset, fcontent, spec, p.opts.CollectComment))
386386
v.File = getRelativeOrBasePath(p.homePageDir, fset, decl.Pos())
387387
v.Line = fset.Position(decl.Pos()).Line
388388
if spec.Type != nil {

src/compress/golang/plugin/parse/pkg.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ func (p *GoParser) parseImports(fset *token.FileSet, file []byte, mod *Module, i
3333
sysImports := make(map[string]string)
3434
ret := &importInfo{}
3535
for _, imp := range impts {
36-
ret.Origins = append(ret.Origins, string(GetRawContent(fset, file, imp)))
36+
ret.Origins = append(ret.Origins, string(GetRawContent(fset, file, imp, p.opts.CollectComment)))
3737
importPath := imp.Path.Value[1 : len(imp.Path.Value)-1] // remove the quotes
3838
importAlias := ""
3939
// Check if user has defined an alias for current import
@@ -185,14 +185,15 @@ func (p *GoParser) loadPackages(mod *Module, dir string, pkgPath PkgPath) (err e
185185
}
186186
bs := p.getFileBytes(filePath)
187187
ctx := &fileContext{
188-
repoDir: p.homePageDir,
189-
filePath: filePath,
190-
module: mod,
191-
pkgPath: pkg.ID,
192-
bs: bs,
193-
fset: fset,
194-
pkgTypeInfo: pkg.TypesInfo,
195-
deps: pkg.Imports,
188+
repoDir: p.homePageDir,
189+
filePath: filePath,
190+
module: mod,
191+
pkgPath: pkg.ID,
192+
bs: bs,
193+
fset: fset,
194+
pkgTypeInfo: pkg.TypesInfo,
195+
deps: pkg.Imports,
196+
collectComment: p.opts.CollectComment,
196197
}
197198
imports, err := p.parseImports(ctx.fset, ctx.bs, mod, file.Imports)
198199
if err != nil {

src/compress/golang/plugin/parse/pkg_test.go

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ import (
2828
)
2929

3030
func Test_goParser_ParseRepo(t *testing.T) {
31-
collectComment = true
3231
type fields struct {
3332
modName string
3433
homePageDir string
@@ -74,7 +73,6 @@ func Test_goParser_ParseRepo(t *testing.T) {
7473
println(string(jf))
7574
})
7675
}
77-
collectComment = false
7876
}
7977

8078
func Test_goParser_ParseDirs(t *testing.T) {
@@ -138,10 +136,10 @@ type Struct struct {
138136
ast.Inspect(node, func(n ast.Node) bool {
139137
fmt.Printf("%#v\n", n)
140138
if sel, ok := n.(*ast.SelectorExpr); ok {
141-
println("selector:", string(GetRawContent(fset, []byte(src), sel)))
139+
println("selector:", string(GetRawContent(fset, []byte(src), sel, false)))
142140
}
143141
if stru, ok := n.(*ast.StructType); ok {
144-
println("struct:", string(GetRawContent(fset, []byte(src), stru)))
142+
println("struct:", string(GetRawContent(fset, []byte(src), stru, true)))
145143
}
146144
return true
147145
})

src/lang/patch/lib_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,16 @@ func TestPatcher(t *testing.T) {
5959
ManagerOptions: localsession.DefaultManagerOptions(),
6060
}
6161
return ret
62+
}`,
63+
File: "backup/metainfo.go",
64+
Type: uniast.FUNC,
65+
},
66+
{
67+
Id: uniast.Identity{ModPath: "github.com/cloudwego/localsession", PkgPath: "github.com/cloudwego/localsession/backup", Name: "Options"},
68+
Codes: `type Options struct {
69+
Enable bool
70+
localsession.ManagerOptions
71+
Test bool
6272
}`,
6373
File: "backup/metainfo.go",
6474
Type: uniast.FUNC,

0 commit comments

Comments
 (0)