Skip to content

Commit 4f4e489

Browse files
author
Christian Weichel
committed
[bugfix] fix #10 by hard de-dupping documentSymbols
1 parent 1ec92fd commit 4f4e489

File tree

1 file changed

+61
-25
lines changed

1 file changed

+61
-25
lines changed

Diff for: handler/handler.go

+61-25
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"bytes"
55
"context"
66
"encoding/json"
7+
"fmt"
78
"io"
89
"io/ioutil"
910
"log"
@@ -587,29 +588,32 @@ func (handler *InoHandler) transformClangdResult(method string, uri lsp.Document
587588
handler.cpp2inoTextEdit(&(*r)[index], uri)
588589
}
589590
case "textDocument/documentSymbol":
590-
r := result.(*[]*documentSymbolOrSymbolInformation)
591+
r, ok := result.(*[]*documentSymbolOrSymbolInformation)
592+
593+
if !ok || len(*r) == 0 {
594+
return result
595+
}
596+
591597
slice := *r
592-
if len(slice) > 0 && slice[0].DocumentSymbol != nil {
598+
if slice[0].DocumentSymbol != nil {
593599
// Treat the input as []DocumentSymbol
594600
symbols := make([]DocumentSymbol, len(slice))
595601
for index := range slice {
596602
symbols[index] = *slice[index].DocumentSymbol
597603
}
598-
result = handler.cpp2inoDocumentSymbols(symbols, uri)
599-
} else if len(slice) > 0 && slice[0].SymbolInformation != nil {
604+
return handler.cpp2inoDocumentSymbols(symbols, uri)
605+
}
606+
if slice[0].SymbolInformation != nil {
600607
// Treat the input as []SymbolInformation
601-
symbols := make([]lsp.SymbolInformation, len(slice))
602-
for index := range slice {
603-
symbols[index] = *slice[index].SymbolInformation
608+
symbols := make([]*lsp.SymbolInformation, len(slice))
609+
for i, s := range slice {
610+
symbols[i] = s.SymbolInformation
604611
}
605-
for index := range symbols {
606-
handler.cpp2inoLocation(&symbols[index].Location)
607-
}
608-
result = symbols
612+
return handler.cpp2inoSymbolInformation(symbols)
609613
}
610614
case "textDocument/rename":
611615
r := result.(*lsp.WorkspaceEdit)
612-
result = handler.cpp2inoWorkspaceEdit(r)
616+
return handler.cpp2inoWorkspaceEdit(r)
613617
case "workspace/symbol":
614618
r := result.(*[]lsp.SymbolInformation)
615619
for index := range *r {
@@ -711,29 +715,61 @@ func (handler *InoHandler) cpp2inoDocumentSymbols(origSymbols []DocumentSymbol,
711715
if !ok || len(origSymbols) == 0 {
712716
return origSymbols
713717
}
714-
newSymbols := make([]DocumentSymbol, len(origSymbols))
715-
j := 0
718+
719+
symbolIdx := make(map[string]*DocumentSymbol)
716720
for i := 0; i < len(origSymbols); i++ {
717721
symbol := &origSymbols[i]
718722
symbol.Range.Start.Line = data.sourceLineMap[symbol.Range.Start.Line]
719723
symbol.Range.End.Line = data.sourceLineMap[symbol.Range.End.Line]
720724

721725
duplicate := false
722-
for k := 0; k < j; k++ {
723-
if symbol.Name == newSymbols[k].Name && symbol.Range.Start.Line == newSymbols[k].Range.Start.Line {
724-
duplicate = true
725-
break
726+
other, duplicate := symbolIdx[symbol.Name]
727+
if duplicate {
728+
// we prefer symbols later in the file due to the function header generation. E.g. if one has a function `void foo() {}` somehwre in the code
729+
// the code generation will add a `void foo();` header at the beginning of the cpp file. We care about the function body later in the file, not
730+
// the header early on.
731+
if other.Range.Start.Line < symbol.Range.Start.Line {
732+
continue
726733
}
727734
}
728-
if !duplicate {
729-
symbol.SelectionRange.Start.Line = data.sourceLineMap[symbol.SelectionRange.Start.Line]
730-
symbol.SelectionRange.End.Line = data.sourceLineMap[symbol.SelectionRange.End.Line]
731-
symbol.Children = handler.cpp2inoDocumentSymbols(symbol.Children, uri)
732-
newSymbols[j] = *symbol
733-
j++
735+
736+
symbol.SelectionRange.Start.Line = data.sourceLineMap[symbol.SelectionRange.Start.Line]
737+
symbol.SelectionRange.End.Line = data.sourceLineMap[symbol.SelectionRange.End.Line]
738+
symbol.Children = handler.cpp2inoDocumentSymbols(symbol.Children, uri)
739+
symbolIdx[symbol.Name] = symbol
740+
}
741+
742+
newSymbols := make([]DocumentSymbol, len(symbolIdx))
743+
j := 0
744+
for _, s := range symbolIdx {
745+
newSymbols[j] = *s
746+
j++
747+
}
748+
return newSymbols
749+
}
750+
751+
func (handler *InoHandler) cpp2inoSymbolInformation(syms []*lsp.SymbolInformation) []lsp.SymbolInformation {
752+
// much like in cpp2inoDocumentSymbols we de-duplicate symbols based on file in-file location.
753+
idx := make(map[string]*lsp.SymbolInformation)
754+
for _, sym := range syms {
755+
handler.cpp2inoLocation(&sym.Location)
756+
757+
nme := fmt.Sprintf("%s::%s", sym.ContainerName, sym.Name)
758+
other, duplicate := idx[nme]
759+
if duplicate && other.Location.Range.Start.Line < sym.Location.Range.Start.Line {
760+
continue
734761
}
762+
763+
idx[nme] = sym
764+
}
765+
766+
var j int
767+
symbols := make([]lsp.SymbolInformation, len(idx))
768+
for _, sym := range idx {
769+
symbols[j] = *sym
770+
j++
735771
}
736-
return newSymbols[:j]
772+
return symbols
737773
}
738774

739775
// FromClangd handles a message received from clangd.

0 commit comments

Comments
 (0)