Skip to content

Commit 5d0cb0a

Browse files
committed
Refactor ut, misc patch on type deducing
1 parent 746018b commit 5d0cb0a

File tree

4 files changed

+363
-662
lines changed

4 files changed

+363
-662
lines changed

include/Feature/Hover.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ struct HoverOptions {
2222
namespace clice::feature {
2323

2424
struct HoverItem {
25+
// NOTE: Use a set of drieved classes?
2526
enum class HoverKind : uint8_t {
2627
/// The typename of a variable or a type alias.
2728
Type,

src/Feature/Hover.cpp

Lines changed: 149 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,13 @@
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+
1116
namespace clice::feature {
1217

1318
namespace {
@@ -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+
2599
static 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,
72155
static 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

78162
static 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-
112184
static 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?
300372
static 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

Comments
 (0)