1//===- EditedSource.h - Collection of source 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_EDITEDSOURCE_H
10#define LLVM_CLANG_EDIT_EDITEDSOURCE_H
11
12#include "clang/Basic/IdentifierTable.h"
13#include "clang/Basic/LLVM.h"
14#include "clang/Basic/SourceLocation.h"
15#include "clang/Edit/FileOffset.h"
16#include "llvm/ADT/DenseMap.h"
17#include "llvm/ADT/SmallVector.h"
18#include "llvm/ADT/StringRef.h"
19#include "llvm/Support/Allocator.h"
20#include <map>
21#include <tuple>
22#include <utility>
23
24namespace clang {
25
26class LangOptions;
27class PPConditionalDirectiveRecord;
28class SourceManager;
29
30namespace edit {
31
32class Commit;
33class EditsReceiver;
34
35class EditedSource {
36  const SourceManager &SourceMgr;
37  const LangOptions &LangOpts;
38  const PPConditionalDirectiveRecord *PPRec;
39
40  struct FileEdit {
41    StringRef Text;
42    unsigned RemoveLen = 0;
43
44    FileEdit() = default;
45  };
46
47  using FileEditsTy = std::map<FileOffset, FileEdit>;
48
49  FileEditsTy FileEdits;
50
51  struct MacroArgUse {
52    IdentifierInfo *Identifier;
53    SourceLocation ImmediateExpansionLoc;
54
55    // Location of argument use inside the top-level macro
56    SourceLocation UseLoc;
57
58    bool operator==(const MacroArgUse &Other) const {
59      return std::tie(Identifier, ImmediateExpansionLoc, UseLoc) ==
60             std::tie(Other.Identifier, Other.ImmediateExpansionLoc,
61                      Other.UseLoc);
62    }
63  };
64
65  llvm::DenseMap<unsigned, SmallVector<MacroArgUse, 2>> ExpansionToArgMap;
66  SmallVector<std::pair<SourceLocation, MacroArgUse>, 2>
67    CurrCommitMacroArgExps;
68
69  IdentifierTable IdentTable;
70  llvm::BumpPtrAllocator StrAlloc;
71
72public:
73  EditedSource(const SourceManager &SM, const LangOptions &LangOpts,
74               const PPConditionalDirectiveRecord *PPRec = nullptr)
75      : SourceMgr(SM), LangOpts(LangOpts), PPRec(PPRec), IdentTable(LangOpts) {}
76
77  const SourceManager &getSourceManager() const { return SourceMgr; }
78  const LangOptions &getLangOpts() const { return LangOpts; }
79
80  const PPConditionalDirectiveRecord *getPPCondDirectiveRecord() const {
81    return PPRec;
82  }
83
84  bool canInsertInOffset(SourceLocation OrigLoc, FileOffset Offs);
85
86  bool commit(const Commit &commit);
87
88  void applyRewrites(EditsReceiver &receiver, bool adjustRemovals = true);
89  void clearRewrites();
90
91  StringRef copyString(StringRef str) { return str.copy(StrAlloc); }
92  StringRef copyString(const Twine &twine);
93
94private:
95  bool commitInsert(SourceLocation OrigLoc, FileOffset Offs, StringRef text,
96                    bool beforePreviousInsertions);
97  bool commitInsertFromRange(SourceLocation OrigLoc, FileOffset Offs,
98                             FileOffset InsertFromRangeOffs, unsigned Len,
99                             bool beforePreviousInsertions);
100  void commitRemove(SourceLocation OrigLoc, FileOffset BeginOffs, unsigned Len);
101
102  StringRef getSourceText(FileOffset BeginOffs, FileOffset EndOffs,
103                          bool &Invalid);
104  FileEditsTy::iterator getActionForOffset(FileOffset Offs);
105  void deconstructMacroArgLoc(SourceLocation Loc,
106                              SourceLocation &ExpansionLoc,
107                              MacroArgUse &ArgUse);
108
109  void startingCommit();
110  void finishedCommit();
111};
112
113} // namespace edit
114
115} // namespace clang
116
117#endif // LLVM_CLANG_EDIT_EDITEDSOURCE_H
118