1 //===--- AtomicChange.h - AtomicChange class --------------------*- 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 // This file defines AtomicChange which is used to create a set of source 11 // changes, e.g. replacements and header insertions. 12 // 13 //===----------------------------------------------------------------------===// 14 15 #ifndef LLVM_CLANG_TOOLING_REFACTOR_ATOMICCHANGE_H 16 #define LLVM_CLANG_TOOLING_REFACTOR_ATOMICCHANGE_H 17 18 #include "clang/Basic/SourceManager.h" 19 #include "clang/Tooling/Core/Replacement.h" 20 #include "llvm/ADT/StringRef.h" 21 #include "llvm/Support/Error.h" 22 23 namespace clang { 24 namespace tooling { 25 26 /// \brief 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. 36 class AtomicChange { 37 public: 38 /// \brief 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 &SM, SourceLocation KeyPosition); 43 44 /// \brief Creates an atomic change for \p FilePath with a customized key. 45 AtomicChange(llvm::StringRef FilePath, llvm::StringRef Key) 46 : Key(Key), FilePath(FilePath) {} 47 48 /// \brief Returns the atomic change as a YAML string. 49 std::string toYAMLString(); 50 51 /// \brief Converts a YAML-encoded automic change to AtomicChange. 52 static AtomicChange convertFromYAML(llvm::StringRef YAMLContent); 53 54 /// \brief Returns the key of this change, which is a concatenation of the 55 /// file name and offset of the key position. 56 const std::string &getKey() const { return Key; } 57 58 /// \brief Returns the path of the file containing this atomic change. 59 const std::string &getFilePath() const { return FilePath; } 60 61 /// \brief If this change could not be created successfully, e.g. because of 62 /// conflicts among replacements, use this to set an error description. 63 /// Thereby, places that cannot be fixed automatically can be gathered when 64 /// applying changes. 65 void setError(llvm::StringRef Error) { this->Error = Error; } 66 67 /// \brief Returns whether an error has been set on this list. 68 bool hasError() const { return !Error.empty(); } 69 70 /// \brief Returns the error message or an empty string if it does not exist. 71 const std::string &getError() const { return Error; } 72 73 /// \brief Adds a replacement that replaces the given Range with 74 /// ReplacementText. 75 /// \returns An llvm::Error carrying ReplacementError on error. 76 llvm::Error replace(const SourceManager &SM, const CharSourceRange &Range, 77 llvm::StringRef ReplacementText); 78 79 /// \brief Adds a replacement that replaces range [Loc, Loc+Length) with 80 /// \p Text. 81 /// \returns An llvm::Error carrying ReplacementError on error. 82 llvm::Error replace(const SourceManager &SM, SourceLocation Loc, 83 unsigned Length, llvm::StringRef Text); 84 85 /// \brief Adds a replacement that inserts \p Text at \p Loc. If this 86 /// insertion conflicts with an existing insertion (at the same position), 87 /// this will be inserted before/after the existing insertion depending on 88 /// \p InsertAfter. Users should use `replace` with `Length=0` instead if they 89 /// do not want conflict resolving by default. If the conflicting replacement 90 /// is not an insertion, an error is returned. 91 /// 92 /// \returns An llvm::Error carrying ReplacementError on error. 93 llvm::Error insert(const SourceManager &SM, SourceLocation Loc, 94 llvm::StringRef Text, bool InsertAfter = true); 95 96 /// \brief Adds a header into the file that contains the key position. 97 /// Header can be in angle brackets or double quotation marks. By default 98 /// (header is not quoted), header will be surrounded with double quotes. 99 void addHeader(llvm::StringRef Header); 100 101 /// \brief Removes a header from the file that contains the key position. 102 void removeHeader(llvm::StringRef Header); 103 104 /// \brief Returns a const reference to existing replacements. 105 const Replacements &getReplacements() const { return Replaces; } 106 107 llvm::ArrayRef<std::string> getInsertedHeaders() const { 108 return InsertedHeaders; 109 } 110 111 llvm::ArrayRef<std::string> getRemovedHeaders() const { 112 return RemovedHeaders; 113 } 114 115 private: 116 AtomicChange() {} 117 118 AtomicChange(std::string Key, std::string FilePath, std::string Error, 119 std::vector<std::string> InsertedHeaders, 120 std::vector<std::string> RemovedHeaders, 121 clang::tooling::Replacements Replaces); 122 123 // This uniquely identifies an AtomicChange. 124 std::string Key; 125 std::string FilePath; 126 std::string Error; 127 std::vector<std::string> InsertedHeaders; 128 std::vector<std::string> RemovedHeaders; 129 tooling::Replacements Replaces; 130 }; 131 132 } // end namespace tooling 133 } // end namespace clang 134 135 #endif // LLVM_CLANG_TOOLING_REFACTOR_ATOMICCHANGE_H 136