Skip to content

Commit 8380d7f

Browse files
committed
Improve source print
1 parent ccb3e93 commit 8380d7f

File tree

5 files changed

+135
-40
lines changed

5 files changed

+135
-40
lines changed

include/Feature/Hover.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#pragma once
22

3-
#include "AST/SourceCode.h"
43
#include "AST/SymbolKind.h"
54
#include "Index/Shared.h"
65
#include "Protocol/Basic.h"
@@ -54,6 +53,8 @@ struct Hover {
5453

5554
std::string name;
5655

56+
const char *lang = "cpp";
57+
5758
/// Extra information.
5859
std::vector<HoverItem> items;
5960

src/Feature/Hover.cpp

Lines changed: 101 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
#include "Feature/Hover.h"
22

33
#include "AST/Selection.h"
4-
#include "AST/Semantic.h"
54
#include "AST/Utility.h"
65
#include "Compiler/CompilationUnit.h"
76
#include "Index/Shared.h"
8-
#include "Support/Compare.h"
7+
#include "Support/Doxygen.h"
98
#include "Support/Logging.h"
10-
#include "Support/Ranges.h"
9+
#include "Support/StructedText.h"
1110

1211
#include "clang/AST/ASTDiagnostic.h"
12+
#include "clang/AST/RecursiveASTVisitor.h"
1313
#include "clang/Lex/Lexer.h"
1414
#include "clang/Sema/HeuristicResolver.h"
1515

@@ -27,6 +27,15 @@ static auto to_proto_range(clang::SourceManager& sm, clang::SourceRange range) -
2727
return {begin, end};
2828
};
2929

30+
clang::PrintingPolicy proxy_print_policy(clang::PrintingPolicy Base) {
31+
Base.AnonymousTagLocations = false;
32+
Base.TerseOutput = true;
33+
Base.PolishForDeclaration = true;
34+
Base.ConstantsAsWritten = true;
35+
Base.SuppressTemplateArgsInCXXConstructors = true;
36+
return Base;
37+
}
38+
3039
// Print type and optionally desuguared type
3140
static std::string print_type(clang::ASTContext& ctx,
3241
clang::QualType qt,
@@ -100,7 +109,7 @@ static std::vector<HoverItem> get_hover_items(CompilationUnitRef unit,
100109
const clang::NamedDecl* decl,
101110
const config::HoverOptions& opt) {
102111
clang::ASTContext& ctx = unit.context();
103-
const auto pp = ctx.getPrintingPolicy();
112+
const auto pp = proxy_print_policy(ctx.getPrintingPolicy());
104113
std::vector<HoverItem> items;
105114

106115
auto add_item = [&items](HoverItem::HoverKind kind, std::string&& val) {
@@ -169,8 +178,8 @@ static std::string get_document(CompilationUnitRef unit,
169178
return "";
170179
}
171180
auto raw_string = comment->getFormattedText(Ctx.getSourceManager(), Ctx.getDiagnostics());
172-
LOG_WARN("Got comment:\n```\n{}\n```\n", raw_string);
173-
return "";
181+
// LOG_WARN("Got comment:\n```\n{}\n```\n", raw_string);
182+
return raw_string;
174183
}
175184

176185
static std::string get_qualifier(CompilationUnitRef unit,
@@ -397,28 +406,36 @@ static std::optional<clang::QualType> getDeducedType(clang::ASTContext& ASTCtx,
397406
return V.DeducedType;
398407
}
399408

400-
// TODO: How does clangd put together decl, name, scope and sometimes initialized value?
401-
// ```
402-
// // scope
403-
// <Access specifier> <type> <name> <initialized value>
404-
// ```
405-
static std::string get_source_code(CompilationUnitRef unit,
406-
const clang::NamedDecl* decl,
407-
config::HoverOptions opt) {
408-
clang::SourceRange range = decl->getSourceRange();
409-
return get_source_code(unit, range);
409+
static std::string get_source_code(const clang::Decl* decl,
410+
clang::PrintingPolicy pp,
411+
const clang::syntax::TokenBuffer& tb) {
412+
if(auto* vd = llvm::dyn_cast<clang::VarDecl>(decl)) {
413+
if(auto* ie = vd->getInit()) {
414+
// Initializers might be huge and result in lots of memory allocations in
415+
// some catostrophic cases. Such long lists are not useful in hover cards
416+
// anyway.
417+
if(200 < tb.expandedTokens(ie->getSourceRange()).size()) {
418+
pp.SuppressInitializers = true;
419+
}
420+
}
421+
}
422+
std::string def;
423+
llvm::raw_string_ostream os(def);
424+
decl->print(os, pp);
425+
return def;
410426
}
411427

412428
static std::optional<Hover> hover(CompilationUnitRef unit,
413429
const clang::NamedDecl* decl,
414430
const config::HoverOptions& opt) {
431+
auto pp = proxy_print_policy(unit.context().getPrintingPolicy());
415432
return Hover{
416433
.kind = SymbolKind::from(decl),
417434
.name = ast::name_of(decl),
418435
.items = get_hover_items(unit, decl, opt),
419436
.document = get_document(unit, decl, opt),
420437
.qualifier = get_qualifier(unit, decl, opt),
421-
.source = get_source_code(unit, decl, opt),
438+
.source = get_source_code(llvm::dyn_cast<const clang::Decl>(decl), pp, unit.token_buffer()),
422439
};
423440
}
424441

@@ -428,7 +445,7 @@ static std::optional<Hover> hover(CompilationUnitRef unit,
428445
// TODO: Hover for type
429446
// TODO: Add source code
430447
auto& ctx = unit.context();
431-
auto pp = ctx.getPrintingPolicy();
448+
auto pp = proxy_print_policy(ctx.getPrintingPolicy());
432449
return Hover{.kind = SymbolKind::Type, .name = print_type(ctx, ty, pp, opt)};
433450
}
434451

@@ -526,12 +543,41 @@ static std::optional<Hover> hover(CompilationUnitRef unit,
526543
return std::nullopt;
527544
}
528545

546+
// TODO: A better way to get current unit lang? e.g. clang::InputKind
547+
const char* get_guessed_lang_name(CompilationUnitRef unit) {
548+
const auto& langopt = unit.lang_options();
549+
if(langopt.ObjC) {
550+
if(langopt.CPlusPlus) {
551+
return "objcpp";
552+
}
553+
return "objc";
554+
}
555+
if(langopt.CPlusPlus || langopt.HIP) {
556+
return "cpp";
557+
}
558+
if(langopt.CUDA) {
559+
return "cuda";
560+
}
561+
if(langopt.SYCLIsDevice || langopt.SYCLIsHost) {
562+
return "sycl";
563+
}
564+
// Editor Support?
565+
// if(langopt.OpenCL) {
566+
// return "opencl";
567+
// }
568+
if(langopt.HLSL) {
569+
return "hlsl";
570+
}
571+
return "c";
572+
}
573+
529574
} // namespace
530575

531576
std::optional<Hover> hover(CompilationUnitRef unit,
532577
std::uint32_t offset,
533578
const config::HoverOptions& opt) {
534579
auto& sm = unit.context().getSourceManager();
580+
auto lang_name = get_guessed_lang_name(unit);
535581

536582
auto src_loc_in_main_file = [&sm, &unit](uint32_t off) -> std::optional<clang::SourceLocation> {
537583
auto fid = sm.getMainFileID();
@@ -564,6 +610,7 @@ std::optional<Hover> hover(CompilationUnitRef unit,
564610
auto raw_name = get_source_code(unit, inclusion.filename_range);
565611
auto file_name = llvm::StringRef{raw_name}.trim("<>\"");
566612
Hover hi;
613+
hi.lang = lang_name;
567614
hi.kind = SymbolKind::Directive;
568615
hi.name = file_name;
569616
auto dir = sm.getFileEntryForID(inclusion.fid)->tryGetRealPathName();
@@ -587,6 +634,7 @@ std::optional<Hover> hover(CompilationUnitRef unit,
587634
auto macro_name = get_source_code(unit, name_range);
588635
macro_name.pop_back();
589636
Hover hi;
637+
hi.lang = lang_name;
590638
hi.kind = SymbolKind::Macro;
591639
hi.name = macro_name;
592640
auto source = "#define " + get_source_code(unit,
@@ -620,6 +668,7 @@ std::optional<Hover> hover(CompilationUnitRef unit,
620668
if(auto node = tree.common_ancestor()) {
621669
LOG_WARN("Got node: {}", node->kind());
622670
if(auto info = hover(unit, node, opt)) {
671+
info->lang = lang_name;
623672
info->hl_range = to_proto_range(sm, hl_range);
624673
return info;
625674
}
@@ -644,20 +693,43 @@ std::optional<std::string> Hover::display(config::HoverOptions opt) {
644693
std::string content;
645694
llvm::raw_string_ostream os(content);
646695
// TODO: generate markdown
647-
os << std::format("{}: {}\n", this->kind.name(), this->name);
648-
os << std::format("Contains {} items\n", this->items.size());
649-
for(auto& hi: this->items) {
650-
os << std::format("- {}: {}\n", clice::refl::enum_name(hi.kind), hi.value);
696+
StructedText out{};
697+
StructedText head_segment{};
698+
head_segment.add_heading(3).append_text(std::format("{}: {}", this->kind.name(), this->name));
699+
// TODO: provider
700+
head_segment.add_ruler();
701+
// FIX: Delete later
702+
head_segment.add_paragraph()
703+
.append_text(std::format("Contains {} items", this->items.size()))
704+
.append_newline_char();
705+
if(this->items.size()) {
706+
auto& bl = head_segment.add_bullet_list();
707+
for(auto& hi: this->items) {
708+
bl.add_item().add_paragraph().append_text(
709+
std::format("{}: {}", clice::refl::enum_name(hi.kind), hi.value));
710+
}
651711
}
652-
if(this->document) {
653-
os << "---\n";
654-
os << "Document:\n```text\n" << *this->document << "\n```\n";
712+
out.append(head_segment);
713+
if(this->document && opt.enable_doxygen_parsing) {
714+
StructedText st{};
715+
auto& raw = *this->document;
716+
auto [di, rest_] = strip_doxygen_info(raw);
717+
if(auto rest = llvm::StringRef(rest_); !rest.trim().empty()) {
718+
st.add_paragraph().append_text(rest.rtrim().str());
719+
st.add_ruler();
720+
}
721+
auto bcc = di.get_block_command_comments();
722+
for(const auto [tag, content]: bcc) {
723+
st.add_paragraph().append_text(tag.str(), Paragraph::Kind::Bold);
724+
st.add_ruler();
725+
}
726+
st.add_ruler();
727+
out.append(st);
655728
}
656-
if(!this->source.empty()) {
657-
os << "---\n";
658-
os << "Source code:\n```cpp\n" << this->source << "\n```\n";
729+
if(!source.empty()) {
730+
out.add_code_block(source + '\n', lang);
659731
}
660-
return os.str();
732+
return out.as_markdown();
661733
}
662734

663735
} // namespace clice::feature

src/Server/Feature.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,15 @@ auto Server::on_hover(proto::HoverParams params) -> Result {
7070
if(auto info = hover->display(opt)) {
7171
result.contents.value = *info;
7272
} else {
73-
clice::logging::warn("Cannot display hover info");
73+
LOG_WARN("Cannot display hover info");
7474
result.contents.value = "Cannot display hover info";
7575
}
7676
if(!hover->hl_range) {
77-
clice::logging::warn("Not available range");
77+
LOG_WARN("Not available range");
7878
}
7979
result.range = hover->hl_range;
8080
} else {
81-
clice::logging::warn("Cannot get hover info");
81+
LOG_WARN("Cannot get hover info");
8282
result.contents.value = "Cannot get hover info";
8383
}
8484
return json::serialize(result);

src/Support/Doxygen.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,11 @@ static void process_paragragh(llvm::SmallVector<llvm::StringRef>::iterator& line
142142
rest_of_line = trimed.drop_front(command_end);
143143
}
144144

145+
if(command == "b" | command == "e" | command == "c") {
146+
// Just start with inline command leave it.
147+
goto normal_line;
148+
}
149+
145150
if(command.equals_insensitive("param")) {
146151
// Got param command
147152
auto direction = DoxygenInfo::ParamCommandCommentContent::ParamDirection::Unspecified;
@@ -230,6 +235,7 @@ static void process_paragragh(llvm::SmallVector<llvm::StringRef>::iterator& line
230235
return;
231236
}
232237
}
238+
normal_line:
233239
// Not a command block, but may include commands like '@b', '@e'
234240
process_non_command_line(*line_ref, rest);
235241
++line_ref;

tests/unit/Feature/HoverTests.cpp

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,22 @@ int main(void) {
158158
tester.compile();
159159
ASSERT_TRUE(tester.unit.has_value());
160160
const unsigned count = annotation.offsets.size();
161-
for(unsigned i = 0; i < count; ++i) {
161+
for(unsigned i = 0; i < count / 2; ++i) {
162162
unsigned offset = annotation.offsets[std::format("pos_{}", i)];
163163
auto HI = clice::feature::hover(*tester.unit, offset, {});
164+
std::println("Hover at pos_{}", i);
165+
if(HI.has_value()) {
166+
auto msg = HI->display({});
167+
std::println("```\n{}```\n", *msg);
168+
} else {
169+
std::println("No hover info");
170+
}
171+
}
172+
173+
for(unsigned i = 0; i < count / 2; ++i) {
174+
unsigned offset = annotation.offsets[std::format("pos_{}_i", i)];
175+
auto HI = clice::feature::hover(*tester.unit, offset, {});
176+
std::println("Hover at pos_{}_i", i);
164177
if(HI.has_value()) {
165178
auto msg = HI->display({});
166179
std::println("```\n{}```\n", *msg);
@@ -236,6 +249,7 @@ int main() {
236249
for(unsigned i = 0; i < count; ++i) {
237250
unsigned offset = annotation.offsets[std::format("pos_{}", i)];
238251
auto HI = clice::feature::hover(*tester.unit, offset, {});
252+
std::println("Hover at pos_{}", i);
239253
if(HI.has_value()) {
240254
auto msg = HI->display({});
241255
std::println("```\n{}```\n", *msg);
@@ -302,15 +316,17 @@ static void fu$(pos_4)nc4() {
302316
for(unsigned i = 0; i < count; ++i) {
303317
unsigned offset = annotation.offsets[std::format("pos_{}", i)];
304318
auto HI = clice::feature::hover(*tester.unit, offset, {});
305-
// if(HI.has_value()) {
306-
// auto msg = HI->display({});
307-
// std::println("```\n{}```\n", *msg);
308-
// } else {
309-
// std::println("No hover info");
310-
// }
319+
if(HI.has_value()) {
320+
auto msg = HI->display({});
321+
std::println("```\n{}```\n", *msg);
322+
} else {
323+
std::println("No hover info");
324+
}
311325
}
312326
}
313327

328+
TEST_CASE(Doxygen) {}
329+
314330
TEST_CASE(Namespace) {
315331
run(R"cpp(
316332
namespace A {

0 commit comments

Comments
 (0)