11 #include "clang/AST/ASTContext.h"
12 #include "clang/AST/DeclCXX.h"
13 #include "clang/AST/DeclObjC.h"
14 #include "clang/AST/DeclTemplate.h"
15 #include "clang/Basic/SourceManager.h"
24 llvm::Optional<const Decl *> insertionDecl(
const DeclContext &DC,
26 bool LastMatched =
false;
27 bool ReturnNext =
false;
28 for (
const auto *
D : DC.decls()) {
34 const Decl *NonTemplate =
D;
35 if (
auto *TD = llvm::dyn_cast<TemplateDecl>(
D))
36 NonTemplate = TD->getTemplatedDecl();
37 bool Matches =
A.Match(NonTemplate);
38 dlog(
" {0} {1} {2}", Matches,
D->getDeclKindName(),
D);
40 switch (
A.Direction) {
42 if (Matches && !LastMatched) {
45 if (llvm::isa<AccessSpecDecl>(
D)) {
53 if (LastMatched && !Matches)
58 LastMatched = Matches;
65 SourceLocation beginLoc(
const Decl &
D) {
66 auto Loc =
D.getBeginLoc();
67 if (RawComment *Comment =
D.getASTContext().getRawCommentForDeclNoCache(&
D)) {
68 auto CommentLoc = Comment->getBeginLoc();
69 if (CommentLoc.isValid() &&
Loc.isValid() &&
70 D.getASTContext().getSourceManager().isBeforeInTranslationUnit(
77 bool any(
const Decl *
D) {
return true; }
79 SourceLocation endLoc(
const DeclContext &DC) {
80 const Decl *
D = llvm::cast<Decl>(&DC);
81 if (
auto *OCD = llvm::dyn_cast<ObjCContainerDecl>(
D))
82 return OCD->getAtEndRange().getBegin();
83 return D->getEndLoc();
86 AccessSpecifier getAccessAtEnd(
const CXXRecordDecl &
C) {
87 AccessSpecifier Spec = (
C.getTagKind() == TTK_Class ? AS_private : AS_public);
88 for (
const auto *
D :
C.decls())
89 if (
const auto *ASD = llvm::dyn_cast<AccessSpecDecl>(
D))
90 Spec = ASD->getAccess();
97 llvm::ArrayRef<Anchor> Anchors) {
98 dlog(
"Looking for insertion point in {0}", DC.getDeclKindName());
99 for (
const auto &
A : Anchors) {
101 if (
auto D = insertionDecl(DC,
A)) {
102 dlog(
" anchor matched before {0}", *
D);
103 return *
D ? beginLoc(**
D) : endLoc(DC);
106 dlog(
"no anchor matched");
107 return SourceLocation();
110 llvm::Expected<tooling::Replacement>
112 llvm::ArrayRef<Anchor> Anchors) {
117 const auto &SM = DC.getParentASTContext().getSourceManager();
118 if (!SM.isWrittenInSameFile(
Loc, cast<Decl>(DC).getLocation()))
119 return error(
"{0} body in wrong file: {1}", DC.getDeclKindName(),
120 Loc.printToString(SM));
121 return tooling::Replacement(SM,
Loc, 0,
Code);
125 std::vector<Anchor> Anchors,
126 AccessSpecifier Protection) {
127 for (
auto &
A : Anchors)
128 A.Match = [
Inner(std::move(
A.Match)), Protection](
const Decl *
D) {
129 return D->getAccess() == Protection &&
Inner(
D);
135 const CXXRecordDecl &InClass,
136 std::vector<Anchor> Anchors,
137 AccessSpecifier Protection) {
141 std::string CodeBuffer;
142 auto &SM = InClass.getASTContext().getSourceManager();
144 if (
Loc.isInvalid()) {
145 Loc = InClass.getBraceRange().getEnd();
146 if (Protection != getAccessAtEnd(InClass)) {
147 CodeBuffer = (getAccessSpelling(Protection) +
":\n" +
Code).str();
151 if (!SM.isWrittenInSameFile(
Loc, InClass.getLocation()))
152 return error(
"Class body in wrong file: {0}",
Loc.printToString(SM));
153 return tooling::Replacement(SM,
Loc, 0,
Code);