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
19namespace clang {
20
21class LangOptions;
22class PPConditionalDirectiveRecord;
23class SourceManager;
24
25namespace edit {
26
27class EditedSource;
28
29class Commit {
30public:
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
51private:
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
62public:
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
124private:
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