1+ #include " Feature/Hover.h"
12#include " AST/Selection.h"
23#include " AST/Semantic.h"
34#include " AST/Utility.h"
45#include " Compiler/CompilationUnit.h"
56#include " Index/Shared.h"
67#include " Support/Compare.h"
78#include " Support/Ranges.h"
8- #include " Feature/Hover.h"
99#include " Support/Logging.h"
10+ #include " Support/Struct.h"
11+ #include " Support/Doxygen.h"
1012#include " llvm/Support/raw_ostream.h"
1113#include " clang/Lex/Lexer.h"
1214#include " clang/AST/ASTTypeTraits.h"
@@ -15,6 +17,16 @@ namespace clice::feature {
1517
1618namespace {
1719
20+ static auto to_proto_range (clang::SourceManager& sm, clang::SourceRange range) -> proto::Range {
21+ auto range_b = range.getBegin ();
22+ auto range_e = range.getEnd ();
23+ auto begin = proto::Position{sm.getSpellingLineNumber (range_b) - 1 ,
24+ sm.getSpellingColumnNumber (range_b) - 1 };
25+ auto end = proto::Position{sm.getSpellingLineNumber (range_e) - 1 ,
26+ sm.getSpellingColumnNumber (range_e) - 1 };
27+ return {begin, end};
28+ };
29+
1830static std::vector<HoverItem> get_hover_items (CompilationUnit& unit,
1931 const clang::NamedDecl* decl,
2032 const config::HoverOptions& opt) {
@@ -134,6 +146,7 @@ static std::optional<Hover> hover(CompilationUnit& unit,
134146 clice::logging::warn (" Hit a typeloc" );
135147 typeloc->dump (llvm::errs (), unit.context ());
136148 auto ty = typeloc->getType ();
149+ // FIXME: AutoTypeLoc / DecltypeTypeLoc
137150 return Hover{.kind = SymbolKind::Type, .name = ty.getAsString ()};
138151}
139152
@@ -150,6 +163,8 @@ static std::optional<Hover> hover(CompilationUnit& unit,
150163 kind_flag_def (Decl);
151164 kind_flag_def (Stmt);
152165 kind_flag_def (Type);
166+ kind_flag_def (AutoTypeLoc);
167+ kind_flag_def (DecltypeTypeLoc);
153168 kind_flag_def (OMPClause);
154169 kind_flag_def (TemplateArgument);
155170 kind_flag_def (TemplateArgumentLoc);
@@ -169,6 +184,15 @@ static std::optional<Hover> hover(CompilationUnit& unit,
169184 } else if (is_in_range (QualType, TypeLoc)) {
170185 // Typeloc
171186 clice::logging::warn (" Hit a `TypeLoc`" );
187+ // auto and decltype is specially processed
188+ if (is (AutoTypeLoc)) {
189+ clice::logging::warn (" Hit a `AutoTypeLoc`" );
190+ return std::nullopt ;
191+ }
192+ if (is (DecltypeTypeLoc)) {
193+ clice::logging::warn (" Hit a `DecltypeTypeLoc`" );
194+ return std::nullopt ;
195+ }
172196 if (auto typeloc = node->get <clang::TypeLoc>()) {
173197 return hover (unit, typeloc, opt);
174198 }
@@ -202,24 +226,29 @@ std::optional<Hover> hover(CompilationUnit& unit,
202226 const config::HoverOptions& opt) {
203227 auto & sm = unit.context ().getSourceManager ();
204228
205- auto src_loc_in_main_file = [&sm](uint32_t off) -> std::optional<clang::SourceLocation> {
206- return sm.getLocForStartOfFile (sm.getMainFileID ()).getLocWithOffset (off);
229+ auto src_loc_in_main_file = [&sm, &unit](uint32_t off) -> std::optional<clang::SourceLocation> {
230+ auto fid = sm.getMainFileID ();
231+ auto buf = sm.getBufferData (fid);
232+ if (off > buf.size ()) {
233+ return std::nullopt ;
234+ }
235+ return unit.create_location (fid, off);
207236 };
208237
238+ // SpellLoc
209239 auto loc = src_loc_in_main_file (offset);
210240 if (!loc.has_value ()) {
211- clice::logging::warn (" Invalid file offset, cannot get location" );
212241 return std::nullopt ;
213242 }
214243
215244 // Handle includsions
216245 bool linenr_invalid = false ;
217246 unsigned linenr = sm.getPresumedLineNumber (*loc, &linenr_invalid);
218247 if (linenr_invalid) {
219- clice::logging::warn (" Invalid location, cannot get linenr" );
220248 return std::nullopt ;
221249 }
222- clice::logging::warn (" Hover at linenr: {}" , linenr);
250+
251+ // FIXME: Cannot handle pch: cannot find records when compiled with pch
223252 auto directive = unit.directives ()[sm.getMainFileID ()];
224253 for (auto & inclusion: directive.includes ) {
225254 bool invalid = false ;
@@ -237,9 +266,59 @@ std::optional<Hover> hover(CompilationUnit& unit,
237266 }
238267 }
239268
269+ // clice::logging::warn("Hit a macro");
270+ auto tokens_under_cursor = unit.spelled_tokens_touch (*loc);
271+ if (tokens_under_cursor.empty ()) {
272+ clice::logging::warn (" Cannot detect tokens" );
273+ return std::nullopt ;
274+ }
275+ auto hl_range = tokens_under_cursor.back ().range (sm).toCharRange (sm).getAsRange ();
276+ for (auto & token: tokens_under_cursor) {
277+ if (token.kind () == clang::tok::identifier) {
278+ for (auto & m: directive.macros ) {
279+ if (token.location () == m.loc ) {
280+ // TODO: Found macro
281+ auto name_range = token.range (sm).toCharRange (sm).getAsRange ();
282+ auto macro_name = get_source_code (unit, name_range);
283+ macro_name.pop_back ();
284+ Hover hi;
285+ hi.kind = SymbolKind::Macro;
286+ hi.name = macro_name;
287+ auto source = " #define " + get_source_code (unit,
288+ {m.macro ->getDefinitionLoc (),
289+ m.macro ->getDefinitionEndLoc ()});
290+ if (m.kind == MacroRef::Ref) {
291+ // TODO: Expanded tokens
292+ if (auto expansion = unit.token_buffer ().expansionStartingAt (&token)) {
293+ std::string expaned_source;
294+ for (const auto & expanded_tok: expansion->Expanded ) {
295+ expaned_source += expanded_tok.text (sm);
296+ // TODO: Format code?
297+ // expaned_source += ' ';
298+ // TODO: Config field: expansion display size
299+ }
300+ if (!expaned_source.empty ()) {
301+ source += " \n\n // Expands to:\n " ;
302+ source += expaned_source;
303+ source += ' \n ' ;
304+ }
305+ }
306+ }
307+ hi.source = source;
308+ hi.hl_range = to_proto_range (sm, hl_range);
309+ return hi;
310+ }
311+ }
312+ }
313+ }
314+
240315 auto tree = SelectionTree::create_right (unit, {offset, offset});
241316 if (auto node = tree.common_ancestor ()) {
242- return hover (unit, node, opt);
317+ if (auto info = hover (unit, node, opt)) {
318+ info->hl_range = to_proto_range (sm, hl_range);
319+ return info;
320+ }
321+ return std::nullopt ;
243322 } else {
244323 clice::logging::warn (" Not an ast node" );
245324 }
@@ -259,15 +338,20 @@ std::optional<std::string> Hover::get_item_content(HoverItem::HoverKind kind) {
259338std::optional<std::string> Hover::display (config::HoverOptions opt) {
260339 std::string content;
261340 llvm::raw_string_ostream os (content);
341+ // TODO: generate markdown
262342 os << std::format (" {}: {}\n " , this ->kind .name (), this ->name );
263343 os << std::format (" Contains {} items\n " , this ->items .size ());
264344 for (auto & hi: this ->items ) {
265345 os << std::format (" - {}: {}\n " , clice::refl::enum_name (hi.kind ), hi.value );
266346 }
267- os << " ---\n " ;
268- os << " Document:\n ```text\n " << this ->document << " \n ```\n " ;
269- os << " ---\n " ;
270- os << " Source code:\n ```cpp\n " << this ->source << " \n ```\n " ;
347+ if (this ->document ) {
348+ os << " ---\n " ;
349+ os << " Document:\n ```text\n " << *this ->document << " \n ```\n " ;
350+ }
351+ if (!this ->source .empty ()) {
352+ os << " ---\n " ;
353+ os << " Source code:\n ```cpp\n " << this ->source << " \n ```\n " ;
354+ }
271355 return os.str ();
272356}
273357
0 commit comments