1 //===- Commit.h - A unit of edits -------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_CLANG_EDIT_COMMIT_H
10 #define LLVM_CLANG_EDIT_COMMIT_H
11 
12 #include "clang/Basic/LLVM.h"
13 #include "clang/Basic/SourceLocation.h"
14 #include "clang/Edit/FileOffset.h"
15 #include "llvm/ADT/SmallVector.h"
16 #include "llvm/ADT/StringRef.h"
17 #include "llvm/Support/Allocator.h"
18 
19 namespace clang {
20 
21 class LangOptions;
22 class PPConditionalDirectiveRecord;
23 class SourceManager;
24 
25 namespace edit {
26 
27 class EditedSource;
28 
29 class Commit {
30 public:
31   enum EditKind {
32     Act_Insert,
33     Act_InsertFromRange,
34     Act_Remove
35   };
36 
37   struct Edit {
38     EditKind Kind;
39     StringRef Text;
40     SourceLocation OrigLoc;
41     FileOffset Offset;
42     FileOffset InsertFromRangeOffs;
43     unsigned Length;
44     bool BeforePrev;
45 
46     SourceLocation getFileLocation(SourceManager &SM) const;
47     CharSourceRange getFileRange(SourceManager &SM) const;
48     CharSourceRange getInsertFromRange(SourceManager &SM) const;
49   };
50 
51 private:
52   const SourceManager &SourceMgr;
53   const LangOptions &LangOpts;
54   const PPConditionalDirectiveRecord *PPRec;
55   EditedSource *Editor = nullptr;
56 
57   bool IsCommitable = true;
58   SmallVector<Edit, 8> CachedEdits;
59 
60   llvm::BumpPtrAllocator StrAlloc;
61 
62 public:
63   explicit Commit(EditedSource &Editor);
64   Commit(const SourceManager &SM, const LangOptions &LangOpts,
65          const PPConditionalDirectiveRecord *PPRec = nullptr)
66       : SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec) {}
67 
68   bool isCommitable() const { return IsCommitable; }
69 
70   bool insert(SourceLocation loc, StringRef text, bool afterToken = false,
71               bool beforePreviousInsertions = false);
72 
73   bool insertAfterToken(SourceLocation loc, StringRef text,
74                         bool beforePreviousInsertions = false) {
75     return insert(loc, text, /*afterToken=*/true, beforePreviousInsertions);
76   }
77 
78   bool insertBefore(SourceLocation loc, StringRef text) {
79     return insert(loc, text, /*afterToken=*/false,
80                   /*beforePreviousInsertions=*/true);
81   }
82 
83   bool insertFromRange(SourceLocation loc, CharSourceRange range,
84                        bool afterToken = false,
85                        bool beforePreviousInsertions = false);
86   bool insertWrap(StringRef before, CharSourceRange range, StringRef after);
87 
88   bool remove(CharSourceRange range);
89 
90   bool replace(CharSourceRange range, StringRef text);
91   bool replaceWithInner(CharSourceRange range, CharSourceRange innerRange);
92   bool replaceText(SourceLocation loc, StringRef text,
93                    StringRef replacementText);
94 
95   bool insertFromRange(SourceLocation loc, SourceRange TokenRange,
96                        bool afterToken = false,
97                        bool beforePreviousInsertions = false) {
98     return insertFromRange(loc, CharSourceRange::getTokenRange(TokenRange),
99                            afterToken, beforePreviousInsertions);
100   }
101 
102   bool insertWrap(StringRef before, SourceRange TokenRange, StringRef after) {
103     return insertWrap(before, CharSourceRange::getTokenRange(TokenRange), after);
104   }
105 
106   bool remove(SourceRange TokenRange) {
107     return remove(CharSourceRange::getTokenRange(TokenRange));
108   }
109 
110   bool replace(SourceRange TokenRange, StringRef text) {
111     return replace(CharSourceRange::getTokenRange(TokenRange), text);
112   }
113 
114   bool replaceWithInner(SourceRange TokenRange, SourceRange TokenInnerRange) {
115     return replaceWithInner(CharSourceRange::getTokenRange(TokenRange),
116                             CharSourceRange::getTokenRange(TokenInnerRange));
117   }
118 
119   using edit_iterator = SmallVectorImpl<Edit>::const_iterator;
120 
121   edit_iterator edit_begin() const { return CachedEdits.begin(); }
122   edit_iterator edit_end() const { return CachedEdits.end(); }
123 
124 private:
125   void addInsert(SourceLocation OrigLoc,
126                 FileOffset Offs, StringRef text, bool beforePreviousInsertions);
127   void addInsertFromRange(SourceLocation OrigLoc, FileOffset Offs,
128                           FileOffset RangeOffs, unsigned RangeLen,
129                           bool beforePreviousInsertions);
130   void addRemove(SourceLocation OrigLoc, FileOffset Offs, unsigned Len);
131 
132   bool canInsert(SourceLocation loc, FileOffset &Offset);
133   bool canInsertAfterToken(SourceLocation loc, FileOffset &Offset,
134                            SourceLocation &AfterLoc);
135   bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs);
136   bool canRemoveRange(CharSourceRange range, FileOffset &Offs, unsigned &Len);
137   bool canReplaceText(SourceLocation loc, StringRef text,
138                       FileOffset &Offs, unsigned &Len);
139 
140   void commitInsert(FileOffset offset, StringRef text,
141                     bool beforePreviousInsertions);
142   void commitRemove(FileOffset offset, unsigned length);
143 
144   bool isAtStartOfMacroExpansion(SourceLocation loc,
145                                  SourceLocation *MacroBegin = nullptr) const;
146   bool isAtEndOfMacroExpansion(SourceLocation loc,
147                                SourceLocation *MacroEnd = nullptr) const;
148 };
149 
150 } // namespace edit
151 
152 } // namespace clang
153 
154 #endif // LLVM_CLANG_EDIT_COMMIT_H
155