Clang Project

clang_source_code/include/clang/Tooling/Refactoring/AtomicChange.h
1//===--- AtomicChange.h - AtomicChange class --------------------*- 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//  This file defines AtomicChange which is used to create a set of source
10//  changes, e.g. replacements and header insertions.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_CLANG_TOOLING_REFACTOR_ATOMICCHANGE_H
15#define LLVM_CLANG_TOOLING_REFACTOR_ATOMICCHANGE_H
16
17#include "clang/Basic/SourceManager.h"
18#include "clang/Format/Format.h"
19#include "clang/Tooling/Core/Replacement.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/Support/Error.h"
22
23namespace clang {
24namespace tooling {
25
26/// An atomic change is used to create and group a set of source edits,
27/// e.g. replacements or header insertions. Edits in an AtomicChange should be
28/// related, e.g. replacements for the same type reference and the corresponding
29/// header insertion/deletion.
30///
31/// An AtomicChange is uniquely identified by a key and will either be fully
32/// applied or not applied at all.
33///
34/// Calling setError on an AtomicChange stores the error message and marks it as
35/// bad, i.e. none of its source edits will be applied.
36class AtomicChange {
37public:
38  /// Creates an atomic change around \p KeyPosition with the key being a
39  /// concatenation of the file name and the offset of \p KeyPosition.
40  /// \p KeyPosition should be the location of the key syntactical element that
41  /// is being changed, e.g. the call to a refactored method.
42  AtomicChange(const SourceManager &SMSourceLocation KeyPosition);
43
44  /// Creates an atomic change for \p FilePath with a customized key.
45  AtomicChange(llvm::StringRef FilePathllvm::StringRef Key)
46      : Key(Key), FilePath(FilePath) {}
47
48  AtomicChange(AtomicChange &&) = default;
49  AtomicChange(const AtomicChange &) = default;
50
51  AtomicChange &operator=(AtomicChange &&) = default;
52  AtomicChange &operator=(const AtomicChange &) = default;
53
54  bool operator==(const AtomicChange &Otherconst;
55
56  /// Returns the atomic change as a YAML string.
57  std::string toYAMLString();
58
59  /// Converts a YAML-encoded automic change to AtomicChange.
60  static AtomicChange convertFromYAML(llvm::StringRef YAMLContent);
61
62  /// Returns the key of this change, which is a concatenation of the
63  /// file name and offset of the key position.
64  const std::string &getKey() const { return Key; }
65
66  /// Returns the path of the file containing this atomic change.
67  const std::string &getFilePath() const { return FilePath; }
68
69  /// If this change could not be created successfully, e.g. because of
70  /// conflicts among replacements, use this to set an error description.
71  /// Thereby, places that cannot be fixed automatically can be gathered when
72  /// applying changes.
73  void setError(llvm::StringRef Error) { this->Error = Error; }
74
75  /// Returns whether an error has been set on this list.
76  bool hasError() const { return !Error.empty(); }
77
78  /// Returns the error message or an empty string if it does not exist.
79  const std::string &getError() const { return Error; }
80
81  /// Adds a replacement that replaces the given Range with
82  /// ReplacementText.
83  /// \returns An llvm::Error carrying ReplacementError on error.
84  llvm::Error replace(const SourceManager &SM, const CharSourceRange &Range,
85                      llvm::StringRef ReplacementText);
86
87  /// Adds a replacement that replaces range [Loc, Loc+Length) with
88  /// \p Text.
89  /// \returns An llvm::Error carrying ReplacementError on error.
90  llvm::Error replace(const SourceManager &SM, SourceLocation Loc,
91                      unsigned Length, llvm::StringRef Text);
92
93  /// Adds a replacement that inserts \p Text at \p Loc. If this
94  /// insertion conflicts with an existing insertion (at the same position),
95  /// this will be inserted before/after the existing insertion depending on
96  /// \p InsertAfter. Users should use `replace` with `Length=0` instead if they
97  /// do not want conflict resolving by default. If the conflicting replacement
98  /// is not an insertion, an error is returned.
99  ///
100  /// \returns An llvm::Error carrying ReplacementError on error.
101  llvm::Error insert(const SourceManager &SM, SourceLocation Loc,
102                     llvm::StringRef Text, bool InsertAfter = true);
103
104  /// Adds a header into the file that contains the key position.
105  /// Header can be in angle brackets or double quotation marks. By default
106  /// (header is not quoted), header will be surrounded with double quotes.
107  void addHeader(llvm::StringRef Header);
108
109  /// Removes a header from the file that contains the key position.
110  void removeHeader(llvm::StringRef Header);
111
112  /// Returns a const reference to existing replacements.
113  const Replacements &getReplacements() const { return Replaces; }
114
115  llvm::ArrayRef<std::stringgetInsertedHeaders() const {
116    return InsertedHeaders;
117  }
118
119  llvm::ArrayRef<std::stringgetRemovedHeaders() const {
120    return RemovedHeaders;
121  }
122
123private:
124  AtomicChange() {}
125
126  AtomicChange(std::string Keystd::string FilePathstd::string Error,
127               std::vector<std::stringInsertedHeaders,
128               std::vector<std::stringRemovedHeaders,
129               clang::tooling::Replacements Replaces);
130
131  // This uniquely identifies an AtomicChange.
132  std::string Key;
133  std::string FilePath;
134  std::string Error;
135  std::vector<std::stringInsertedHeaders;
136  std::vector<std::stringRemovedHeaders;
137  tooling::Replacements Replaces;
138};
139
140using AtomicChanges = std::vector<AtomicChange>;
141
142// Defines specs for applying changes.
143struct ApplyChangesSpec {
144  // If true, cleans up redundant/erroneous code around changed code with
145  // clang-format's cleanup functionality, e.g. redundant commas around deleted
146  // parameter or empty namespaces introduced by deletions.
147  bool Cleanup = true;
148
149  format::FormatStyle Style = format::getNoStyle();
150
151  // Options for selectively formatting changes with clang-format:
152  // kAll: Format all changed lines.
153  // kNone: Don't format anything.
154  // kViolations: Format lines exceeding the `ColumnLimit` in `Style`.
155  enum FormatOption { kAllkNonekViolations };
156
157  FormatOption Format = kNone;
158};
159
160/// Applies all AtomicChanges in \p Changes to the \p Code.
161///
162/// This completely ignores the file path in each change and replaces them with
163/// \p FilePath, i.e. callers are responsible for ensuring all changes are for
164/// the same file.
165///
166/// \returns The changed code if all changes are applied successfully;
167/// otherwise, an llvm::Error carrying llvm::StringError is returned (the Error
168/// message can be converted to string with `llvm::toString()` and the
169/// error_code should be ignored).
170llvm::Expected<std::string>
171applyAtomicChanges(llvm::StringRef FilePathllvm::StringRef Code,
172                   llvm::ArrayRef<AtomicChangeChanges,
173                   const ApplyChangesSpec &Spec);
174
175// end namespace tooling
176// end namespace clang
177
178#endif // LLVM_CLANG_TOOLING_REFACTOR_ATOMICCHANGE_H
179
clang::tooling::AtomicChange::toYAMLString
clang::tooling::AtomicChange::convertFromYAML
clang::tooling::AtomicChange::getKey
clang::tooling::AtomicChange::getFilePath
clang::tooling::AtomicChange::setError
clang::tooling::AtomicChange::hasError
clang::tooling::AtomicChange::getError
clang::tooling::AtomicChange::replace
clang::tooling::AtomicChange::replace
clang::tooling::AtomicChange::insert
clang::tooling::AtomicChange::addHeader
clang::tooling::AtomicChange::removeHeader
clang::tooling::AtomicChange::getReplacements
clang::tooling::AtomicChange::getInsertedHeaders
clang::tooling::AtomicChange::getRemovedHeaders
clang::tooling::AtomicChange::Key
clang::tooling::AtomicChange::FilePath
clang::tooling::AtomicChange::Error
clang::tooling::AtomicChange::InsertedHeaders
clang::tooling::AtomicChange::RemovedHeaders
clang::tooling::AtomicChange::Replaces
clang::tooling::ApplyChangesSpec::Cleanup
clang::tooling::ApplyChangesSpec::Style
clang::tooling::ApplyChangesSpec::FormatOption
clang::tooling::ApplyChangesSpec::Format