Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:37:11

0001 //===--- AtomicChange.h - AtomicChange class --------------------*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 //
0009 //  This file defines AtomicChange which is used to create a set of source
0010 //  changes, e.g. replacements and header insertions.
0011 //
0012 //===----------------------------------------------------------------------===//
0013 
0014 #ifndef LLVM_CLANG_TOOLING_REFACTORING_ATOMICCHANGE_H
0015 #define LLVM_CLANG_TOOLING_REFACTORING_ATOMICCHANGE_H
0016 
0017 #include "clang/Basic/SourceManager.h"
0018 #include "clang/Format/Format.h"
0019 #include "clang/Tooling/Core/Replacement.h"
0020 #include "llvm/ADT/Any.h"
0021 #include "llvm/ADT/StringRef.h"
0022 #include "llvm/Support/Error.h"
0023 
0024 namespace clang {
0025 namespace tooling {
0026 
0027 /// An atomic change is used to create and group a set of source edits,
0028 /// e.g. replacements or header insertions. Edits in an AtomicChange should be
0029 /// related, e.g. replacements for the same type reference and the corresponding
0030 /// header insertion/deletion.
0031 ///
0032 /// An AtomicChange is uniquely identified by a key and will either be fully
0033 /// applied or not applied at all.
0034 ///
0035 /// Calling setError on an AtomicChange stores the error message and marks it as
0036 /// bad, i.e. none of its source edits will be applied.
0037 class AtomicChange {
0038 public:
0039   /// Creates an atomic change around \p KeyPosition with the key being a
0040   /// concatenation of the file name and the offset of \p KeyPosition.
0041   /// \p KeyPosition should be the location of the key syntactical element that
0042   /// is being changed, e.g. the call to a refactored method.
0043   AtomicChange(const SourceManager &SM, SourceLocation KeyPosition);
0044 
0045   AtomicChange(const SourceManager &SM, SourceLocation KeyPosition,
0046                llvm::Any Metadata);
0047 
0048   /// Creates an atomic change for \p FilePath with a customized key.
0049   AtomicChange(llvm::StringRef FilePath, llvm::StringRef Key)
0050       : Key(Key), FilePath(FilePath) {}
0051 
0052   AtomicChange(AtomicChange &&) = default;
0053   AtomicChange(const AtomicChange &) = default;
0054 
0055   AtomicChange &operator=(AtomicChange &&) = default;
0056   AtomicChange &operator=(const AtomicChange &) = default;
0057 
0058   bool operator==(const AtomicChange &Other) const;
0059 
0060   /// Returns the atomic change as a YAML string.
0061   std::string toYAMLString();
0062 
0063   /// Converts a YAML-encoded automic change to AtomicChange.
0064   static AtomicChange convertFromYAML(llvm::StringRef YAMLContent);
0065 
0066   /// Returns the key of this change, which is a concatenation of the
0067   /// file name and offset of the key position.
0068   const std::string &getKey() const { return Key; }
0069 
0070   /// Returns the path of the file containing this atomic change.
0071   const std::string &getFilePath() const { return FilePath; }
0072 
0073   /// If this change could not be created successfully, e.g. because of
0074   /// conflicts among replacements, use this to set an error description.
0075   /// Thereby, places that cannot be fixed automatically can be gathered when
0076   /// applying changes.
0077   void setError(llvm::StringRef Error) { this->Error = std::string(Error); }
0078 
0079   /// Returns whether an error has been set on this list.
0080   bool hasError() const { return !Error.empty(); }
0081 
0082   /// Returns the error message or an empty string if it does not exist.
0083   const std::string &getError() const { return Error; }
0084 
0085   /// Adds a replacement that replaces the given Range with
0086   /// ReplacementText.
0087   /// \returns An llvm::Error carrying ReplacementError on error.
0088   llvm::Error replace(const SourceManager &SM, const CharSourceRange &Range,
0089                       llvm::StringRef ReplacementText);
0090 
0091   /// Adds a replacement that replaces range [Loc, Loc+Length) with
0092   /// \p Text.
0093   /// \returns An llvm::Error carrying ReplacementError on error.
0094   llvm::Error replace(const SourceManager &SM, SourceLocation Loc,
0095                       unsigned Length, llvm::StringRef Text);
0096 
0097   /// Adds a replacement that inserts \p Text at \p Loc. If this
0098   /// insertion conflicts with an existing insertion (at the same position),
0099   /// this will be inserted before/after the existing insertion depending on
0100   /// \p InsertAfter. Users should use `replace` with `Length=0` instead if they
0101   /// do not want conflict resolving by default. If the conflicting replacement
0102   /// is not an insertion, an error is returned.
0103   ///
0104   /// \returns An llvm::Error carrying ReplacementError on error.
0105   llvm::Error insert(const SourceManager &SM, SourceLocation Loc,
0106                      llvm::StringRef Text, bool InsertAfter = true);
0107 
0108   /// Adds a header into the file that contains the key position.
0109   /// Header can be in angle brackets or double quotation marks. By default
0110   /// (header is not quoted), header will be surrounded with double quotes.
0111   void addHeader(llvm::StringRef Header);
0112 
0113   /// Removes a header from the file that contains the key position.
0114   void removeHeader(llvm::StringRef Header);
0115 
0116   /// Returns a const reference to existing replacements.
0117   const Replacements &getReplacements() const { return Replaces; }
0118 
0119   Replacements &getReplacements() { return Replaces; }
0120 
0121   llvm::ArrayRef<std::string> getInsertedHeaders() const {
0122     return InsertedHeaders;
0123   }
0124 
0125   llvm::ArrayRef<std::string> getRemovedHeaders() const {
0126     return RemovedHeaders;
0127   }
0128 
0129   const llvm::Any &getMetadata() const { return Metadata; }
0130 
0131 private:
0132   AtomicChange() {}
0133 
0134   AtomicChange(std::string Key, std::string FilePath, std::string Error,
0135                std::vector<std::string> InsertedHeaders,
0136                std::vector<std::string> RemovedHeaders,
0137                clang::tooling::Replacements Replaces);
0138 
0139   // This uniquely identifies an AtomicChange.
0140   std::string Key;
0141   std::string FilePath;
0142   std::string Error;
0143   std::vector<std::string> InsertedHeaders;
0144   std::vector<std::string> RemovedHeaders;
0145   tooling::Replacements Replaces;
0146 
0147   // This field stores metadata which is ignored for the purposes of applying
0148   // edits to source, but may be useful for other consumers of AtomicChanges. In
0149   // particular, consumers can use this to direct how they want to consume each
0150   // edit.
0151   llvm::Any Metadata;
0152 };
0153 
0154 using AtomicChanges = std::vector<AtomicChange>;
0155 
0156 // Defines specs for applying changes.
0157 struct ApplyChangesSpec {
0158   // If true, cleans up redundant/erroneous code around changed code with
0159   // clang-format's cleanup functionality, e.g. redundant commas around deleted
0160   // parameter or empty namespaces introduced by deletions.
0161   bool Cleanup = true;
0162 
0163   format::FormatStyle Style = format::getNoStyle();
0164 
0165   // Options for selectively formatting changes with clang-format:
0166   // kAll: Format all changed lines.
0167   // kNone: Don't format anything.
0168   // kViolations: Format lines exceeding the `ColumnLimit` in `Style`.
0169   enum FormatOption { kAll, kNone, kViolations };
0170 
0171   FormatOption Format = kNone;
0172 };
0173 
0174 /// Applies all AtomicChanges in \p Changes to the \p Code.
0175 ///
0176 /// This completely ignores the file path in each change and replaces them with
0177 /// \p FilePath, i.e. callers are responsible for ensuring all changes are for
0178 /// the same file.
0179 ///
0180 /// \returns The changed code if all changes are applied successfully;
0181 /// otherwise, an llvm::Error carrying llvm::StringError is returned (the Error
0182 /// message can be converted to string with `llvm::toString()` and the
0183 /// error_code should be ignored).
0184 llvm::Expected<std::string>
0185 applyAtomicChanges(llvm::StringRef FilePath, llvm::StringRef Code,
0186                    llvm::ArrayRef<AtomicChange> Changes,
0187                    const ApplyChangesSpec &Spec);
0188 
0189 } // end namespace tooling
0190 } // end namespace clang
0191 
0192 #endif // LLVM_CLANG_TOOLING_REFACTORING_ATOMICCHANGE_H