clang API Documentation

Replacement.h
Go to the documentation of this file.
00001 //===--- Replacement.h - Framework for clang refactoring tools --*- C++ -*-===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 //
00010 //  Classes supporting refactorings that span multiple translation units.
00011 //  While single translation unit refactorings are supported via the Rewriter,
00012 //  when refactoring multiple translation units changes must be stored in a
00013 //  SourceManager independent form, duplicate changes need to be removed, and
00014 //  all changes must be applied at once at the end of the refactoring so that
00015 //  the code is always parseable.
00016 //
00017 //===----------------------------------------------------------------------===//
00018 
00019 #ifndef LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H
00020 #define LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H
00021 
00022 #include "clang/Basic/SourceLocation.h"
00023 #include "llvm/ADT/StringRef.h"
00024 #include <set>
00025 #include <string>
00026 #include <vector>
00027 
00028 namespace clang {
00029 
00030 class Rewriter;
00031 
00032 namespace tooling {
00033 
00034 /// \brief A source range independent of the \c SourceManager.
00035 class Range {
00036 public:
00037   Range() : Offset(0), Length(0) {}
00038   Range(unsigned Offset, unsigned Length) : Offset(Offset), Length(Length) {}
00039 
00040   /// \brief Accessors.
00041   /// @{
00042   unsigned getOffset() const { return Offset; }
00043   unsigned getLength() const { return Length; }
00044   /// @}
00045 
00046   /// \name Range Predicates
00047   /// @{
00048   /// \brief Whether this range overlaps with \p RHS or not.
00049   bool overlapsWith(Range RHS) const {
00050     return Offset + Length > RHS.Offset && Offset < RHS.Offset + RHS.Length;
00051   }
00052 
00053   /// \brief Whether this range contains \p RHS or not.
00054   bool contains(Range RHS) const {
00055     return RHS.Offset >= Offset &&
00056            (RHS.Offset + RHS.Length) <= (Offset + Length);
00057   }
00058   /// @}
00059 
00060 private:
00061   unsigned Offset;
00062   unsigned Length;
00063 };
00064 
00065 /// \brief A text replacement.
00066 ///
00067 /// Represents a SourceManager independent replacement of a range of text in a
00068 /// specific file.
00069 class Replacement {
00070 public:
00071   /// \brief Creates an invalid (not applicable) replacement.
00072   Replacement();
00073 
00074   /// \brief Creates a replacement of the range [Offset, Offset+Length) in
00075   /// FilePath with ReplacementText.
00076   ///
00077   /// \param FilePath A source file accessible via a SourceManager.
00078   /// \param Offset The byte offset of the start of the range in the file.
00079   /// \param Length The length of the range in bytes.
00080   Replacement(StringRef FilePath, unsigned Offset,
00081               unsigned Length, StringRef ReplacementText);
00082 
00083   /// \brief Creates a Replacement of the range [Start, Start+Length) with
00084   /// ReplacementText.
00085   Replacement(const SourceManager &Sources, SourceLocation Start, unsigned Length,
00086               StringRef ReplacementText);
00087 
00088   /// \brief Creates a Replacement of the given range with ReplacementText.
00089   Replacement(const SourceManager &Sources, const CharSourceRange &Range,
00090               StringRef ReplacementText);
00091 
00092   /// \brief Creates a Replacement of the node with ReplacementText.
00093   template <typename Node>
00094   Replacement(const SourceManager &Sources, const Node &NodeToReplace,
00095               StringRef ReplacementText);
00096 
00097   /// \brief Returns whether this replacement can be applied to a file.
00098   ///
00099   /// Only replacements that are in a valid file can be applied.
00100   bool isApplicable() const;
00101 
00102   /// \brief Accessors.
00103   /// @{
00104   StringRef getFilePath() const { return FilePath; }
00105   unsigned getOffset() const { return ReplacementRange.getOffset(); }
00106   unsigned getLength() const { return ReplacementRange.getLength(); }
00107   StringRef getReplacementText() const { return ReplacementText; }
00108   /// @}
00109 
00110   /// \brief Applies the replacement on the Rewriter.
00111   bool apply(Rewriter &Rewrite) const;
00112 
00113   /// \brief Returns a human readable string representation.
00114   std::string toString() const;
00115 
00116  private:
00117   void setFromSourceLocation(const SourceManager &Sources, SourceLocation Start,
00118                              unsigned Length, StringRef ReplacementText);
00119   void setFromSourceRange(const SourceManager &Sources,
00120                           const CharSourceRange &Range,
00121                           StringRef ReplacementText);
00122 
00123   std::string FilePath;
00124   Range ReplacementRange;
00125   std::string ReplacementText;
00126 };
00127 
00128 /// \brief Less-than operator between two Replacements.
00129 bool operator<(const Replacement &LHS, const Replacement &RHS);
00130 
00131 /// \brief Equal-to operator between two Replacements.
00132 bool operator==(const Replacement &LHS, const Replacement &RHS);
00133 
00134 /// \brief A set of Replacements.
00135 /// FIXME: Change to a vector and deduplicate in the RefactoringTool.
00136 typedef std::set<Replacement> Replacements;
00137 
00138 /// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
00139 ///
00140 /// Replacement applications happen independently of the success of
00141 /// other applications.
00142 ///
00143 /// \returns true if all replacements apply. false otherwise.
00144 bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite);
00145 
00146 /// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
00147 ///
00148 /// Replacement applications happen independently of the success of
00149 /// other applications.
00150 ///
00151 /// \returns true if all replacements apply. false otherwise.
00152 bool applyAllReplacements(const std::vector<Replacement> &Replaces,
00153                           Rewriter &Rewrite);
00154 
00155 /// \brief Applies all replacements in \p Replaces to \p Code.
00156 ///
00157 /// This completely ignores the path stored in each replacement. If one or more
00158 /// replacements cannot be applied, this returns an empty \c string.
00159 std::string applyAllReplacements(StringRef Code, const Replacements &Replaces);
00160 
00161 /// \brief Calculates how a code \p Position is shifted when \p Replaces are
00162 /// applied.
00163 unsigned shiftedCodePosition(const Replacements& Replaces, unsigned Position);
00164 
00165 /// \brief Calculates how a code \p Position is shifted when \p Replaces are
00166 /// applied.
00167 ///
00168 /// \pre Replaces[i].getOffset() <= Replaces[i+1].getOffset().
00169 unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
00170                              unsigned Position);
00171 
00172 /// \brief Removes duplicate Replacements and reports if Replacements conflict
00173 /// with one another. All Replacements are assumed to be in the same file.
00174 ///
00175 /// \post Replaces[i].getOffset() <= Replaces[i+1].getOffset().
00176 ///
00177 /// This function sorts \p Replaces so that conflicts can be reported simply by
00178 /// offset into \p Replaces and number of elements in the conflict.
00179 void deduplicate(std::vector<Replacement> &Replaces,
00180                  std::vector<Range> &Conflicts);
00181 
00182 /// \brief Collection of Replacements generated from a single translation unit.
00183 struct TranslationUnitReplacements {
00184   /// Name of the main source for the translation unit.
00185   std::string MainSourceFile;
00186 
00187   /// A freeform chunk of text to describe the context of the replacements.
00188   /// Will be printed, for example, when detecting conflicts during replacement
00189   /// deduplication.
00190   std::string Context;
00191 
00192   std::vector<Replacement> Replacements;
00193 };
00194 
00195 /// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
00196 ///
00197 /// Replacement applications happen independently of the success of
00198 /// other applications.
00199 ///
00200 /// \returns true if all replacements apply. false otherwise.
00201 bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite);
00202 
00203 /// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
00204 ///
00205 /// Replacement applications happen independently of the success of
00206 /// other applications.
00207 ///
00208 /// \returns true if all replacements apply. false otherwise.
00209 bool applyAllReplacements(const std::vector<Replacement> &Replaces,
00210                           Rewriter &Rewrite);
00211 
00212 /// \brief Applies all replacements in \p Replaces to \p Code.
00213 ///
00214 /// This completely ignores the path stored in each replacement. If one or more
00215 /// replacements cannot be applied, this returns an empty \c string.
00216 std::string applyAllReplacements(StringRef Code, const Replacements &Replaces);
00217 
00218 template <typename Node>
00219 Replacement::Replacement(const SourceManager &Sources,
00220                          const Node &NodeToReplace, StringRef ReplacementText) {
00221   const CharSourceRange Range =
00222       CharSourceRange::getTokenRange(NodeToReplace->getSourceRange());
00223   setFromSourceRange(Sources, Range, ReplacementText);
00224 }
00225 
00226 } // end namespace tooling
00227 } // end namespace clang
00228 
00229 #endif // LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H