56#include "clang/AST/ASTContext.h"
57#include "clang/AST/Decl.h"
58#include "clang/AST/DeclBase.h"
59#include "clang/AST/ExprCXX.h"
60#include "clang/AST/NestedNameSpecifier.h"
61#include "clang/AST/RecursiveASTVisitor.h"
62#include "clang/AST/Stmt.h"
63#include "clang/Basic/LangOptions.h"
64#include "clang/Basic/SourceLocation.h"
65#include "clang/Basic/SourceManager.h"
66#include "clang/Tooling/Core/Replacement.h"
67#include "clang/Tooling/Refactoring/Extract/SourceExtraction.h"
68#include "llvm/ADT/STLExtras.h"
69#include "llvm/ADT/SmallSet.h"
70#include "llvm/ADT/SmallVector.h"
71#include "llvm/ADT/StringRef.h"
72#include "llvm/Support/Casting.h"
73#include "llvm/Support/Error.h"
85enum class ZoneRelative {
92enum FunctionDeclKind {
101bool isRootStmt(
const Node *N) {
102 if (!N->ASTNode.get<Stmt>())
112 !N->ASTNode.get<CXXOperatorCallExpr>())
127const Node *getParentOfRootStmts(
const Node *CommonAnc) {
130 const Node *Parent =
nullptr;
131 switch (CommonAnc->Selected) {
143 Parent = CommonAnc->Parent;
148 if (Parent->ASTNode.get<DeclStmt>())
149 Parent = Parent->Parent;
153 return llvm::all_of(Parent->Children, isRootStmt) ? Parent :
nullptr;
157struct ExtractionZone {
159 const Node *Parent =
nullptr;
161 SourceRange ZoneRange;
163 const FunctionDecl *EnclosingFunction =
nullptr;
165 SourceRange EnclosingFuncRange;
167 llvm::DenseSet<const Stmt *> RootStmts;
169 SourceLocation getInsertionPoint()
const {
170 return EnclosingFuncRange.getBegin();
172 bool isRootStmt(
const Stmt *S)
const;
175 const Node *getLastRootStmt()
const {
return Parent->Children.back(); }
181 bool requiresHoisting(
const SourceManager &SM,
182 const HeuristicResolver *Resolver)
const {
184 llvm::SmallPtrSet<const Decl *, 1> DeclsInExtZone;
185 for (
auto *RootStmt : RootStmts) {
188 [&DeclsInExtZone](
const ReferenceLoc &Loc) {
191 DeclsInExtZone.insert(Loc.Targets.front());
196 if (DeclsInExtZone.empty())
199 for (
const auto *S : EnclosingFunction->getBody()->children()) {
200 if (SM.isBeforeInTranslationUnit(S->getSourceRange().getEnd(),
203 bool HasPostUse =
false;
206 [&](
const ReferenceLoc &Loc) {
208 SM.isBeforeInTranslationUnit(Loc.NameLoc, ZoneRange.getEnd()))
210 HasPostUse = llvm::any_of(Loc.Targets,
211 [&DeclsInExtZone](
const Decl *Target) {
212 return DeclsInExtZone.contains(Target);
227bool alwaysReturns(
const ExtractionZone &EZ) {
228 const Stmt *Last = EZ.getLastRootStmt()->ASTNode.get<Stmt>();
230 while (
const auto *CS = llvm::dyn_cast<CompoundStmt>(Last)) {
231 if (CS->body_empty())
233 Last = CS->body_back();
235 return llvm::isa<ReturnStmt>(Last);
238bool ExtractionZone::isRootStmt(
const Stmt *S)
const {
239 return RootStmts.contains(S);
243const FunctionDecl *findEnclosingFunction(
const Node *CommonAnc) {
245 for (
const Node *CurNode = CommonAnc; CurNode; CurNode = CurNode->Parent) {
247 if (CurNode->ASTNode.get<LambdaExpr>())
249 if (
const FunctionDecl *Func = CurNode->ASTNode.get<FunctionDecl>()) {
251 if (Func->isTemplated())
253 if (!Func->getBody())
255 for (
const auto *S : Func->getBody()->children()) {
270std::optional<SourceRange> findZoneRange(
const Node *Parent,
271 const SourceManager &SM,
272 const LangOptions &LangOpts) {
275 SM, LangOpts, Parent->Children.front()->ASTNode.getSourceRange()))
276 SR.setBegin(BeginFileRange->getBegin());
280 SM, LangOpts, Parent->Children.back()->ASTNode.getSourceRange()))
281 SR.setEnd(EndFileRange->getEnd());
291std::optional<SourceRange>
292computeEnclosingFuncRange(
const FunctionDecl *EnclosingFunction,
293 const SourceManager &SM,
294 const LangOptions &LangOpts) {
300bool validSingleChild(
const Node *Child,
const FunctionDecl *EnclosingFunc) {
304 if (Child->ASTNode.get<Expr>())
307 assert(EnclosingFunc->hasBody() &&
308 "We should always be extracting from a function body.");
309 if (Child->ASTNode.get<Stmt>() == EnclosingFunc->getBody())
316std::optional<ExtractionZone> findExtractionZone(
const Node *CommonAnc,
317 const SourceManager &SM,
318 const LangOptions &LangOpts) {
319 ExtractionZone ExtZone;
320 ExtZone.Parent = getParentOfRootStmts(CommonAnc);
321 if (!ExtZone.Parent || ExtZone.Parent->Children.empty())
323 ExtZone.EnclosingFunction = findEnclosingFunction(ExtZone.Parent);
324 if (!ExtZone.EnclosingFunction)
328 if (ExtZone.Parent->Children.size() == 1 &&
329 !validSingleChild(ExtZone.getLastRootStmt(), ExtZone.EnclosingFunction))
332 computeEnclosingFuncRange(ExtZone.EnclosingFunction, SM, LangOpts))
333 ExtZone.EnclosingFuncRange = *FuncRange;
334 if (
auto ZoneRange = findZoneRange(ExtZone.Parent, SM, LangOpts))
335 ExtZone.ZoneRange = *ZoneRange;
336 if (ExtZone.EnclosingFuncRange.isInvalid() || ExtZone.ZoneRange.isInvalid())
339 for (
const Node *Child : ExtZone.Parent->Children)
340 ExtZone.RootStmts.insert(Child->ASTNode.get<Stmt>());
351 bool PassByReference;
352 unsigned OrderPriority;
353 std::string render(
const DeclContext *Context)
const;
354 bool operator<(
const Parameter &Other)
const {
355 return OrderPriority < Other.OrderPriority;
358 std::string Name =
"extracted";
360 std::vector<Parameter> Parameters;
361 SourceRange BodyRange;
362 SourceLocation DefinitionPoint;
363 std::optional<SourceLocation> ForwardDeclarationPoint;
364 const CXXRecordDecl *EnclosingClass =
nullptr;
365 NestedNameSpecifier DefinitionQualifier = std::nullopt;
366 const DeclContext *SemanticDC =
nullptr;
367 const DeclContext *SyntacticDC =
nullptr;
368 const DeclContext *ForwardDeclarationSyntacticDC =
nullptr;
369 bool CallerReturnsValue =
false;
371 ConstexprSpecKind Constexpr = ConstexprSpecKind::Unspecified;
376 tooling::ExtractionSemicolonPolicy SemicolonPolicy;
377 const LangOptions *LangOpts;
378 NewFunction(tooling::ExtractionSemicolonPolicy SemicolonPolicy,
379 const LangOptions *LangOpts)
380 : SemicolonPolicy(SemicolonPolicy), LangOpts(LangOpts) {}
382 std::string renderCall()
const;
384 std::string renderDeclaration(FunctionDeclKind K,
385 const DeclContext &SemanticDC,
386 const DeclContext &SyntacticDC,
387 const SourceManager &SM)
const;
391 renderParametersForDeclaration(
const DeclContext &Enclosing)
const;
392 std::string renderParametersForCall()
const;
393 std::string renderSpecifiers(FunctionDeclKind K)
const;
394 std::string renderQualifiers()
const;
395 std::string renderDeclarationName(FunctionDeclKind K)
const;
397 std::string getFuncBody(
const SourceManager &SM)
const;
400std::string NewFunction::renderParametersForDeclaration(
401 const DeclContext &Enclosing)
const {
403 bool NeedCommaBefore =
false;
404 for (
const Parameter &P : Parameters) {
407 NeedCommaBefore =
true;
408 Result +=
P.render(&Enclosing);
413std::string NewFunction::renderParametersForCall()
const {
415 bool NeedCommaBefore =
false;
416 for (
const Parameter &P : Parameters) {
419 NeedCommaBefore =
true;
425std::string NewFunction::renderSpecifiers(FunctionDeclKind K)
const {
426 std::string Attributes;
428 if (Static && K != FunctionDeclKind::OutOfLineDefinition) {
429 Attributes +=
"static ";
433 case ConstexprSpecKind::Unspecified:
434 case ConstexprSpecKind::Constinit:
436 case ConstexprSpecKind::Constexpr:
437 Attributes +=
"constexpr ";
439 case ConstexprSpecKind::Consteval:
440 Attributes +=
"consteval ";
447std::string NewFunction::renderQualifiers()
const {
448 std::string Attributes;
451 Attributes +=
" const";
457std::string NewFunction::renderDeclarationName(FunctionDeclKind K)
const {
458 if (!DefinitionQualifier || K != OutOfLineDefinition)
461 std::string QualifierName;
462 llvm::raw_string_ostream Oss(QualifierName);
463 DefinitionQualifier.print(Oss, *LangOpts);
464 return llvm::formatv(
"{0}{1}", QualifierName, Name);
467std::string NewFunction::renderCall()
const {
469 llvm::formatv(
"{0}{1}({2}){3}", CallerReturnsValue ?
"return " :
"", Name,
470 renderParametersForCall(),
471 (SemicolonPolicy.isNeededInOriginalFunction() ?
";" :
"")));
474std::string NewFunction::renderDeclaration(FunctionDeclKind K,
475 const DeclContext &SemanticDC,
476 const DeclContext &SyntacticDC,
477 const SourceManager &SM)
const {
478 std::string
Declaration = std::string(llvm::formatv(
479 "{0}{1} {2}({3}){4}", renderSpecifiers(K),
480 printType(ReturnType, SyntacticDC), renderDeclarationName(K),
481 renderParametersForDeclaration(SemanticDC), renderQualifiers()));
484 case ForwardDeclaration:
485 return std::string(llvm::formatv(
"{0};\n", Declaration));
486 case OutOfLineDefinition:
487 case InlineDefinition:
489 llvm::formatv(
"{0} {\n{1}\n}\n", Declaration, getFuncBody(SM)));
492 llvm_unreachable(
"Unsupported FunctionDeclKind enum");
495std::string NewFunction::getFuncBody(
const SourceManager &SM)
const {
501 (SemicolonPolicy.isNeededInExtractedFunction() ?
";" :
"");
504std::string NewFunction::Parameter::render(
const DeclContext *Context)
const {
505 return printType(TypeInfo, *Context) + (PassByReference ?
" &" :
" ") + Name;
509struct CapturedZoneInfo {
510 struct DeclInformation {
512 ZoneRelative DeclaredIn;
515 bool IsReferencedInZone =
false;
516 bool IsReferencedInPostZone =
false;
518 DeclInformation(
const Decl *TheDecl, ZoneRelative DeclaredIn,
520 : TheDecl(TheDecl), DeclaredIn(DeclaredIn), DeclIndex(DeclIndex){};
522 void markOccurence(ZoneRelative ReferenceLoc);
525 llvm::DenseMap<const Decl *, DeclInformation> DeclInfoMap;
526 bool HasReturnStmt =
false;
527 bool AlwaysReturns =
false;
530 bool BrokenControlFlow =
false;
533 DeclInformation *createDeclInfo(
const Decl *D, ZoneRelative RelativeLoc);
534 DeclInformation *getDeclInfoFor(
const Decl *D);
537CapturedZoneInfo::DeclInformation *
538CapturedZoneInfo::createDeclInfo(
const Decl *D, ZoneRelative RelativeLoc) {
540 auto InsertionResult = DeclInfoMap.insert(
541 {
D, DeclInformation(D, RelativeLoc, DeclInfoMap.size())});
543 return &InsertionResult.first->second;
546CapturedZoneInfo::DeclInformation *
547CapturedZoneInfo::getDeclInfoFor(
const Decl *D) {
549 auto Iter = DeclInfoMap.find(D);
550 if (Iter == DeclInfoMap.end())
552 return &Iter->second;
555void CapturedZoneInfo::DeclInformation::markOccurence(
556 ZoneRelative ReferenceLoc) {
557 switch (ReferenceLoc) {
558 case ZoneRelative::Inside:
559 IsReferencedInZone =
true;
561 case ZoneRelative::After:
562 IsReferencedInPostZone =
true;
569bool isLoop(
const Stmt *S) {
570 return isa<ForStmt>(S) || isa<DoStmt>(S) || isa<WhileStmt>(S) ||
571 isa<CXXForRangeStmt>(S);
575CapturedZoneInfo captureZoneInfo(
const ExtractionZone &ExtZone) {
579 class ExtractionZoneVisitor
580 :
public clang::RecursiveASTVisitor<ExtractionZoneVisitor> {
582 ExtractionZoneVisitor(
const ExtractionZone &ExtZone) : ExtZone(ExtZone) {
583 TraverseDecl(
const_cast<FunctionDecl *
>(ExtZone.EnclosingFunction));
586 bool TraverseStmt(Stmt *S) {
589 bool IsRootStmt = ExtZone.isRootStmt(
const_cast<const Stmt *
>(S));
593 CurrentLocation = ZoneRelative::Inside;
594 addToLoopSwitchCounters(S, 1);
596 RecursiveASTVisitor::TraverseStmt(S);
597 addToLoopSwitchCounters(S, -1);
601 CurrentLocation = ZoneRelative::After;
607 void addToLoopSwitchCounters(Stmt *S,
int Increment) {
608 if (CurrentLocation != ZoneRelative::Inside)
611 CurNumberOfNestedLoops += Increment;
612 else if (isa<SwitchStmt>(S))
613 CurNumberOfSwitch += Increment;
616 bool VisitDecl(Decl *D) {
617 Info.createDeclInfo(D, CurrentLocation);
621 bool VisitDeclRefExpr(DeclRefExpr *DRE) {
623 const Decl *
D = DRE->getDecl();
624 auto *DeclInfo =
Info.getDeclInfoFor(D);
627 DeclInfo =
Info.createDeclInfo(D, ZoneRelative::OutsideFunc);
628 DeclInfo->markOccurence(CurrentLocation);
633 bool VisitReturnStmt(ReturnStmt *Return) {
634 if (CurrentLocation == ZoneRelative::Inside)
635 Info.HasReturnStmt =
true;
639 bool VisitBreakStmt(BreakStmt *Break) {
642 if (CurrentLocation == ZoneRelative::Inside &&
643 !(CurNumberOfNestedLoops || CurNumberOfSwitch))
644 Info.BrokenControlFlow =
true;
648 bool VisitContinueStmt(ContinueStmt *Continue) {
651 if (CurrentLocation == ZoneRelative::Inside && !CurNumberOfNestedLoops)
652 Info.BrokenControlFlow =
true;
655 CapturedZoneInfo
Info;
656 const ExtractionZone &ExtZone;
657 ZoneRelative CurrentLocation = ZoneRelative::Before;
660 unsigned CurNumberOfNestedLoops = 0;
661 unsigned CurNumberOfSwitch = 0;
663 ExtractionZoneVisitor Visitor(ExtZone);
664 CapturedZoneInfo Result = std::move(Visitor.Info);
665 Result.AlwaysReturns = alwaysReturns(ExtZone);
673bool createParameters(NewFunction &ExtractedFunc,
674 const CapturedZoneInfo &CapturedInfo) {
675 for (
const auto &KeyVal : CapturedInfo.DeclInfoMap) {
676 const auto &DeclInfo = KeyVal.second;
680 if (DeclInfo.DeclaredIn == ZoneRelative::Inside &&
681 DeclInfo.IsReferencedInPostZone)
683 if (!DeclInfo.IsReferencedInZone)
685 if (DeclInfo.DeclaredIn == ZoneRelative::Inside ||
686 DeclInfo.DeclaredIn == ZoneRelative::OutsideFunc)
689 const ValueDecl *VD = dyn_cast_or_null<ValueDecl>(DeclInfo.TheDecl);
692 if (!VD || isa<FunctionDecl>(DeclInfo.TheDecl))
695 QualType TypeInfo = VD->getType().getNonReferenceType();
701 bool IsPassedByReference =
true;
703 ExtractedFunc.Parameters.push_back({std::string(VD->getName()), TypeInfo,
705 DeclInfo.DeclIndex});
707 llvm::sort(ExtractedFunc.Parameters);
714tooling::ExtractionSemicolonPolicy
715getSemicolonPolicy(ExtractionZone &ExtZone,
const SourceManager &SM,
716 const LangOptions &LangOpts) {
718 SourceRange FuncBodyRange = {ExtZone.ZoneRange.getBegin(),
719 ExtZone.ZoneRange.getEnd().getLocWithOffset(-1)};
720 auto SemicolonPolicy = tooling::ExtractionSemicolonPolicy::compute(
721 ExtZone.getLastRootStmt()->ASTNode.get<Stmt>(), FuncBodyRange, SM,
724 ExtZone.ZoneRange.setEnd(FuncBodyRange.getEnd().getLocWithOffset(1));
725 return SemicolonPolicy;
729bool generateReturnProperties(NewFunction &ExtractedFunc,
730 const FunctionDecl &EnclosingFunc,
731 const CapturedZoneInfo &CapturedInfo) {
735 if (CapturedInfo.HasReturnStmt) {
738 if (!CapturedInfo.AlwaysReturns)
740 QualType Ret = EnclosingFunc.getReturnType();
743 if (Ret->isDependentType())
745 ExtractedFunc.ReturnType = Ret;
749 ExtractedFunc.ReturnType = EnclosingFunc.getParentASTContext().VoidTy;
753void captureMethodInfo(NewFunction &ExtractedFunc,
754 const CXXMethodDecl *Method) {
755 ExtractedFunc.Static =
Method->isStatic();
756 ExtractedFunc.Const =
Method->isConst();
757 ExtractedFunc.EnclosingClass =
Method->getParent();
762llvm::Expected<NewFunction> getExtractedFunction(ExtractionZone &ExtZone,
763 const SourceManager &SM,
764 const LangOptions &LangOpts) {
765 CapturedZoneInfo CapturedInfo = captureZoneInfo(ExtZone);
767 if (CapturedInfo.BrokenControlFlow)
768 return error(
"Cannot extract break/continue without corresponding "
769 "loop/switch statement.");
770 NewFunction ExtractedFunc(getSemicolonPolicy(ExtZone, SM, LangOpts),
773 ExtractedFunc.SyntacticDC =
774 ExtZone.EnclosingFunction->getLexicalDeclContext();
775 ExtractedFunc.SemanticDC = ExtZone.EnclosingFunction->getDeclContext();
776 ExtractedFunc.DefinitionQualifier = ExtZone.EnclosingFunction->getQualifier();
777 ExtractedFunc.Constexpr = ExtZone.EnclosingFunction->getConstexprKind();
779 if (
const auto *Method =
780 llvm::dyn_cast<CXXMethodDecl>(ExtZone.EnclosingFunction))
781 captureMethodInfo(ExtractedFunc, Method);
783 if (ExtZone.EnclosingFunction->isOutOfLine()) {
786 const auto *FirstOriginalDecl =
787 ExtZone.EnclosingFunction->getCanonicalDecl();
791 return error(
"Declaration is inside a macro");
792 ExtractedFunc.ForwardDeclarationPoint = DeclPos->getBegin();
793 ExtractedFunc.ForwardDeclarationSyntacticDC = ExtractedFunc.SemanticDC;
796 ExtractedFunc.BodyRange = ExtZone.ZoneRange;
797 ExtractedFunc.DefinitionPoint = ExtZone.getInsertionPoint();
799 ExtractedFunc.CallerReturnsValue = CapturedInfo.AlwaysReturns;
800 if (!createParameters(ExtractedFunc, CapturedInfo) ||
801 !generateReturnProperties(ExtractedFunc, *ExtZone.EnclosingFunction,
803 return error(
"Too complex to extract.");
804 return ExtractedFunc;
807class ExtractFunction :
public Tweak {
809 const char *id() const final;
810 bool prepare(const Selection &Inputs) override;
811 Expected<Effect> apply(const Selection &Inputs) override;
812 std::
string title()
const override {
return "Extract to function"; }
813 llvm::StringLiteral kind()
const override {
814 return CodeAction::REFACTOR_KIND;
818 ExtractionZone ExtZone;
822tooling::Replacement replaceWithFuncCall(
const NewFunction &ExtractedFunc,
823 const SourceManager &SM,
824 const LangOptions &LangOpts) {
825 std::string FuncCall = ExtractedFunc.renderCall();
826 return tooling::Replacement(
827 SM, CharSourceRange(ExtractedFunc.BodyRange,
false), FuncCall, LangOpts);
830tooling::Replacement createFunctionDefinition(
const NewFunction &ExtractedFunc,
831 const SourceManager &SM) {
832 FunctionDeclKind DeclKind = InlineDefinition;
833 if (ExtractedFunc.ForwardDeclarationPoint)
834 DeclKind = OutOfLineDefinition;
835 std::string FunctionDef = ExtractedFunc.renderDeclaration(
836 DeclKind, *ExtractedFunc.SemanticDC, *ExtractedFunc.SyntacticDC, SM);
838 return tooling::Replacement(SM, ExtractedFunc.DefinitionPoint, 0,
842tooling::Replacement createForwardDeclaration(
const NewFunction &ExtractedFunc,
843 const SourceManager &SM) {
844 std::string FunctionDecl = ExtractedFunc.renderDeclaration(
845 ForwardDeclaration, *ExtractedFunc.SemanticDC,
846 *ExtractedFunc.ForwardDeclarationSyntacticDC, SM);
847 SourceLocation DeclPoint = *ExtractedFunc.ForwardDeclarationPoint;
849 return tooling::Replacement(SM, DeclPoint, 0, FunctionDecl);
853bool hasReturnStmt(
const ExtractionZone &ExtZone) {
854 class ReturnStmtVisitor
855 :
public clang::RecursiveASTVisitor<ReturnStmtVisitor> {
857 bool VisitReturnStmt(ReturnStmt *Return) {
865 for (
const Stmt *RootStmt : ExtZone.RootStmts) {
866 V.TraverseStmt(
const_cast<Stmt *
>(RootStmt));
873bool ExtractFunction::prepare(
const Selection &Inputs) {
874 const LangOptions &LangOpts = Inputs.AST->getLangOpts();
875 if (!LangOpts.CPlusPlus)
877 const Node *CommonAnc = Inputs.ASTSelection.commonAncestor();
878 const SourceManager &SM = Inputs.AST->getSourceManager();
879 auto MaybeExtZone = findExtractionZone(CommonAnc, SM, LangOpts);
881 (hasReturnStmt(*MaybeExtZone) && !alwaysReturns(*MaybeExtZone)))
885 if (MaybeExtZone->requiresHoisting(SM, Inputs.AST->getHeuristicResolver()))
888 ExtZone = std::move(*MaybeExtZone);
892Expected<Tweak::Effect> ExtractFunction::apply(
const Selection &Inputs) {
893 const SourceManager &SM = Inputs.AST->getSourceManager();
894 const LangOptions &LangOpts = Inputs.AST->getLangOpts();
895 auto ExtractedFunc = getExtractedFunction(ExtZone, SM, LangOpts);
898 return ExtractedFunc.takeError();
899 tooling::Replacements Edit;
900 if (
auto Err = Edit.add(createFunctionDefinition(*ExtractedFunc, SM)))
901 return std::move(Err);
902 if (
auto Err = Edit.add(replaceWithFuncCall(*ExtractedFunc, SM, LangOpts)))
903 return std::move(Err);
905 if (
auto FwdLoc = ExtractedFunc->ForwardDeclarationPoint) {
908 if (SM.isWrittenInSameFile(ExtractedFunc->DefinitionPoint, *FwdLoc)) {
909 if (
auto Err = Edit.add(createForwardDeclaration(*ExtractedFunc, SM)))
910 return std::move(Err);
912 auto MultiFileEffect = Effect::mainFileEdit(SM, std::move(Edit));
913 if (!MultiFileEffect)
914 return MultiFileEffect.takeError();
916 tooling::Replacements OtherEdit(
917 createForwardDeclaration(*ExtractedFunc, SM));
918 if (
auto PathAndEdit =
919 Tweak::Effect::fileEdit(SM, SM.getFileID(*FwdLoc), OtherEdit))
920 MultiFileEffect->ApplyEdits.try_emplace(PathAndEdit->first,
921 PathAndEdit->second);
923 return PathAndEdit.takeError();
924 return MultiFileEffect;
927 return Effect::mainFileEdit(SM, std::move(Edit));
#define REGISTER_TWEAK(Subclass)
llvm::Error error(std::error_code, std::string &&)
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
@ Info
An information message.
std::optional< SourceRange > toHalfOpenFileRange(const SourceManager &SM, const LangOptions &LangOpts, SourceRange R)
Turns a token range into a half-open range and checks its correctness.
std::string printType(const QualType QT, const DeclContext &CurContext, const llvm::StringRef Placeholder, bool FullyQualify)
Returns a QualType as string.
void findExplicitReferences(const Stmt *S, llvm::function_ref< void(ReferenceLoc)> Out, const HeuristicResolver *Resolver)
Recursively traverse S and report all references explicitly written in the code.
llvm::StringRef toSourceCode(const SourceManager &SM, SourceRange R)
Returns the source code covered by the source range.
bool operator<(const Ref &L, const Ref &R)
@ Parameter
An inlay hint that is for a parameter.
cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccess P
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//