66#include " Compiler/CompilationUnit.h"
77#include " Index/Shared.h"
88#include " Support/Compare.h"
9+ #include " Support/Logging.h"
910#include " Support/Ranges.h"
1011
12+ #include " clang/AST/ASTDiagnostic.h"
13+ #include " clang/Lex/Lexer.h"
14+ #include " clang/Sema/HeuristicResolver.h"
15+
1116namespace clice ::feature {
1217
1318namespace {
@@ -22,24 +27,106 @@ static auto to_proto_range(clang::SourceManager& sm, clang::SourceRange range) -
2227 return {begin, end};
2328};
2429
30+ // Print type and optionally desuguared type
31+ static std::string print_type (clang::ASTContext& ctx,
32+ clang::QualType qt,
33+ const clang::PrintingPolicy pp,
34+ const config::HoverOptions& opt) {
35+ std::string ret;
36+ llvm::raw_string_ostream os (ret);
37+ while (!qt.isNull () && qt->isDecltypeType ()) {
38+ qt = qt->castAs <clang::DecltypeType>()->getUnderlyingType ();
39+ }
40+ if (!qt.isNull () && !qt.hasQualifiers () && pp.SuppressTagKeyword ) {
41+ if (auto * tt = llvm::dyn_cast<clang::TagType>(qt.getTypePtr ());
42+ tt && tt->isCanonicalUnqualified ()) {
43+ os << tt->getDecl ()->getKindName () << ' ' ;
44+ }
45+ }
46+ qt.print (os, pp);
47+ if (qt.isNull () && opt.show_aka ) {
48+ bool should_aka = false ;
49+ auto desugared_ty = clang::desugarForDiagnostic (ctx, qt, should_aka);
50+ if (should_aka) {
51+ os << " (a.k.a " << desugared_ty.getAsString (pp) << " )" ;
52+ }
53+ }
54+ return ret;
55+ }
56+
57+ static std::string print_type (const clang::TemplateTypeParmDecl* TTP) {
58+ std::string ret = TTP->wasDeclaredWithTypename () ? " typename" : " class" ;
59+ if (TTP->isParameterPack ()) {
60+ ret += " ..." ;
61+ }
62+ return ret;
63+ }
64+
65+ static std::string print_type (const clang::NonTypeTemplateParmDecl* NTTP,
66+ const clang::PrintingPolicy PP,
67+ const config::HoverOptions& opt) {
68+ std::string ret = print_type (NTTP->getASTContext (), NTTP->getType (), PP, opt);
69+ if (NTTP->isParameterPack ()) {
70+ ret += " ..." ;
71+ }
72+ return ret;
73+ }
74+
75+ static std::string print_type (const clang::TemplateTemplateParmDecl* TTP,
76+ const clang::PrintingPolicy PP,
77+ const config::HoverOptions& opt) {
78+ using namespace clang ;
79+ std::string ret;
80+ llvm::raw_string_ostream OS (ret);
81+ OS << " template <" ;
82+ llvm::StringRef Sep = " " ;
83+ for (const Decl* Param: *TTP->getTemplateParameters ()) {
84+ OS << Sep;
85+ Sep = " , " ;
86+ if (const auto * TTP = dyn_cast<TemplateTypeParmDecl>(Param))
87+ OS << print_type (TTP);
88+ else if (const auto * NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
89+ OS << print_type (NTTP, PP, opt);
90+ else if (const auto * TTPD = dyn_cast<TemplateTemplateParmDecl>(Param))
91+ OS << print_type (TTPD, PP, opt);
92+ }
93+ // FIXME: TemplateTemplateParameter doesn't store the info on whether this
94+ // param was a "typename" or "class".
95+ OS << " > class" ;
96+ return ret;
97+ }
98+
2599static std::vector<HoverItem> get_hover_items (CompilationUnit& unit,
26100 const clang::NamedDecl* decl,
27101 const config::HoverOptions& opt) {
28102 clang::ASTContext& ctx = unit.context ();
103+ const auto pp = ctx.getPrintingPolicy ();
29104 std::vector<HoverItem> items;
30105
31106 auto add_item = [&items](HoverItem::HoverKind kind, std::string&& val) {
32107 items.emplace_back (kind, val);
33108 };
34109
35- // / TODO: Add other hover items.
110+ // Add type info
111+ if (const auto * VD = dyn_cast<clang::ValueDecl>(decl)) {
112+ add_item (HoverItem::Type, print_type (ctx, VD->getType (), pp, opt));
113+ } else if (const auto * TTP = dyn_cast<clang::TemplateTypeParmDecl>(decl)) {
114+ add_item (HoverItem::Type, TTP->wasDeclaredWithTypename () ? " typename" : " class" );
115+ } else if (const auto * TTP = dyn_cast<clang::TemplateTemplateParmDecl>(decl)) {
116+ add_item (HoverItem::Type, print_type (TTP, pp, opt));
117+ } else if (const auto * VT = dyn_cast<clang::VarTemplateDecl>(decl)) {
118+ add_item (HoverItem::Type, print_type (ctx, VT->getTemplatedDecl ()->getType (), pp, opt));
119+ } else if (const auto * TN = dyn_cast<clang::TypedefNameDecl>(decl)) {
120+ add_item (HoverItem::Type,
121+ print_type (ctx, TN->getUnderlyingType ().getDesugaredType (ctx), pp, opt));
122+ } else if (const auto * TAT = dyn_cast<clang::TypeAliasTemplateDecl>(decl)) {
123+ add_item (HoverItem::Type,
124+ print_type (ctx, TAT->getTemplatedDecl ()->getUnderlyingType (), pp, opt));
125+ }
126+
36127 if (auto fd = llvm::dyn_cast<clang::FieldDecl>(decl)) {
37- LOGGING_WARN (" Got a field decl" );
128+ // LOG_INFO ("Got a field decl");
38129 const auto record = fd->getParent ();
39- add_item (HoverItem::Type, fd->getType ().getAsString ());
40-
41- // / Remove in release mode
42- // / add_item(HoverItem::FieldIndex, llvm::Twine(fd->getFieldIndex()).str());
43130 if (!record->isDependentType ()) {
44131 add_item (HoverItem::Offset, llvm::Twine (ctx.getFieldOffset (fd)).str ());
45132 add_item (HoverItem::Align,
@@ -57,13 +144,9 @@ static std::vector<HoverItem> get_hover_items(CompilationUnit& unit,
57144
58145 if (fd->isBitField ()) {
59146 add_item (HoverItem::BitWidth, llvm::Twine (fd->getBitWidthValue ()).str ());
60- LOGGING_WARN (" Got bit field, name: {}, bitwidth: {}" ,
61- fd->getName (),
62- fd->getBitWidthValue ());
63147 }
64148 } else if (auto vd = llvm::dyn_cast<clang::VarDecl>(decl)) {
65- LOGGING_WARN (" Got a var decl" );
66- add_item (HoverItem::Type, vd->getType ().getAsString ());
149+ auto ty = vd->getType ();
67150 }
68151
69152 return items;
@@ -72,12 +155,14 @@ static std::vector<HoverItem> get_hover_items(CompilationUnit& unit,
72155static std::vector<HoverItem> get_hover_items (CompilationUnit& unit,
73156 const clang::TypeLoc* typeloc,
74157 const config::HoverOptions& opt) {
158+ // TODO: Add items for typeloc
75159 return {};
76160}
77161
78162static std::string get_document (CompilationUnit& unit,
79163 const clang::NamedDecl* decl,
80164 config::HoverOptions opt) {
165+ // TODO: Get comment and strip `/**/` and `//`
81166 clang::ASTContext& Ctx = unit.context ();
82167 const clang::RawComment* comment = Ctx.getRawCommentForAnyRedecl (decl);
83168 if (!comment) {
@@ -96,19 +181,6 @@ static std::string get_qualifier(CompilationUnit& unit,
96181 return result;
97182}
98183
99- // Get all source code
100- static std::string get_source_code (CompilationUnit& unit, clang::SourceRange range) {
101- clang::LangOptions lo;
102- auto & sm = unit.context ().getSourceManager ();
103- auto start_loc = sm.getSpellingLoc (range.getBegin ());
104- auto last_token_loc = sm.getSpellingLoc (range.getEnd ());
105- auto end_loc = clang::Lexer::getLocForEndOfToken (last_token_loc, 0 , sm, lo);
106- return std::string{clang::Lexer::getSourceText (
107- clang::CharSourceRange::getCharRange (clang::SourceRange{start_loc, end_loc}),
108- sm,
109- lo)};
110- }
111-
112184static clang::TemplateTypeParmTypeLoc getContainedAutoParamType (clang::TypeLoc TL) {
113185 if (auto QTL = TL.getAs <clang::QualifiedTypeLoc>())
114186 return getContainedAutoParamType (QTL.getUnqualifiedLoc ());
@@ -296,7 +368,7 @@ class DeducedTypeVisitor : public clang::RecursiveASTVisitor<DeducedTypeVisitor>
296368 clang::QualType DeducedType;
297369};
298370
299- // FIXME: Do as clangd did(?) a more simple way?
371+ // FIXME: Do as clangd a more simple way?
300372static std::optional<clang::QualType> getDeducedType (clang::ASTContext& ASTCtx,
301373 const clang::HeuristicResolver* Resolver,
302374 clang::SourceLocation Loc) {
@@ -311,6 +383,19 @@ static std::optional<clang::QualType> getDeducedType(clang::ASTContext& ASTCtx,
311383 return V.DeducedType ;
312384}
313385
386+ // Get all source code
387+ static std::string get_source_code (CompilationUnit& unit, clang::SourceRange range) {
388+ clang::LangOptions lo;
389+ auto & sm = unit.context ().getSourceManager ();
390+ auto start_loc = sm.getSpellingLoc (range.getBegin ());
391+ auto last_token_loc = sm.getSpellingLoc (range.getEnd ());
392+ auto end_loc = clang::Lexer::getLocForEndOfToken (last_token_loc, 0 , sm, lo);
393+ return std::string{clang::Lexer::getSourceText (
394+ clang::CharSourceRange::getCharRange (clang::SourceRange{start_loc, end_loc}),
395+ sm,
396+ lo)};
397+ }
398+
314399// TODO: How does clangd put together decl, name, scope and sometimes initialized value?
315400// ```
316401// // scope
@@ -348,10 +433,9 @@ static std::optional<Hover> hover(CompilationUnit& unit,
348433 const SelectionTree::Node* node,
349434 const config::HoverOptions& opt) {
350435 using namespace clang ;
351- auto wanted_node = node;
352- auto Kind = node->data .getNodeKind ();
353436
354437#define kind_flag_def (Ty ) static constexpr auto Flag##Ty = ASTNodeKind::getFromNodeKind<Ty>()
438+
355439 kind_flag_def (QualType);
356440 kind_flag_def (TypeLoc);
357441 kind_flag_def (Decl);
@@ -366,44 +450,70 @@ static std::optional<Hover> hover(CompilationUnit& unit,
366450 kind_flag_def (TemplateName);
367451 kind_flag_def (NestedNameSpecifierLoc);
368452 kind_flag_def (Attr);
453+ kind_flag_def (DeclRefExpr);
369454 kind_flag_def (ObjCProtocolLoc);
370455
371456#define is (flag ) (Kind.isSame(Flag##flag))
372457
373458#define is_in_range (LHS, RHS ) (!((Kind < Flag##LHS) && is(LHS)) && (Kind < Flag##RHS))
374459
460+ auto wanted_node = node;
461+ auto Kind = node->data .getNodeKind ();
462+
375463 // auto and decltype is specially processed
376464 if (is (AutoTypeLoc) || is (DecltypeTypeLoc)) {
377465 auto resolver = HeuristicResolver (unit.context ());
378466 if (auto ty = getDeducedType (unit.context (), &resolver, node->source_range ().getBegin ())) {
379467 return hover (unit, *ty, opt);
380468 } else {
381- LOGGING_WARN (" Cannot get deduced type" );
469+ LOG_WARN (" Cannot get deduced type" );
382470 }
383471 }
384472
385473 if (is (NestedNameSpecifierLoc)) {
386- LOGGING_WARN (" Hit a `NestedNameSpecifierLoc`" );
474+ if (auto ns_specifier_loc = node->get <NestedNameSpecifierLoc>()) {
475+ LOG_WARN (" Hit a `NestedNameSpecifierLoc`" );
476+ if (auto ns_specifier = ns_specifier_loc->getNestedNameSpecifier ()) {
477+ auto ns = ns_specifier->getAsNamespace ();
478+ assert (ns);
479+ std::string name;
480+ if (!ns->isAnonymousNamespace ()) {
481+ name = ns->getNameAsString ();
482+ } else {
483+ name = " Anonymous" ;
484+ }
485+ return Hover{.kind = SymbolKind::Namespace, .name = name};
486+ } else {
487+ LOG_WARN (" Cannot get namespace" );
488+ }
489+ }
387490 } else if (is_in_range (QualType, TypeLoc)) {
388491 // Typeloc
389- LOGGING_WARN (" Hit a `TypeLoc`" );
390- if (auto typeloc = node->get <clang:: TypeLoc>()) {
492+ LOG_WARN (" Hit a `TypeLoc`" );
493+ if (auto typeloc = node->get <TypeLoc>()) {
391494 return hover (unit, typeloc->getType (), opt);
392495 }
393496 } else if (is_in_range (Decl, Stmt)) {
394497 // Decl
395- LOGGING_WARN (" Hit a `Decl`" );
498+ LOG_WARN (" Hit a `Decl`" );
396499 if (auto decl = node->get <clang::NamedDecl>()) {
397500 return hover (unit, decl, opt);
398501 } else {
399- LOGGING_WARN (" Not intersted" );
502+ LOG_WARN (" Not intersted" );
503+ }
504+ } else if (is (DeclRefExpr)) {
505+ LOG_WARN (" Hit an `DeclRef`, Unhandled" );
506+ if (auto dr = node->get <DeclRefExpr>()) {
507+ auto vd = dr->getDecl ();
508+ assert (vd);
509+ return hover (unit, llvm::dyn_cast<NamedDecl>(vd), opt);
400510 }
401511 } else if (is_in_range (Attr, ObjCProtocolLoc)) {
402- LOGGING_WARN (" Hit an `Attr`" );
403- // TODO: Attr
512+ LOG_WARN (" Hit an `Attr`, Unhandled " );
513+ // TODO: Attr?
404514 } else {
405515 // Not interested
406- LOGGING_WARN (" Not interested" );
516+ LOG_WARN (" Not interested" );
407517 }
408518
409519#undef is
@@ -462,15 +572,14 @@ std::optional<Hover> hover(CompilationUnit& unit,
462572
463573 auto tokens_under_cursor = unit.spelled_tokens_touch (*loc);
464574 if (tokens_under_cursor.empty ()) {
465- LOGGING_WARN (" Cannot detect tokens" );
575+ LOG_WARN (" Cannot detect tokens" );
466576 return std::nullopt ;
467577 }
468578 auto hl_range = tokens_under_cursor.back ().range (sm).toCharRange (sm).getAsRange ();
469579 for (auto & token: tokens_under_cursor) {
470580 if (token.kind () == clang::tok::identifier) {
471581 for (auto & m: directive.macros ) {
472582 if (token.location () == m.loc ) {
473- // TODO: Found macro
474583 auto name_range = token.range (sm).toCharRange (sm).getAsRange ();
475584 auto macro_name = get_source_code (unit, name_range);
476585 macro_name.pop_back ();
@@ -481,7 +590,6 @@ std::optional<Hover> hover(CompilationUnit& unit,
481590 {m.macro ->getDefinitionLoc (),
482591 m.macro ->getDefinitionEndLoc ()});
483592 if (m.kind == MacroRef::Ref) {
484- // TODO: Expanded tokens
485593 if (auto expansion = unit.token_buffer ().expansionStartingAt (&token)) {
486594 std::string expaned_source;
487595 for (const auto & expanded_tok: expansion->Expanded ) {
@@ -507,14 +615,14 @@ std::optional<Hover> hover(CompilationUnit& unit,
507615
508616 auto tree = SelectionTree::create_right (unit, {offset, offset});
509617 if (auto node = tree.common_ancestor ()) {
510- LOGGING_WARN (" Got node: {}" , node->kind ());
618+ LOG_WARN (" Got node: {}" , node->kind ());
511619 if (auto info = hover (unit, node, opt)) {
512620 info->hl_range = to_proto_range (sm, hl_range);
513621 return info;
514622 }
515623 return std::nullopt ;
516624 } else {
517- LOGGING_WARN (" Not an ast node" );
625+ LOG_WARN (" Not an ast node" );
518626 }
519627
520628 return std::nullopt ;
0 commit comments