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