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/DeclCXX.h"
25 #include "clang/AST/DeclTemplate.h"
26 #include "clang/AST/Expr.h"
27 #include "clang/AST/ExprCXX.h"
28 #include "clang/AST/OperationKinds.h"
29 #include "clang/AST/PrettyPrinter.h"
30 #include "clang/AST/Type.h"
31 #include "clang/Basic/SourceLocation.h"
32 #include "clang/Basic/Specifiers.h"
33 #include "clang/Basic/TokenKinds.h"
34 #include "clang/Index/IndexSymbol.h"
35 #include "clang/Tooling/Syntax/Tokens.h"
36 #include "llvm/ADT/None.h"
37 #include "llvm/ADT/Optional.h"
38 #include "llvm/ADT/STLExtras.h"
39 #include "llvm/ADT/SmallVector.h"
40 #include "llvm/ADT/StringExtras.h"
41 #include "llvm/ADT/StringRef.h"
42 #include "llvm/Support/Casting.h"
43 #include "llvm/Support/ErrorHandling.h"
44 #include "llvm/Support/raw_ostream.h"
51 PrintingPolicy printingPolicyForDecls(PrintingPolicy
Base) {
52 PrintingPolicy Policy(
Base);
54 Policy.AnonymousTagLocations =
false;
55 Policy.TerseOutput =
true;
56 Policy.PolishForDeclaration =
true;
57 Policy.ConstantsAsWritten =
true;
58 Policy.SuppressTagKeyword =
false;
66 std::string getLocalScope(
const Decl *D) {
67 std::vector<std::string> Scopes;
68 const DeclContext *DC = D->getDeclContext();
69 auto GetName = [](
const TypeDecl *D) {
70 if (!D->getDeclName().isEmpty()) {
71 PrintingPolicy Policy = D->getASTContext().getPrintingPolicy();
72 Policy.SuppressScope =
true;
75 if (
auto RD = dyn_cast<RecordDecl>(D))
76 return (
"(anonymous " + RD->getKindName() +
")").str();
77 return std::string(
"");
80 if (
const TypeDecl *TD = dyn_cast<TypeDecl>(DC))
81 Scopes.push_back(GetName(TD));
82 else if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
83 Scopes.push_back(FD->getNameAsString());
87 return llvm::join(llvm::reverse(Scopes),
"::");
92 std::string getNamespaceScope(
const Decl *D) {
93 const DeclContext *DC = D->getDeclContext();
95 if (
const TagDecl *TD = dyn_cast<TagDecl>(DC))
96 return getNamespaceScope(TD);
97 if (
const FunctionDecl *FD = dyn_cast<FunctionDecl>(DC))
98 return getNamespaceScope(FD);
99 if (
const NamespaceDecl *NSD = dyn_cast<NamespaceDecl>(DC)) {
101 if (NSD->isInline() || NSD->isAnonymousNamespace())
102 return getNamespaceScope(NSD);
104 if (
const NamedDecl *ND = dyn_cast<NamedDecl>(DC))
110 std::string printDefinition(
const Decl *D) {
112 llvm::raw_string_ostream
OS(Definition);
113 PrintingPolicy Policy =
114 printingPolicyForDecls(D->getASTContext().getPrintingPolicy());
115 Policy.IncludeTagDefinition =
false;
116 Policy.SuppressTemplateArgsInCXXConstructors =
true;
117 Policy.SuppressTagKeyword =
true;
118 D->print(
OS, Policy);
123 std::string
printType(QualType QT,
const PrintingPolicy &Policy) {
127 while (!QT.isNull() && QT->isDecltypeType())
128 QT = QT->getAs<DecltypeType>()->getUnderlyingType();
129 return QT.getAsString(Policy);
132 std::string
printType(
const TemplateTypeParmDecl *TTP) {
133 std::string Res = TTP->wasDeclaredWithTypename() ?
"typename" :
"class";
134 if (TTP->isParameterPack())
139 std::string
printType(
const NonTypeTemplateParmDecl *NTTP,
140 const PrintingPolicy &
PP) {
142 if (NTTP->isParameterPack())
147 std::string
printType(
const TemplateTemplateParmDecl *TTP,
148 const PrintingPolicy &
PP) {
150 llvm::raw_string_ostream
OS(Res);
152 llvm::StringRef Sep =
"";
153 for (
const Decl *Param : *TTP->getTemplateParameters()) {
156 if (
const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param))
158 else if (
const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param))
160 else if (
const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param))
169 std::vector<HoverInfo::Param>
170 fetchTemplateParameters(
const TemplateParameterList *Params,
171 const PrintingPolicy &
PP) {
173 std::vector<HoverInfo::Param> TempParameters;
175 for (
const Decl *Param : *Params) {
177 if (
const auto *TTP = dyn_cast<TemplateTypeParmDecl>(Param)) {
180 if (!TTP->getName().empty())
181 P.Name = TTP->getNameAsString();
183 if (TTP->hasDefaultArgument())
184 P.Default = TTP->getDefaultArgument().getAsString(
PP);
185 }
else if (
const auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
188 if (IdentifierInfo *II = NTTP->getIdentifier())
189 P.Name = II->getName().str();
191 if (NTTP->hasDefaultArgument()) {
193 llvm::raw_string_ostream
Out(*P.Default);
194 NTTP->getDefaultArgument()->printPretty(
Out,
nullptr,
PP);
196 }
else if (
const auto *TTPD = dyn_cast<TemplateTemplateParmDecl>(Param)) {
199 if (!TTPD->getName().empty())
200 P.Name = TTPD->getNameAsString();
202 if (TTPD->hasDefaultArgument()) {
204 llvm::raw_string_ostream
Out(*P.Default);
205 TTPD->getDefaultArgument().getArgument().print(
PP,
Out);
208 TempParameters.push_back(std::move(P));
211 return TempParameters;
214 const FunctionDecl *getUnderlyingFunction(
const Decl *D) {
216 if (
const VarDecl *VD = llvm::dyn_cast<VarDecl>(D)) {
217 auto QT = VD->getType();
219 while (!QT->getPointeeType().isNull())
220 QT = QT->getPointeeType();
222 if (
const auto *CD = QT->getAsCXXRecordDecl())
223 return CD->getLambdaCallOperator();
228 return D->getAsFunction();
233 const NamedDecl *getDeclForComment(
const NamedDecl *D) {
234 if (
const auto *TSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(D)) {
237 if (TSD->getTemplateSpecializationKind() == TSK_Undeclared)
238 return TSD->getSpecializedTemplate();
239 if (
const auto *TIP = TSD->getTemplateInstantiationPattern())
242 if (
const auto *TSD = llvm::dyn_cast<VarTemplateSpecializationDecl>(D)) {
243 if (TSD->getTemplateSpecializationKind() == TSK_Undeclared)
244 return TSD->getSpecializedTemplate();
245 if (
const auto *TIP = TSD->getTemplateInstantiationPattern())
248 if (
const auto *FD = D->getAsFunction())
249 if (
const auto *TIP = FD->getTemplateInstantiationPattern())
255 void enhanceFromIndex(HoverInfo &Hover,
const NamedDecl &ND,
256 const SymbolIndex *
Index) {
257 assert(&ND == getDeclForComment(&ND));
259 if (!Hover.Documentation.empty() || !
Index)
265 SymbolCollector::Options(),
274 Hover.Documentation = std::string(S.Documentation);
281 const Expr *getDefaultArg(
const ParmVarDecl *PVD) {
286 if (!PVD->hasDefaultArg() || PVD->hasUnparsedDefaultArg())
288 return PVD->hasUninstantiatedDefaultArg() ? PVD->getUninstantiatedDefaultArg()
289 : PVD->getDefaultArg();
292 HoverInfo::Param toHoverInfoParam(
const ParmVarDecl *PVD,
293 const PrintingPolicy &Policy) {
294 HoverInfo::Param
Out;
296 if (!PVD->getName().empty())
297 Out.Name = PVD->getNameAsString();
298 if (
const Expr *DefArg = getDefaultArg(PVD)) {
299 Out.Default.emplace();
300 llvm::raw_string_ostream
OS(*
Out.Default);
301 DefArg->printPretty(
OS,
nullptr, Policy);
307 void fillFunctionTypeAndParams(HoverInfo &HI,
const Decl *D,
308 const FunctionDecl *FD,
309 const PrintingPolicy &Policy) {
310 HI.Parameters.emplace();
311 for (
const ParmVarDecl *PVD : FD->parameters())
312 HI.Parameters->emplace_back(toHoverInfoParam(PVD, Policy));
316 const auto NK = FD->getDeclName().getNameKind();
317 if (NK == DeclarationName::CXXConstructorName ||
318 NK == DeclarationName::CXXDestructorName ||
319 NK == DeclarationName::CXXConversionFunctionName)
322 HI.ReturnType =
printType(FD->getReturnType(), Policy);
323 QualType QT = FD->getType();
324 if (
const VarDecl *VD = llvm::dyn_cast<VarDecl>(D))
325 QT = VD->getType().getDesugaredType(D->getASTContext());
330 llvm::Optional<std::string> printExprValue(
const Expr *
E,
331 const ASTContext &
Ctx) {
336 if (
const auto *ILE = llvm::dyn_cast<InitListExpr>(
E)) {
337 if (!ILE->isSemanticForm())
338 E = ILE->getSemanticForm();
343 QualType T =
E->getType();
344 if (T.isNull() || T->isFunctionType() || T->isFunctionPointerType() ||
345 T->isFunctionReferenceType())
350 if (
E->isValueDependent() || !
E->EvaluateAsRValue(Constant,
Ctx) ||
357 if (T->isEnumeralType() &&
Constant.Val.getInt().getMinSignedBits() <= 64) {
359 int64_t Val =
Constant.Val.getInt().getExtValue();
360 for (
const EnumConstantDecl *ECD :
361 T->castAs<EnumType>()->getDecl()->enumerators())
362 if (ECD->getInitVal() == Val)
363 return llvm::formatv(
"{0} ({1})", ECD->getNameAsString(), Val).str();
368 llvm::Optional<std::string> printExprValue(
const SelectionTree::Node *N,
369 const ASTContext &
Ctx) {
370 for (; N; N = N->Parent) {
372 if (
const Expr *
E = N->ASTNode.get<Expr>()) {
373 if (
auto Val = printExprValue(
E,
Ctx))
375 }
else if (N->ASTNode.get<
Decl>() || N->ASTNode.get<Stmt>()) {
384 llvm::Optional<StringRef> fieldName(
const Expr *
E) {
385 const auto *ME = llvm::dyn_cast<MemberExpr>(
E->IgnoreCasts());
386 if (!ME || !llvm::isa<CXXThisExpr>(ME->getBase()->IgnoreCasts()))
388 const auto *
Field = llvm::dyn_cast<FieldDecl>(ME->getMemberDecl());
389 if (!Field || !
Field->getDeclName().isIdentifier())
391 return Field->getDeclName().getAsIdentifierInfo()->getName();
395 llvm::Optional<StringRef> getterVariableName(
const CXXMethodDecl *CMD) {
396 assert(CMD->hasBody());
397 if (CMD->getNumParams() != 0 || CMD->isVariadic())
399 const auto *Body = llvm::dyn_cast<CompoundStmt>(CMD->getBody());
400 const auto *OnlyReturn = (Body && Body->size() == 1)
401 ? llvm::dyn_cast<ReturnStmt>(Body->body_front())
403 if (!OnlyReturn || !OnlyReturn->getRetValue())
405 return fieldName(OnlyReturn->getRetValue());
412 llvm::Optional<StringRef> setterVariableName(
const CXXMethodDecl *CMD) {
413 assert(CMD->hasBody());
414 if (CMD->isConst() || CMD->getNumParams() != 1 || CMD->isVariadic())
416 const ParmVarDecl *Arg = CMD->getParamDecl(0);
417 if (Arg->isParameterPack())
420 const auto *Body = llvm::dyn_cast<CompoundStmt>(CMD->getBody());
421 if (!Body || Body->size() == 0 || Body->size() > 2)
424 if (Body->size() == 2) {
425 auto *Ret = llvm::dyn_cast<ReturnStmt>(Body->body_back());
426 if (!Ret || !Ret->getRetValue())
428 const Expr *RetVal = Ret->getRetValue()->IgnoreCasts();
429 if (
const auto *UO = llvm::dyn_cast<UnaryOperator>(RetVal)) {
430 if (UO->getOpcode() != UO_Deref)
432 RetVal = UO->getSubExpr()->IgnoreCasts();
434 if (!llvm::isa<CXXThisExpr>(RetVal))
438 const Expr *LHS, *RHS;
439 if (
const auto *BO = llvm::dyn_cast<BinaryOperator>(Body->body_front())) {
440 if (BO->getOpcode() != BO_Assign)
444 }
else if (
const auto *COCE =
445 llvm::dyn_cast<CXXOperatorCallExpr>(Body->body_front())) {
446 if (COCE->getOperator() != OO_Equal || COCE->getNumArgs() != 2)
448 LHS = COCE->getArg(0);
449 RHS = COCE->getArg(1);
453 auto *DRE = llvm::dyn_cast<DeclRefExpr>(RHS->IgnoreCasts());
454 if (!DRE || DRE->getDecl() != Arg)
456 return fieldName(LHS);
459 std::string synthesizeDocumentation(
const NamedDecl *ND) {
460 if (
const auto *CMD = llvm::dyn_cast<CXXMethodDecl>(ND)) {
462 if (CMD->getDeclName().isIdentifier() && !CMD->isStatic() &&
463 (CMD = llvm::dyn_cast_or_null<CXXMethodDecl>(CMD->getDefinition())) &&
465 if (
const auto GetterField = getterVariableName(CMD))
466 return llvm::formatv(
"Trivial accessor for `{0}`.", *GetterField);
467 if (
const auto SetterField = setterVariableName(CMD))
468 return llvm::formatv(
"Trivial setter for `{0}`.", *SetterField);
475 HoverInfo getHoverContents(
const NamedDecl *D,
const SymbolIndex *
Index) {
477 const ASTContext &
Ctx = D->getASTContext();
479 HI.AccessSpecifier = getAccessSpelling(D->getAccess()).str();
480 HI.NamespaceScope = getNamespaceScope(D);
481 if (!HI.NamespaceScope->empty())
482 HI.NamespaceScope->append(
"::");
483 HI.LocalScope = getLocalScope(D);
484 if (!HI.LocalScope.empty())
485 HI.LocalScope.append(
"::");
487 PrintingPolicy Policy = printingPolicyForDecls(
Ctx.getPrintingPolicy());
489 const auto *CommentD = getDeclForComment(D);
491 enhanceFromIndex(HI, *CommentD,
Index);
492 if (HI.Documentation.empty())
493 HI.Documentation = synthesizeDocumentation(D);
498 if (
const TemplateDecl *TD = D->getDescribedTemplate()) {
499 HI.TemplateParameters =
500 fetchTemplateParameters(TD->getTemplateParameters(), Policy);
502 }
else if (
const FunctionDecl *FD = D->getAsFunction()) {
503 if (
const auto *FTD = FD->getDescribedTemplate()) {
504 HI.TemplateParameters =
505 fetchTemplateParameters(FTD->getTemplateParameters(), Policy);
511 if (
const FunctionDecl *FD = getUnderlyingFunction(D))
512 fillFunctionTypeAndParams(HI, D, FD, Policy);
513 else if (
const auto *VD = dyn_cast<ValueDecl>(D))
514 HI.Type =
printType(VD->getType(), Policy);
515 else if (
const auto *TTP = dyn_cast<TemplateTypeParmDecl>(D))
516 HI.Type = TTP->wasDeclaredWithTypename() ?
"typename" :
"class";
517 else if (
const auto *TTP = dyn_cast<TemplateTemplateParmDecl>(D))
521 if (
const auto *Var = dyn_cast<VarDecl>(D)) {
522 if (
const Expr *Init = Var->getInit())
523 HI.Value = printExprValue(Init,
Ctx);
524 }
else if (
const auto *ECD = dyn_cast<EnumConstantDecl>(D)) {
526 if (!ECD->getType()->isDependentType())
527 HI.Value = ECD->getInitVal().toString(10);
530 HI.Definition = printDefinition(D);
535 HoverInfo getHoverContents(QualType T, ASTContext &ASTCtx,
536 const SymbolIndex *
Index) {
539 if (
const auto *D = T->getAsTagDecl()) {
543 const auto *CommentD = getDeclForComment(D);
545 enhanceFromIndex(HI, *CommentD,
Index);
548 auto Policy = printingPolicyForDecls(ASTCtx.getPrintingPolicy());
549 Policy.SuppressTagKeyword =
true;
550 HI.Name = T.getAsString(Policy);
556 HoverInfo getHoverContents(
const DefinedMacro &Macro, ParsedAST &AST) {
559 HI.Name = std::string(
Macro.Name);
560 HI.Kind = index::SymbolKind::Macro;
565 SourceLocation StartLoc =
Macro.Info->getDefinitionLoc();
566 SourceLocation EndLoc =
Macro.Info->getDefinitionEndLoc();
574 if (SM.getPresumedLoc(EndLoc,
false).isValid()) {
575 EndLoc = Lexer::getLocForEndOfToken(EndLoc, 0, SM, AST.
getLangOpts());
577 StringRef Buffer = SM.getBufferData(SM.getFileID(StartLoc), &Invalid);
579 unsigned StartOffset = SM.getFileOffset(StartLoc);
580 unsigned EndOffset = SM.getFileOffset(EndLoc);
581 if (EndOffset <= Buffer.size() && StartOffset < EndOffset)
583 (
"#define " + Buffer.substr(StartOffset, EndOffset - StartOffset))
590 bool isLiteral(
const Expr *
E) {
593 return llvm::isa<CharacterLiteral>(
E) || llvm::isa<CompoundLiteralExpr>(
E) ||
594 llvm::isa<CXXBoolLiteralExpr>(
E) ||
595 llvm::isa<CXXNullPtrLiteralExpr>(
E) ||
596 llvm::isa<FixedPointLiteral>(
E) || llvm::isa<FloatingLiteral>(
E) ||
597 llvm::isa<ImaginaryLiteral>(
E) || llvm::isa<IntegerLiteral>(
E) ||
598 llvm::isa<StringLiteral>(
E) || llvm::isa<UserDefinedLiteral>(
E);
601 llvm::StringLiteral getNameForExpr(
const Expr *
E) {
609 return llvm::StringLiteral(
"expression");
614 llvm::Optional<HoverInfo> getHoverContents(
const Expr *
E, ParsedAST &AST) {
625 printingPolicyForDecls(AST.
getASTContext().getPrintingPolicy());
626 Policy.SuppressTagKeyword =
true;
629 HI.Name = std::string(getNameForExpr(
E));
635 bool isParagraphBreak(llvm::StringRef Rest) {
636 return Rest.ltrim(
" \t").startswith(
"\n");
639 bool punctuationIndicatesLineBreak(llvm::StringRef
Line) {
640 constexpr llvm::StringLiteral
Punctuation = R
"txt(.:,;!?)txt";
646 bool isHardLineBreakIndicator(llvm::StringRef Rest) {
649 constexpr llvm::StringLiteral LinebreakIndicators = R
"txt(-*@>#`)txt";
651 Rest = Rest.ltrim(" \t");
655 if (LinebreakIndicators.contains(Rest.front()))
658 if (llvm::isDigit(Rest.front())) {
659 llvm::StringRef AfterDigit = Rest.drop_while(llvm::isDigit);
660 if (AfterDigit.startswith(
".") || AfterDigit.startswith(
")"))
666 bool isHardLineBreakAfter(llvm::StringRef
Line, llvm::StringRef Rest) {
668 return punctuationIndicatesLineBreak(
Line) || isHardLineBreakIndicator(Rest);
671 void addLayoutInfo(
const NamedDecl &ND, HoverInfo &HI) {
672 if (ND.isInvalidDecl())
675 const auto &
Ctx = ND.getASTContext();
676 if (
auto *RD = llvm::dyn_cast<RecordDecl>(&ND)) {
677 if (
auto Size =
Ctx.getTypeSizeInCharsIfKnown(RD->getTypeForDecl()))
678 HI.Size = Size->getQuantity();
682 if (
const auto *FD = llvm::dyn_cast<FieldDecl>(&ND)) {
683 const auto *
Record = FD->getParent();
687 HI.Offset =
Ctx.getFieldOffset(FD) / 8;
688 if (
auto Size =
Ctx.getTypeSizeInCharsIfKnown(FD->getType()))
689 HI.Size = Size->getQuantity();
697 void maybeAddCalleeArgInfo(
const SelectionTree::Node *N, HoverInfo &HI,
698 const PrintingPolicy &Policy) {
699 const auto &OuterNode = N->outerImplicit();
700 if (!OuterNode.Parent)
702 const auto *
CE = OuterNode.Parent->ASTNode.get<CallExpr>();
705 const FunctionDecl *FD =
CE->getDirectCallee();
712 if (!FD || FD->isOverloadedOperator() || FD->isVariadic())
716 for (
unsigned I = 0; I <
CE->getNumArgs() && I < FD->getNumParams(); ++I) {
717 if (
CE->getArg(I) != OuterNode.ASTNode.get<Expr>())
721 if (
const ParmVarDecl *PVD = FD->getParamDecl(I))
722 HI.CalleeArgInfo.emplace(toHoverInfoParam(PVD, Policy));
725 if (!HI.CalleeArgInfo)
731 HoverInfo::PassType PassType;
732 if (
const auto *
E = N->ASTNode.get<Expr>()) {
733 if (
E->getType().isConstQualified())
737 for (
auto *CastNode = N->Parent;
738 CastNode != OuterNode.Parent && !PassType.Converted;
739 CastNode = CastNode->Parent) {
740 if (
const auto *ImplicitCast = CastNode->ASTNode.get<ImplicitCastExpr>()) {
741 switch (ImplicitCast->getCastKind()) {
743 case CK_DerivedToBase:
744 case CK_UncheckedDerivedToBase:
747 PassType.PassBy = ImplicitCast->getType().isConstQualified()
751 case CK_LValueToRValue:
752 case CK_ArrayToPointerDecay:
753 case CK_FunctionToPointerDecay:
754 case CK_NullToPointer:
755 case CK_NullToMemberPointer:
761 PassType.Converted =
true;
764 }
else if (
const auto *CtorCall =
765 CastNode->ASTNode.get<CXXConstructExpr>()) {
768 if (CtorCall->getConstructor()->isCopyConstructor())
771 PassType.Converted =
true;
774 PassType.Converted =
true;
778 HI.CallPassType.emplace(PassType);
789 llvm::consumeError(CurLoc.takeError());
793 auto TokensTouchingCursor = syntax::spelledTokensTouching(*CurLoc, TB);
795 if (TokensTouchingCursor.empty())
801 CharSourceRange HighlightRange =
802 TokensTouchingCursor.back().range(SM).toCharRange(SM);
803 llvm::Optional<HoverInfo> HI;
807 for (
const auto &Tok : TokensTouchingCursor) {
808 if (Tok.kind() == tok::identifier) {
810 HighlightRange = Tok.range(SM).toCharRange(SM);
812 HI = getHoverContents(*M, AST);
815 }
else if (Tok.kind() == tok::kw_auto || Tok.kind() == tok::kw_decltype) {
818 HighlightRange = Tok.range(SM).toCharRange(SM);
826 auto Offset = SM.getFileOffset(*CurLoc);
831 std::vector<const Decl *> Result;
835 if (!Decls.empty()) {
836 HI = getHoverContents(Decls.front(),
Index);
838 if (Decls.front() == N->ASTNode.get<
Decl>())
839 addLayoutInfo(*Decls.front(), *HI);
843 maybeAddCalleeArgInfo(N, *HI, AST.
getASTContext().getPrintingPolicy());
844 }
else if (
const Expr *
E = N->ASTNode.get<Expr>()) {
845 HI = getHoverContents(
E, AST);
855 auto Replacements = format::reformat(
858 tooling::applyAllReplacements(HI->Definition, Replacements))
859 HI->Definition = *Formatted;
880 if (
Kind != index::SymbolKind::Unknown)
882 assert(!
Name.empty() &&
"hover triggered on a nameless symbol");
897 Output.addParagraph().appendText(
"Parameters: ");
901 llvm::raw_string_ostream
OS(Buffer);
907 Output.addParagraph().appendText(
"Type: ").appendCode(*
Type);
917 Output.addParagraph().appendText(
918 llvm::formatv(
"Offset: {0} byte{1}", *
Offset, *
Offset == 1 ?
"" :
"s")
921 Output.addParagraph().appendText(
922 llvm::formatv(
"Size: {0} byte{1}", *
Size, *
Size == 1 ?
"" :
"s").str());
927 llvm::raw_string_ostream
OS(Buffer);
939 Output.addParagraph().appendText(
OS.str());
947 std::string ScopeComment;
954 "// In " + llvm::StringRef(
LocalScope).rtrim(
':').str() +
'\n';
956 ScopeComment =
"// In namespace " +
957 llvm::StringRef(*NamespaceScope).rtrim(
':').str() +
'\n';
964 Output.addCodeBlock(ScopeComment + DefinitionWithAccess);
977 llvm::StringRef Prefix =
Line.substr(0,
Offset);
978 constexpr llvm::StringLiteral BeforeStartChars =
" \t(=";
979 if (!Prefix.empty() && !BeforeStartChars.contains(Prefix.back()))
984 if (Next == llvm::StringRef::npos)
992 llvm::StringRef
Suffix =
Line.substr(Next + 1);
993 constexpr llvm::StringLiteral AfterEndChars =
" \t)=.,;:";
994 if (!
Suffix.empty() && !AfterEndChars.contains(
Suffix.front()))
1002 for (
unsigned I = 0; I <
Line.size(); ++I) {
1006 Out.appendText(
Line.substr(0, I));
1007 Out.appendCode(
Range->trim(
"`"),
true);
1013 Out.appendText(
Line).appendSpace();
1017 std::vector<llvm::StringRef> ParagraphLines;
1018 auto FlushParagraph = [&] {
1019 if (ParagraphLines.empty())
1021 auto &P =
Output.addParagraph();
1022 for (llvm::StringRef
Line : ParagraphLines)
1024 ParagraphLines.clear();
1027 llvm::StringRef
Line, Rest;
1028 for (std::tie(
Line, Rest) = Input.split(
'\n');
1029 !(
Line.empty() && Rest.empty());
1030 std::tie(
Line, Rest) = Rest.split(
'\n')) {
1036 ParagraphLines.push_back(
Line);
1038 if (isParagraphBreak(Rest) || isHardLineBreakAfter(
Line, Rest)) {
1047 std::vector<llvm::StringRef>
Output;