|
4 | 4 | "bytes"
|
5 | 5 | "context"
|
6 | 6 | "encoding/json"
|
| 7 | + "fmt" |
7 | 8 | "io"
|
8 | 9 | "io/ioutil"
|
9 | 10 | "log"
|
@@ -587,29 +588,32 @@ func (handler *InoHandler) transformClangdResult(method string, uri lsp.Document
|
587 | 588 | handler.cpp2inoTextEdit(&(*r)[index], uri)
|
588 | 589 | }
|
589 | 590 | case "textDocument/documentSymbol":
|
590 |
| - r := result.(*[]*documentSymbolOrSymbolInformation) |
| 591 | + r, ok := result.(*[]*documentSymbolOrSymbolInformation) |
| 592 | + |
| 593 | + if !ok || len(*r) == 0 { |
| 594 | + return result |
| 595 | + } |
| 596 | + |
591 | 597 | slice := *r
|
592 |
| - if len(slice) > 0 && slice[0].DocumentSymbol != nil { |
| 598 | + if slice[0].DocumentSymbol != nil { |
593 | 599 | // Treat the input as []DocumentSymbol
|
594 | 600 | symbols := make([]DocumentSymbol, len(slice))
|
595 | 601 | for index := range slice {
|
596 | 602 | symbols[index] = *slice[index].DocumentSymbol
|
597 | 603 | }
|
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 { |
600 | 607 | // 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 |
604 | 611 | }
|
605 |
| - for index := range symbols { |
606 |
| - handler.cpp2inoLocation(&symbols[index].Location) |
607 |
| - } |
608 |
| - result = symbols |
| 612 | + return handler.cpp2inoSymbolInformation(symbols) |
609 | 613 | }
|
610 | 614 | case "textDocument/rename":
|
611 | 615 | r := result.(*lsp.WorkspaceEdit)
|
612 |
| - result = handler.cpp2inoWorkspaceEdit(r) |
| 616 | + return handler.cpp2inoWorkspaceEdit(r) |
613 | 617 | case "workspace/symbol":
|
614 | 618 | r := result.(*[]lsp.SymbolInformation)
|
615 | 619 | for index := range *r {
|
@@ -711,29 +715,61 @@ func (handler *InoHandler) cpp2inoDocumentSymbols(origSymbols []DocumentSymbol,
|
711 | 715 | if !ok || len(origSymbols) == 0 {
|
712 | 716 | return origSymbols
|
713 | 717 | }
|
714 |
| - newSymbols := make([]DocumentSymbol, len(origSymbols)) |
715 |
| - j := 0 |
| 718 | + |
| 719 | + symbolIdx := make(map[string]*DocumentSymbol) |
716 | 720 | for i := 0; i < len(origSymbols); i++ {
|
717 | 721 | symbol := &origSymbols[i]
|
718 | 722 | symbol.Range.Start.Line = data.sourceLineMap[symbol.Range.Start.Line]
|
719 | 723 | symbol.Range.End.Line = data.sourceLineMap[symbol.Range.End.Line]
|
720 | 724 |
|
721 | 725 | 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 |
726 | 733 | }
|
727 | 734 | }
|
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 |
734 | 761 | }
|
| 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++ |
735 | 771 | }
|
736 |
| - return newSymbols[:j] |
| 772 | + return symbols |
737 | 773 | }
|
738 | 774 |
|
739 | 775 | // FromClangd handles a message received from clangd.
|
|
0 commit comments