File indexing completed on 2026-05-10 08:37:10
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018 #ifndef LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H
0019 #define LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H
0020
0021 #include "clang/Basic/LangOptions.h"
0022 #include "clang/Basic/SourceLocation.h"
0023 #include "llvm/ADT/StringRef.h"
0024 #include "llvm/Support/Compiler.h"
0025 #include "llvm/Support/Error.h"
0026 #include "llvm/Support/raw_ostream.h"
0027 #include <map>
0028 #include <optional>
0029 #include <set>
0030 #include <string>
0031 #include <system_error>
0032 #include <utility>
0033 #include <vector>
0034
0035 namespace clang {
0036
0037 class FileManager;
0038 class Rewriter;
0039 class SourceManager;
0040
0041 namespace tooling {
0042
0043
0044 class Range {
0045 public:
0046 Range() = default;
0047 Range(unsigned Offset, unsigned Length) : Offset(Offset), Length(Length) {}
0048
0049
0050
0051 unsigned getOffset() const { return Offset; }
0052 unsigned getLength() const { return Length; }
0053
0054
0055
0056
0057
0058 bool overlapsWith(Range RHS) const {
0059 return Offset + Length > RHS.Offset && Offset < RHS.Offset + RHS.Length;
0060 }
0061
0062
0063 bool contains(Range RHS) const {
0064 return RHS.Offset >= Offset &&
0065 (RHS.Offset + RHS.Length) <= (Offset + Length);
0066 }
0067
0068
0069 bool operator==(const Range &RHS) const {
0070 return Offset == RHS.getOffset() && Length == RHS.getLength();
0071 }
0072
0073
0074 private:
0075 unsigned Offset = 0;
0076 unsigned Length = 0;
0077 };
0078
0079
0080
0081
0082
0083 class Replacement {
0084 public:
0085
0086 Replacement();
0087
0088
0089
0090
0091
0092
0093
0094 Replacement(StringRef FilePath, unsigned Offset, unsigned Length,
0095 StringRef ReplacementText);
0096
0097
0098
0099 Replacement(const SourceManager &Sources, SourceLocation Start,
0100 unsigned Length, StringRef ReplacementText);
0101
0102
0103 Replacement(const SourceManager &Sources, const CharSourceRange &Range,
0104 StringRef ReplacementText,
0105 const LangOptions &LangOpts = LangOptions());
0106
0107
0108 template <typename Node>
0109 Replacement(const SourceManager &Sources, const Node &NodeToReplace,
0110 StringRef ReplacementText,
0111 const LangOptions &LangOpts = LangOptions());
0112
0113
0114
0115
0116 bool isApplicable() const;
0117
0118
0119
0120 StringRef getFilePath() const { return FilePath; }
0121 unsigned getOffset() const { return ReplacementRange.getOffset(); }
0122 unsigned getLength() const { return ReplacementRange.getLength(); }
0123 StringRef getReplacementText() const { return ReplacementText; }
0124
0125
0126
0127 bool apply(Rewriter &Rewrite) const;
0128
0129
0130 std::string toString() const;
0131
0132 private:
0133 void setFromSourceLocation(const SourceManager &Sources, SourceLocation Start,
0134 unsigned Length, StringRef ReplacementText);
0135 void setFromSourceRange(const SourceManager &Sources,
0136 const CharSourceRange &Range,
0137 StringRef ReplacementText,
0138 const LangOptions &LangOpts);
0139
0140 std::string FilePath;
0141 Range ReplacementRange;
0142 std::string ReplacementText;
0143 };
0144
0145 enum class replacement_error {
0146 fail_to_apply = 0,
0147 wrong_file_path,
0148 overlap_conflict,
0149 insert_conflict,
0150 };
0151
0152
0153
0154 class ReplacementError : public llvm::ErrorInfo<ReplacementError> {
0155 public:
0156 ReplacementError(replacement_error Err) : Err(Err) {}
0157
0158
0159 ReplacementError(replacement_error Err, Replacement Existing)
0160 : Err(Err), ExistingReplacement(std::move(Existing)) {}
0161
0162
0163
0164 ReplacementError(replacement_error Err, Replacement New, Replacement Existing)
0165 : Err(Err), NewReplacement(std::move(New)),
0166 ExistingReplacement(std::move(Existing)) {}
0167
0168 std::string message() const override;
0169
0170 void log(raw_ostream &OS) const override { OS << message(); }
0171
0172 replacement_error get() const { return Err; }
0173
0174 static char ID;
0175
0176 const std::optional<Replacement> &getNewReplacement() const {
0177 return NewReplacement;
0178 }
0179
0180 const std::optional<Replacement> &getExistingReplacement() const {
0181 return ExistingReplacement;
0182 }
0183
0184 private:
0185
0186 std::error_code convertToErrorCode() const override {
0187 return llvm::inconvertibleErrorCode();
0188 }
0189
0190 replacement_error Err;
0191
0192
0193
0194 std::optional<Replacement> NewReplacement;
0195
0196
0197 std::optional<Replacement> ExistingReplacement;
0198 };
0199
0200
0201 bool operator<(const Replacement &LHS, const Replacement &RHS);
0202
0203
0204 bool operator==(const Replacement &LHS, const Replacement &RHS);
0205 inline bool operator!=(const Replacement &LHS, const Replacement &RHS) {
0206 return !(LHS == RHS);
0207 }
0208
0209
0210
0211
0212 class Replacements {
0213 private:
0214 using ReplacementsImpl = std::set<Replacement>;
0215
0216 public:
0217 using const_iterator = ReplacementsImpl::const_iterator;
0218 using const_reverse_iterator = ReplacementsImpl::const_reverse_iterator;
0219
0220 Replacements() = default;
0221
0222 explicit Replacements(const Replacement &R) { Replaces.insert(R); }
0223
0224
0225
0226
0227
0228
0229
0230
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249
0250
0251
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261 llvm::Error add(const Replacement &R);
0262
0263
0264
0265 [[nodiscard]] Replacements merge(const Replacements &Replaces) const;
0266
0267
0268 std::vector<Range> getAffectedRanges() const;
0269
0270
0271
0272
0273 unsigned getShiftedCodePosition(unsigned Position) const;
0274
0275 unsigned size() const { return Replaces.size(); }
0276
0277 void clear() { Replaces.clear(); }
0278
0279 bool empty() const { return Replaces.empty(); }
0280
0281 const_iterator begin() const { return Replaces.begin(); }
0282
0283 const_iterator end() const { return Replaces.end(); }
0284
0285 const_reverse_iterator rbegin() const { return Replaces.rbegin(); }
0286
0287 const_reverse_iterator rend() const { return Replaces.rend(); }
0288
0289 bool operator==(const Replacements &RHS) const {
0290 return Replaces == RHS.Replaces;
0291 }
0292
0293 private:
0294 Replacements(const_iterator Begin, const_iterator End)
0295 : Replaces(Begin, End) {}
0296
0297
0298
0299 Replacement getReplacementInChangedCode(const Replacement &R) const;
0300
0301
0302
0303
0304
0305 Replacements getCanonicalReplacements() const;
0306
0307
0308
0309
0310 llvm::Expected<Replacements>
0311 mergeIfOrderIndependent(const Replacement &R) const;
0312
0313 ReplacementsImpl Replaces;
0314 };
0315
0316
0317
0318
0319
0320
0321
0322 bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite);
0323
0324
0325
0326
0327
0328
0329
0330
0331 llvm::Expected<std::string> applyAllReplacements(StringRef Code,
0332 const Replacements &Replaces);
0333
0334
0335 struct TranslationUnitReplacements {
0336
0337 std::string MainSourceFile;
0338
0339 std::vector<Replacement> Replacements;
0340 };
0341
0342
0343
0344
0345
0346
0347
0348
0349
0350 std::vector<Range>
0351 calculateRangesAfterReplacements(const Replacements &Replaces,
0352 const std::vector<Range> &Ranges);
0353
0354
0355
0356
0357 std::map<std::string, Replacements> groupReplacementsByFile(
0358 FileManager &FileMgr,
0359 const std::map<std::string, Replacements> &FileToReplaces);
0360
0361 template <typename Node>
0362 Replacement::Replacement(const SourceManager &Sources,
0363 const Node &NodeToReplace, StringRef ReplacementText,
0364 const LangOptions &LangOpts) {
0365 const CharSourceRange Range =
0366 CharSourceRange::getTokenRange(NodeToReplace->getSourceRange());
0367 setFromSourceRange(Sources, Range, ReplacementText, LangOpts);
0368 }
0369
0370 }
0371
0372 }
0373
0374 #endif