25
25
#include " clang/AST/PrettyPrinter.h"
26
26
#include " clang/Index/IndexSymbol.h"
27
27
#include " llvm/ADT/STLExtras.h"
28
- #include " llvm/ADT/iterator_range.h"
29
- #include " llvm/Support/Casting.h"
28
+ #include " llvm/ADT/SmallVector.h"
29
+ #include " llvm/ADT/StringExtras.h"
30
+ #include " llvm/ADT/StringRef.h"
30
31
#include " llvm/Support/raw_ostream.h"
32
+ #include < string>
31
33
32
34
namespace clang {
33
35
namespace clangd {
@@ -224,8 +226,8 @@ void enhanceFromIndex(HoverInfo &Hover, const NamedDecl &ND,
224
226
225
227
// Populates Type, ReturnType, and Parameters for function-like decls.
226
228
void fillFunctionTypeAndParams (HoverInfo &HI, const Decl *D,
227
- const FunctionDecl *FD,
228
- const PrintingPolicy &Policy) {
229
+ const FunctionDecl *FD,
230
+ const PrintingPolicy &Policy) {
229
231
HI.Parameters .emplace ();
230
232
for (const ParmVarDecl *PVD : FD->parameters ()) {
231
233
HI.Parameters ->emplace_back ();
@@ -250,11 +252,11 @@ void fillFunctionTypeAndParams(HoverInfo &HI, const Decl *D,
250
252
}
251
253
}
252
254
253
- if (const auto * CCD = llvm::dyn_cast<CXXConstructorDecl>(FD)) {
255
+ if (const auto * CCD = llvm::dyn_cast<CXXConstructorDecl>(FD)) {
254
256
// Constructor's "return type" is the class type.
255
257
HI.ReturnType = declaredType (CCD->getParent ()).getAsString (Policy);
256
258
// Don't provide any type for the constructor itself.
257
- } else if (llvm::isa<CXXDestructorDecl>(FD)){
259
+ } else if (llvm::isa<CXXDestructorDecl>(FD)) {
258
260
HI.ReturnType = " void" ;
259
261
} else {
260
262
HI.ReturnType = FD->getReturnType ().getAsString (Policy);
@@ -309,7 +311,7 @@ llvm::Optional<std::string> printExprValue(const SelectionTree::Node *N,
309
311
}
310
312
311
313
// / Generate a \p Hover object given the declaration \p D.
312
- HoverInfo getHoverContents (const Decl *D, const SymbolIndex *Index) {
314
+ HoverInfo getHoverContents (const NamedDecl *D, const SymbolIndex *Index) {
313
315
HoverInfo HI;
314
316
const ASTContext &Ctx = D->getASTContext ();
315
317
@@ -321,12 +323,10 @@ HoverInfo getHoverContents(const Decl *D, const SymbolIndex *Index) {
321
323
HI.LocalScope .append (" ::" );
322
324
323
325
PrintingPolicy Policy = printingPolicyForDecls (Ctx.getPrintingPolicy ());
324
- if (const NamedDecl *ND = llvm::dyn_cast<NamedDecl>(D)) {
325
- HI.Name = printName (Ctx, *ND);
326
- ND = getDeclForComment (ND);
327
- HI.Documentation = getDeclComment (Ctx, *ND);
328
- enhanceFromIndex (HI, *ND, Index);
329
- }
326
+ HI.Name = printName (Ctx, *D);
327
+ const auto *CommentD = getDeclForComment (D);
328
+ HI.Documentation = getDeclComment (Ctx, *CommentD);
329
+ enhanceFromIndex (HI, *CommentD, Index);
330
330
331
331
HI.Kind = index::getSymbolInfo (D).Kind ;
332
332
@@ -460,34 +460,70 @@ llvm::Optional<HoverInfo> getHover(ParsedAST &AST, Position Pos,
460
460
tooling::applyAllReplacements (HI->Definition , Replacements))
461
461
HI->Definition = *Formatted;
462
462
463
- HI->SymRange = getTokenRange (AST.getSourceManager (),
464
- AST. getLangOpts (), SourceLocationBeg);
463
+ HI->SymRange = getTokenRange (AST.getSourceManager (), AST. getLangOpts (),
464
+ SourceLocationBeg);
465
465
return HI;
466
466
}
467
467
468
468
markup::Document HoverInfo::present () const {
469
469
markup::Document Output;
470
- if (NamespaceScope) {
471
- auto &P = Output.addParagraph ();
472
- P.appendText (" Declared in" );
473
- // Drop trailing "::".
474
- if (!LocalScope.empty ())
475
- P.appendCode (llvm::StringRef (LocalScope).drop_back (2 ));
476
- else if (NamespaceScope->empty ())
477
- P.appendCode (" global namespace" );
478
- else
479
- P.appendCode (llvm::StringRef (*NamespaceScope).drop_back (2 ));
470
+ // Header contains a text of the form:
471
+ // variable `var` : `int`
472
+ //
473
+ // class `X`
474
+ //
475
+ // function `foo` → `int`
476
+ markup::Paragraph &Header = Output.addParagraph ();
477
+ Header.appendText (index::getSymbolKindString (Kind));
478
+ assert (!Name.empty () && " hover triggered on a nameless symbol" );
479
+ Header.appendCode (Name);
480
+ if (ReturnType) {
481
+ Header.appendText (" →" );
482
+ Header.appendCode (*ReturnType);
483
+ } else if (Type) {
484
+ Header.appendText (" :" );
485
+ Header.appendCode (*Type);
480
486
}
481
487
482
- if (!Definition.empty ()) {
483
- Output.addCodeBlock (Definition);
484
- } else {
485
- // Builtin types
486
- Output.addCodeBlock (Name);
488
+ // For functions we display signature in a list form, e.g.:
489
+ // - `bool param1`
490
+ // - `int param2 = 5`
491
+ if (Parameters && !Parameters->empty ()) {
492
+ markup::BulletList &L = Output.addBulletList ();
493
+ for (const auto &Param : *Parameters) {
494
+ std::string Buffer;
495
+ llvm::raw_string_ostream OS (Buffer);
496
+ OS << Param;
497
+ L.addItem ().addParagraph ().appendCode (std::move (OS.str ()));
498
+ }
499
+ }
500
+
501
+ if (Value) {
502
+ markup::Paragraph &P = Output.addParagraph ();
503
+ P.appendText (" Value =" );
504
+ P.appendCode (*Value);
487
505
}
488
506
489
507
if (!Documentation.empty ())
490
508
Output.addParagraph ().appendText (Documentation);
509
+
510
+ if (!Definition.empty ()) {
511
+ std::string ScopeComment;
512
+ // Drop trailing "::".
513
+ if (!LocalScope.empty ()) {
514
+ // Container name, e.g. class, method, function.
515
+ // We might want to propogate some info about container type to print
516
+ // function foo, class X, method X::bar, etc.
517
+ ScopeComment =
518
+ " // In " + llvm::StringRef (LocalScope).rtrim (' :' ).str () + ' \n ' ;
519
+ } else if (NamespaceScope && !NamespaceScope->empty ()) {
520
+ ScopeComment = " // In namespace " +
521
+ llvm::StringRef (*NamespaceScope).rtrim (' :' ).str () + ' \n ' ;
522
+ }
523
+ // Note that we don't print anything for global namespace, to not annoy
524
+ // non-c++ projects or projects that are not making use of namespaces.
525
+ Output.addCodeBlock (ScopeComment + Definition);
526
+ }
491
527
return Output;
492
528
}
493
529
0 commit comments