20 #include "clang/AST/ASTContext.h" 21 #include "clang/AST/ASTTypeTraits.h" 22 #include "clang/AST/Decl.h" 23 #include "clang/AST/DeclBase.h" 24 #include "clang/AST/DeclTemplate.h" 25 #include "clang/AST/Expr.h" 26 #include "clang/AST/ExprCXX.h" 27 #include "clang/AST/PrettyPrinter.h" 28 #include "clang/AST/Type.h" 29 #include "clang/Basic/Specifiers.h" 30 #include "clang/Index/IndexSymbol.h" 31 #include "llvm/ADT/None.h" 32 #include "llvm/ADT/Optional.h" 33 #include "llvm/ADT/STLExtras.h" 34 #include "llvm/ADT/SmallVector.h" 35 #include "llvm/ADT/StringExtras.h" 36 #include "llvm/ADT/StringRef.h" 37 #include "llvm/Support/Casting.h" 38 #include "llvm/Support/ErrorHandling.h" 39 #include "llvm/Support/raw_ostream.h" 46 PrintingPolicy printingPolicyForDecls(PrintingPolicy
Base) {
47 PrintingPolicy Policy(Base);
49 Policy.AnonymousTagLocations =
false;
50 Policy.TerseOutput =
true;
51 Policy.PolishForDeclaration =
true;
52 Policy.ConstantsAsWritten =
true;
53 Policy.SuppressTagKeyword =
false;
61 std::string getLocalScope(
const Decl *D) {
62 std::vector<std::string> Scopes;
63 const DeclContext *DC = D->getDeclContext();
64 auto GetName = [](
const TypeDecl *D) {
65 if (!D->getDeclName().isEmpty()) {
66 PrintingPolicy Policy = D->getASTContext().getPrintingPolicy();
67 Policy.SuppressScope =
true;
70 if (
auto RD = dyn_cast<RecordDecl>(D))
71 return (
"(anonymous " + RD->getKindName() +
")").str();
72 return std::string(
"");
75 if (
const TypeDecl *TD = dyn_cast<TypeDecl>(DC))
76 Scopes.push_back(GetName(TD));
77 else if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
78 Scopes.push_back(FD->getNameAsString());
82 return llvm::join(llvm::reverse(Scopes),
"::");
87 std::string getNamespaceScope(
const Decl *D) {
88 const DeclContext *DC = D->getDeclContext();
90 if (
const TagDecl *TD = dyn_cast<TagDecl>(DC))
91 return getNamespaceScope(TD);
92 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
93 return getNamespaceScope(FD);
94 if (
const NamespaceDecl *NSD = dyn_cast<NamespaceDecl>(DC)) {
96 if (NSD->isInline() || NSD->isAnonymousNamespace())
97 return getNamespaceScope(NSD);
99 if (
const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
105 std::string printDefinition(
const Decl *D) {
107 llvm::raw_string_ostream OS(Definition);
108 PrintingPolicy Policy =
109 printingPolicyForDecls(D->getASTContext().getPrintingPolicy());
110 Policy.IncludeTagDefinition =
false;
111 Policy.SuppressTemplateArgsInCXXConstructors =
true;
112 Policy.SuppressTagKeyword =
true;
113 D->print(OS, Policy);
118 void printParams(llvm::raw_ostream &OS,
119 const std::vector<HoverInfo::Param> &Params) {
120 for (
size_t I = 0,
E = Params.size(); I !=
E; ++I) {
127 std::string
printType(QualType QT,
const PrintingPolicy &Policy) {
131 while (
const auto *DT = QT->getAs<DecltypeType>())
132 QT = DT->getUnderlyingType();
133 return QT.getAsString(Policy);
136 std::vector<HoverInfo::Param>
137 fetchTemplateParameters(
const TemplateParameterList *Params,
138 const PrintingPolicy &
PP) {
140 std::vector<HoverInfo::Param> TempParameters;
142 for (
const Decl *Param : *Params) {
144 if (
const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
145 P.Type = TTP->wasDeclaredWithTypename() ?
"typename" :
"class";
146 if (TTP->isParameterPack())
149 if (!TTP->getName().empty())
150 P.Name = TTP->getNameAsString();
151 if (TTP->hasDefaultArgument())
152 P.Default = TTP->getDefaultArgument().getAsString(PP);
153 }
else if (
const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
154 if (IdentifierInfo *II = NTTP->getIdentifier())
155 P.Name = II->getName().str();
158 if (NTTP->isParameterPack())
161 if (NTTP->hasDefaultArgument()) {
163 llvm::raw_string_ostream Out(*P.Default);
164 NTTP->getDefaultArgument()->printPretty(Out,
nullptr, PP);
166 }
else if (
const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {
168 llvm::raw_string_ostream OS(*P.Type);
171 fetchTemplateParameters(TTPD->getTemplateParameters(),
PP));
175 if (!TTPD->getName().empty())
176 P.Name = TTPD->getNameAsString();
177 if (TTPD->hasDefaultArgument()) {
179 llvm::raw_string_ostream Out(*P.Default);
180 TTPD->getDefaultArgument().getArgument().print(PP, Out);
183 TempParameters.push_back(std::move(P));
186 return TempParameters;
189 const FunctionDecl *getUnderlyingFunction(
const Decl *D) {
191 if (
const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) {
192 auto QT = VD->getType();
194 while (!QT->getPointeeType().isNull())
195 QT = QT->getPointeeType();
197 if (
const auto *CD = QT->getAsCXXRecordDecl())
198 return CD->getLambdaCallOperator();
203 return D->getAsFunction();
208 const NamedDecl *getDeclForComment(
const NamedDecl *D) {
209 if (
const auto *TSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D)) {
212 if (TSD->getTemplateSpecializationKind() == TSK_Undeclared)
213 return TSD->getSpecializedTemplate();
214 if (
const auto *TIP = TSD->getTemplateInstantiationPattern())
217 if (
const auto *TSD = llvm::dyn_cast<VarTemplateSpecializationDecl>(D)) {
218 if (TSD->getTemplateSpecializationKind() == TSK_Undeclared)
219 return TSD->getSpecializedTemplate();
220 if (
const auto *TIP = TSD->getTemplateInstantiationPattern())
223 if (
const auto *FD = D->getAsFunction())
224 if (
const auto *TIP = FD->getTemplateInstantiationPattern())
230 void enhanceFromIndex(HoverInfo &Hover,
const NamedDecl &ND,
231 const SymbolIndex *
Index) {
232 assert(&ND == getDeclForComment(&ND));
234 if (!Hover.Documentation.empty() || !
Index)
240 SymbolCollector::Options(),
249 Req, [&](
const Symbol &S) { Hover.Documentation = S.Documentation; });
253 void fillFunctionTypeAndParams(HoverInfo &HI,
const Decl *D,
254 const FunctionDecl *FD,
255 const PrintingPolicy &Policy) {
256 HI.Parameters.emplace();
257 for (
const ParmVarDecl *PVD : FD->parameters()) {
258 HI.Parameters->emplace_back();
259 auto &P = HI.Parameters->back();
260 if (!PVD->getType().isNull()) {
261 P.Type =
printType(PVD->getType(), Policy);
264 llvm::raw_string_ostream OS(Param);
267 elog(
"Got param with null type: {0}", Param);
269 if (!PVD->getName().empty())
270 P.Name = PVD->getNameAsString();
271 if (PVD->hasDefaultArg()) {
273 llvm::raw_string_ostream Out(*P.Default);
274 PVD->getDefaultArg()->printPretty(Out,
nullptr, Policy);
280 const auto NK = FD->getDeclName().getNameKind();
281 if (NK == DeclarationName::CXXConstructorName ||
282 NK == DeclarationName::CXXDestructorName ||
283 NK == DeclarationName::CXXConversionFunctionName)
286 HI.ReturnType =
printType(FD->getReturnType(), Policy);
287 QualType QT = FD->getType();
288 if (
const VarDecl *VD = llvm::dyn_cast<VarDecl>(D))
289 QT = VD->getType().getDesugaredType(D->getASTContext());
294 llvm::Optional<std::string> printExprValue(
const Expr *
E,
295 const ASTContext &
Ctx) {
299 QualType T = E->getType();
300 if (T.isNull() || T->isFunctionType() || T->isFunctionPointerType() ||
301 T->isFunctionReferenceType())
304 if (E->isValueDependent() || !E->EvaluateAsRValue(Constant, Ctx))
308 if (T->isEnumeralType() && Constant.Val.getInt().getMinSignedBits() <= 64) {
310 int64_t Val = Constant.Val.getInt().getExtValue();
311 for (
const EnumConstantDecl *ECD :
312 T->castAs<EnumType>()->getDecl()->enumerators())
313 if (ECD->getInitVal() == Val)
314 return llvm::formatv(
"{0} ({1})", ECD->getNameAsString(), Val).str();
316 return Constant.Val.getAsString(Ctx, E->getType());
319 llvm::Optional<std::string> printExprValue(
const SelectionTree::Node *N,
320 const ASTContext &Ctx) {
321 for (; N; N = N->Parent) {
323 if (
const Expr *E = N->ASTNode.get<Expr>()) {
324 if (
auto Val = printExprValue(E, Ctx))
326 }
else if (N->ASTNode.get<
Decl>() || N->ASTNode.get<Stmt>()) {
336 HoverInfo getHoverContents(
const NamedDecl *D,
const SymbolIndex *Index) {
338 const ASTContext &Ctx = D->getASTContext();
340 HI.NamespaceScope = getNamespaceScope(D);
341 if (!HI.NamespaceScope->empty())
342 HI.NamespaceScope->append(
"::");
343 HI.LocalScope = getLocalScope(D);
344 if (!HI.LocalScope.empty())
345 HI.LocalScope.append(
"::");
347 PrintingPolicy Policy = printingPolicyForDecls(Ctx.getPrintingPolicy());
349 const auto *CommentD = getDeclForComment(D);
351 enhanceFromIndex(HI, *CommentD, Index);
356 if (
const TemplateDecl *TD = D->getDescribedTemplate()) {
357 HI.TemplateParameters =
358 fetchTemplateParameters(TD->getTemplateParameters(), Policy);
360 }
else if (
const FunctionDecl *FD = D->getAsFunction()) {
361 if (
const auto *FTD = FD->getDescribedTemplate()) {
362 HI.TemplateParameters =
363 fetchTemplateParameters(FTD->getTemplateParameters(), Policy);
369 if (
const FunctionDecl *FD = getUnderlyingFunction(D))
370 fillFunctionTypeAndParams(HI, D, FD, Policy);
371 else if (
const auto *VD = dyn_cast<ValueDecl>(D))
372 HI.Type =
printType(VD->getType(), Policy);
375 if (
const auto *Var = dyn_cast<VarDecl>(D)) {
376 if (
const Expr *Init = Var->getInit())
377 HI.Value = printExprValue(Init, Ctx);
378 }
else if (
const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
380 if (!ECD->getType()->isDependentType())
381 HI.Value = ECD->getInitVal().toString(10);
384 HI.Definition = printDefinition(D);
389 HoverInfo getHoverContents(QualType T, ASTContext &ASTCtx,
390 const SymbolIndex *Index) {
393 if (
const auto *D = T->getAsTagDecl()) {
397 const auto *CommentD = getDeclForComment(D);
399 enhanceFromIndex(HI, *CommentD, Index);
402 auto Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy());
403 Policy.SuppressTagKeyword =
true;
404 HI.Name = T.getAsString(Policy);
410 HoverInfo getHoverContents(
const DefinedMacro &Macro, ParsedAST &AST) {
412 SourceManager &SM = AST.getSourceManager();
413 HI.Name = Macro.Name;
414 HI.Kind = index::SymbolKind::Macro;
419 SourceLocation StartLoc = Macro.Info->getDefinitionLoc();
420 SourceLocation EndLoc = Macro.Info->getDefinitionEndLoc();
421 if (EndLoc.isValid()) {
422 EndLoc = Lexer::getLocForEndOfToken(EndLoc, 0, SM, AST.getLangOpts());
424 StringRef Buffer = SM.getBufferData(SM.getFileID(StartLoc), &Invalid);
426 unsigned StartOffset = SM.getFileOffset(StartLoc);
427 unsigned EndOffset = SM.getFileOffset(EndLoc);
428 if (EndOffset <= Buffer.size() && StartOffset < EndOffset)
430 (
"#define " + Buffer.substr(StartOffset, EndOffset - StartOffset))
437 bool isLiteral(
const Expr *E) {
440 return llvm::isa<CharacterLiteral>(
E) || llvm::isa<CompoundLiteralExpr>(E) ||
441 llvm::isa<CXXBoolLiteralExpr>(
E) ||
442 llvm::isa<CXXNullPtrLiteralExpr>(E) ||
443 llvm::isa<FixedPointLiteral>(
E) || llvm::isa<FloatingLiteral>(E) ||
444 llvm::isa<ImaginaryLiteral>(
E) || llvm::isa<IntegerLiteral>(E) ||
445 llvm::isa<StringLiteral>(
E) || llvm::isa<UserDefinedLiteral>(E);
448 llvm::StringLiteral getNameForExpr(
const Expr *E) {
455 llvm::Optional<HoverInfo> getHoverContents(
const Expr *E, ParsedAST &AST) {
464 if (
auto Val = printExprValue(E, AST.getASTContext())) {
466 printingPolicyForDecls(AST.getASTContext().getPrintingPolicy());
467 Policy.SuppressTagKeyword =
true;
468 HI.Type =
printType(E->getType(), Policy);
470 HI.Name = getNameForExpr(E);
481 llvm::Optional<HoverInfo> HI;
482 SourceLocation SourceLocationBeg = SM.getMacroArgExpandedLocation(
488 HI = getHoverContents(*M, AST);
492 llvm::consumeError(
Offset.takeError());
496 std::vector<const Decl *> Result;
499 if (!
Decls.empty()) {
504 }
else if (
const Expr *E = N->ASTNode.get<Expr>()) {
505 HI = getHoverContents(E, AST);
515 auto Replacements = format::reformat(
518 tooling::applyAllReplacements(HI->Definition, Replacements))
519 HI->Definition = *Formatted;
543 assert(!
Name.empty() &&
"hover triggered on a nameless symbol");
562 llvm::raw_string_ostream OS(Buffer);
580 if (!Definition.empty()) {
582 std::string ScopeComment;
589 "// In " + llvm::StringRef(
LocalScope).rtrim(
':').str() +
'\n';
591 ScopeComment =
"// In namespace " +
592 llvm::StringRef(*NamespaceScope).rtrim(
':').str() +
'\n';
603 std::vector<llvm::StringRef> Output;
605 Output.push_back(*P.
Type);
607 Output.push_back(*P.
Name);
std::string printName(const ASTContext &Ctx, const NamedDecl &ND)
Prints unqualified name of the decl for the purpose of displaying it to the user. ...
const FunctionDecl * Decl
std::string printQualifiedName(const NamedDecl &ND)
Returns the qualified name of ND.
Paragraph & appendCode(std::string Code)
Append inline code, this translates to the ` block in markdown.
llvm::Optional< QualType > getDeducedType(ASTContext &ASTCtx, SourceLocation Loc)
Retrieves the deduced type at a given location (auto, decltype).
const LangOptions & getLangOpts() const
llvm::Optional< SymbolID > getSymbolID(const Decl *D)
Gets the symbol ID for a declaration, if possible.
Preprocessor & getPreprocessor()
Interface for symbol indexes that can be used for searching or matching symbols among a set of symbol...
llvm::Optional< std::string > Name
None for unnamed parameters.
SourceLocation getBeginningOfIdentifier(const Position &Pos, const SourceManager &SM, const LangOptions &LangOpts)
Get the beginning SourceLocation at a specified Pos in the main file.
llvm::Optional< std::string > Type
Pretty-printed variable type.
Documents should not be synced at all.
llvm::Optional< std::vector< Param > > Parameters
Set for functions, lambdas and macros with parameters.
class Document & addItem()
void elog(const char *Fmt, Ts &&... Vals)
This declaration is an alias that was referred to.
const syntax::TokenBuffer & getTokens() const
Tokens recorded while parsing the main file.
std::string printType(const QualType QT, const DeclContext &CurContext)
Returns a QualType as string.
ASTContext & getASTContext()
Note that the returned ast will not contain decls from the preamble that were not deserialized during...
Represents parameters of a function, a template or a macro.
llvm::Optional< std::string > Type
The pretty-printed parameter type, e.g.
std::vector< SymbolDetails > getSymbolInfo(ParsedAST &AST, Position Pos)
Get info about symbols at Pos.
std::string Name
Name of the symbol, does not contain any "::".
llvm::Optional< HoverInfo > getHover(ParsedAST &AST, Position Pos, format::FormatStyle Style, const SymbolIndex *Index)
Get the hover information when hovering at Pos.
llvm::Expected< size_t > positionToOffset(llvm::StringRef Code, Position P, bool AllowColumnsBeyondLineLength)
Turn a [line, column] pair into an offset in Code.
void addCodeBlock(std::string Code, std::string Language="cpp")
Adds a block of code.
llvm::SmallVector< const NamedDecl *, 1 > explicitReferenceTargets(DynTypedNode N, DeclRelationSet Mask)
llvm::Optional< std::string > Default
None if no default is provided.
QualType declaredType(const TypeDecl *D)
Paragraph & appendText(std::string Text)
Append plain text to the end of the string.
llvm::Optional< Range > getTokenRange(const SourceManager &SM, const LangOptions &LangOpts, SourceLocation TokLoc)
Returns the taken range at TokLoc.
A format-agnostic representation for structured text.
std::string LocalScope
Remaining named contexts in symbol's qualified name, empty string means symbol is not local...
llvm::Optional< std::string > NamespaceScope
For a variable named Bar, declared in clang::clangd::Foo::getFoo the following fields will hold: ...
Stores and provides access to parsed AST.
SourceManager & getSourceManager()
std::string getDeclComment(const ASTContext &Ctx, const NamedDecl &Decl)
Similar to getDocComment, but returns the comment for a NamedDecl.
static bool shouldCollectSymbol(const NamedDecl &ND, const ASTContext &ASTCtx, const Options &Opts, bool IsMainFileSymbol)
Returns true is ND should be collected.
llvm::Optional< std::string > ReturnType
Set for functions and lambadas.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
BulletList & addBulletList()
void addRuler()
Inserts a horizontal separator to the document.
CharSourceRange Range
SourceRange for the file name.
llvm::Optional< std::string > Value
Contains the evaluated value of the symbol if available.
Represents parts of the markup that can contain strings, like inline code, code block or plain text...
markup::Document present() const
Produce a user-readable information.
Paragraph & addHeading(size_t Level)
Heading is a special type of paragraph that will be prepended with Level many '#'s in markdown...
llvm::SmallDenseMap< const NamedDecl *, RelSet > Decls
Paragraph & addParagraph()
Adds a semantical block that will be separate from others.
static std::string join(ArrayRef< SpecialMemberFunctionsCheck::SpecialMemberFunctionKind > SMFS, llvm::StringRef AndOr)
std::unique_ptr< GlobalCompilationDatabase > Base
llvm::raw_ostream & operator<<(llvm::raw_ostream &OS, const CodeCompletion &C)
std::string Documentation
llvm::Optional< DefinedMacro > locateMacroAt(SourceLocation Loc, Preprocessor &PP)
Gets the macro at a specified Loc.
const SymbolIndex * Index
static cl::opt< std::string > FormatStyle("format-style", cl::desc(R"(
Style for formatting code around applied fixes:
- 'none' (default) turns off formatting
- 'file' (literally 'file', not a placeholder)
uses .clang-format file in the closest parent
directory
- '{ <json> }' specifies options inline, e.g.
-format-style='{BasedOnStyle: llvm, IndentWidth: 8}'
- 'llvm', 'google', 'webkit', 'mozilla'
See clang-format documentation for the up-to-date
information about formatting styles and options.
This option overrides the 'FormatStyle` option in
.clang-tidy file, if any.
)"), cl::init("none"), cl::cat(ClangTidyCategory))
Represents a sequence of one or more documents.