diff options
| author | Marc-Andre Laperle <marc-andre.laperle@ericsson.com> | 2018-02-16 21:38:15 +0000 |
|---|---|---|
| committer | Marc-Andre Laperle <marc-andre.laperle@ericsson.com> | 2018-02-16 21:38:15 +0000 |
| commit | 3e618ed8f0cead7afa8f5d48e2fd2f707b5740d2 (patch) | |
| tree | 50e907d80bfb82faf362c44165af34e254ebadb8 /clang-tools-extra/clangd/XRefs.cpp | |
| parent | 27b9ac2372e5340fe92196f47cb31ed72d367aa4 (diff) | |
| download | bcm5719-llvm-3e618ed8f0cead7afa8f5d48e2fd2f707b5740d2.tar.gz bcm5719-llvm-3e618ed8f0cead7afa8f5d48e2fd2f707b5740d2.zip | |
[clangd] Implement textDocument/hover
Summary: Implemention of textDocument/hover as described in LSP definition.
This patch adds a basic Hover implementation. When hovering a variable,
function, method or namespace, clangd will return a text containing the
declaration's scope, as well as the declaration of the hovered entity.
For example, for a variable:
Declared in class Foo::Bar
int hello = 2
For macros, the macro definition is returned.
This patch doesn't include:
- markdown support (the client I use doesn't support it yet)
- range support (optional in the Hover response)
- comments associated to variables/functions/classes
They are kept as future work to keep this patch simpler.
I added tests in XRefsTests.cpp. hover.test contains one simple
smoketest to make sure the feature works from a black box perspective.
Reviewers: malaperle, krasimir, bkramer, ilya-biryukov
Subscribers: sammccall, mgrang, klimek, rwols, ilya-biryukov, arphaman, cfe-commits
Differential Revision: https://reviews.llvm.org/D35894
Signed-off-by: Simon Marchi <simon.marchi@ericsson.com>
Signed-off-by: William Enright <william.enright@polymtl.ca>
llvm-svn: 325395
Diffstat (limited to 'clang-tools-extra/clangd/XRefs.cpp')
| -rw-r--r-- | clang-tools-extra/clangd/XRefs.cpp | 162 |
1 files changed, 154 insertions, 8 deletions
diff --git a/clang-tools-extra/clangd/XRefs.cpp b/clang-tools-extra/clangd/XRefs.cpp index 849fa8bfbb2..896588110b9 100644 --- a/clang-tools-extra/clangd/XRefs.cpp +++ b/clang-tools-extra/clangd/XRefs.cpp @@ -9,6 +9,7 @@ #include "XRefs.h" #include "Logger.h" #include "URI.h" +#include "clang/AST/DeclTemplate.h" #include "clang/Index/IndexDataConsumer.h" #include "clang/Index/IndexingAction.h" #include "llvm/Support/Path.h" @@ -31,10 +32,15 @@ const Decl* GetDefinition(const Decl* D) { return nullptr; } +struct MacroDecl { + StringRef Name; + const MacroInfo *Info; +}; + /// Finds declarations locations that a given source location refers to. class DeclarationAndMacrosFinder : public index::IndexDataConsumer { std::vector<const Decl *> Decls; - std::vector<const MacroInfo *> MacroInfos; + std::vector<MacroDecl> MacroInfos; const SourceLocation &SearchedLocation; const ASTContext &AST; Preprocessor &PP; @@ -54,10 +60,17 @@ public: return std::move(Decls); } - std::vector<const MacroInfo *> takeMacroInfos() { + std::vector<MacroDecl> takeMacroInfos() { // Don't keep the same Macro info multiple times. - std::sort(MacroInfos.begin(), MacroInfos.end()); - auto Last = std::unique(MacroInfos.begin(), MacroInfos.end()); + std::sort(MacroInfos.begin(), MacroInfos.end(), + [](const MacroDecl &Left, const MacroDecl &Right) { + return Left.Info < Right.Info; + }); + + auto Last = std::unique(MacroInfos.begin(), MacroInfos.end(), + [](const MacroDecl &Left, const MacroDecl &Right) { + return Left.Info == Right.Info; + }); MacroInfos.erase(Last, MacroInfos.end()); return std::move(MacroInfos); } @@ -111,7 +124,7 @@ private: PP.getMacroDefinitionAtLoc(IdentifierInfo, BeforeSearchedLocation); MacroInfo *MacroInf = MacroDef.getMacroInfo(); if (MacroInf) { - MacroInfos.push_back(MacroInf); + MacroInfos.push_back(MacroDecl{IdentifierInfo->getName(), MacroInf}); } } } @@ -176,8 +189,7 @@ std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos) { DeclMacrosFinder, IndexOpts); std::vector<const Decl *> Decls = DeclMacrosFinder->takeDecls(); - std::vector<const MacroInfo *> MacroInfos = - DeclMacrosFinder->takeMacroInfos(); + std::vector<MacroDecl> MacroInfos = DeclMacrosFinder->takeMacroInfos(); std::vector<Location> Result; for (auto Item : Decls) { @@ -187,7 +199,8 @@ std::vector<Location> findDefinitions(ParsedAST &AST, Position Pos) { } for (auto Item : MacroInfos) { - SourceRange SR(Item->getDefinitionLoc(), Item->getDefinitionEndLoc()); + SourceRange SR(Item.Info->getDefinitionLoc(), + Item.Info->getDefinitionEndLoc()); auto L = getDeclarationLocation(AST, SR); if (L) Result.push_back(*L); @@ -299,5 +312,138 @@ std::vector<DocumentHighlight> findDocumentHighlights(ParsedAST &AST, return DocHighlightsFinder->takeHighlights(); } +static PrintingPolicy PrintingPolicyForDecls(PrintingPolicy Base) { + PrintingPolicy Policy(Base); + + Policy.AnonymousTagLocations = false; + Policy.TerseOutput = true; + Policy.PolishForDeclaration = true; + Policy.ConstantsAsWritten = true; + Policy.SuppressTagKeyword = false; + + return Policy; +} + +/// Return a string representation (e.g. "class MyNamespace::MyClass") of +/// the type declaration \p TD. +static std::string TypeDeclToString(const TypeDecl *TD) { + QualType Type = TD->getASTContext().getTypeDeclType(TD); + + PrintingPolicy Policy = + PrintingPolicyForDecls(TD->getASTContext().getPrintingPolicy()); + + std::string Name; + llvm::raw_string_ostream Stream(Name); + Type.print(Stream, Policy); + + return Stream.str(); +} + +/// Return a string representation (e.g. "namespace ns1::ns2") of +/// the named declaration \p ND. +static std::string NamedDeclQualifiedName(const NamedDecl *ND, + StringRef Prefix) { + PrintingPolicy Policy = + PrintingPolicyForDecls(ND->getASTContext().getPrintingPolicy()); + + std::string Name; + llvm::raw_string_ostream Stream(Name); + Stream << Prefix << ' '; + ND->printQualifiedName(Stream, Policy); + + return Stream.str(); +} + +/// Given a declaration \p D, return a human-readable string representing the +/// scope in which it is declared. If the declaration is in the global scope, +/// return the string "global namespace". +static llvm::Optional<std::string> getScopeName(const Decl *D) { + const DeclContext *DC = D->getDeclContext(); + + if (const TranslationUnitDecl *TUD = dyn_cast<TranslationUnitDecl>(DC)) + return std::string("global namespace"); + + if (const TypeDecl *TD = dyn_cast<TypeDecl>(DC)) + return TypeDeclToString(TD); + else if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC)) + return NamedDeclQualifiedName(ND, "namespace"); + else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC)) + return NamedDeclQualifiedName(FD, "function"); + + return llvm::None; +} + +/// Generate a \p Hover object given the declaration \p D. +static Hover getHoverContents(const Decl *D) { + Hover H; + llvm::Optional<std::string> NamedScope = getScopeName(D); + + // Generate the "Declared in" section. + if (NamedScope) { + assert(!NamedScope->empty()); + + H.Contents.Value += "Declared in "; + H.Contents.Value += *NamedScope; + H.Contents.Value += "\n\n"; + } + + // We want to include the template in the Hover. + if (TemplateDecl *TD = D->getDescribedTemplate()) + D = TD; + + std::string DeclText; + llvm::raw_string_ostream OS(DeclText); + + PrintingPolicy Policy = + PrintingPolicyForDecls(D->getASTContext().getPrintingPolicy()); + + D->print(OS, Policy); + + OS.flush(); + + H.Contents.Value += DeclText; + return H; +} + +/// Generate a \p Hover object given the macro \p MacroInf. +static Hover getHoverContents(StringRef MacroName) { + Hover H; + + H.Contents.Value = "#define "; + H.Contents.Value += MacroName; + + return H; +} + +Hover getHover(ParsedAST &AST, Position Pos) { + const SourceManager &SourceMgr = AST.getASTContext().getSourceManager(); + const FileEntry *FE = SourceMgr.getFileEntryForID(SourceMgr.getMainFileID()); + if (FE == nullptr) + return Hover(); + + SourceLocation SourceLocationBeg = getBeginningOfIdentifier(AST, Pos, FE); + auto DeclMacrosFinder = std::make_shared<DeclarationAndMacrosFinder>( + llvm::errs(), SourceLocationBeg, AST.getASTContext(), + AST.getPreprocessor()); + + index::IndexingOptions IndexOpts; + IndexOpts.SystemSymbolFilter = + index::IndexingOptions::SystemSymbolFilterKind::All; + IndexOpts.IndexFunctionLocals = true; + + indexTopLevelDecls(AST.getASTContext(), AST.getTopLevelDecls(), + DeclMacrosFinder, IndexOpts); + + std::vector<MacroDecl> Macros = DeclMacrosFinder->takeMacroInfos(); + if (!Macros.empty()) + return getHoverContents(Macros[0].Name); + + std::vector<const Decl *> Decls = DeclMacrosFinder->takeDecls(); + if (!Decls.empty()) + return getHoverContents(Decls[0]); + + return Hover(); +} + } // namespace clangd } // namespace clang |

