]> granicus.if.org Git - clang/commitdiff
Refactor libTooling to reduce required dependencies.
authorDaniel Jasper <djasper@google.com>
Wed, 29 Oct 2014 18:55:09 +0000 (18:55 +0000)
committerDaniel Jasper <djasper@google.com>
Wed, 29 Oct 2014 18:55:09 +0000 (18:55 +0000)
This moves classes for storing and applying replacements to separate
files. These classes specifically are used by clang-format which doesn't
have any other dependencies on clangAST. Thereby, the size of
clang-format's binary can be cut roughly in half and its build time sped
up.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@220867 91177308-0d34-0410-b5e6-96231b3b80d8

15 files changed:
include/clang/Tooling/Core/Replacement.h [new file with mode: 0644]
include/clang/Tooling/Refactoring.h
lib/Format/CMakeLists.txt
lib/Tooling/CMakeLists.txt
lib/Tooling/Core/CMakeLists.txt [new file with mode: 0644]
lib/Tooling/Core/Makefile [new file with mode: 0644]
lib/Tooling/Core/Replacement.cpp [new file with mode: 0644]
lib/Tooling/Makefile
lib/Tooling/Refactoring.cpp
tools/clang-format/CMakeLists.txt
tools/clang-format/Makefile
tools/libclang/Makefile
unittests/Format/CMakeLists.txt
unittests/Format/Makefile
unittests/Tooling/Makefile

diff --git a/include/clang/Tooling/Core/Replacement.h b/include/clang/Tooling/Core/Replacement.h
new file mode 100644 (file)
index 0000000..30a7036
--- /dev/null
@@ -0,0 +1,229 @@
+//===--- Replacement.h - Framework for clang refactoring tools --*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  Classes supporting refactorings that span multiple translation units.
+//  While single translation unit refactorings are supported via the Rewriter,
+//  when refactoring multiple translation units changes must be stored in a
+//  SourceManager independent form, duplicate changes need to be removed, and
+//  all changes must be applied at once at the end of the refactoring so that
+//  the code is always parseable.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H
+#define LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H
+
+#include "clang/Basic/SourceLocation.h"
+#include "llvm/ADT/StringRef.h"
+#include <set>
+#include <string>
+#include <vector>
+
+namespace clang {
+
+class Rewriter;
+
+namespace tooling {
+
+/// \brief A source range independent of the \c SourceManager.
+class Range {
+public:
+  Range() : Offset(0), Length(0) {}
+  Range(unsigned Offset, unsigned Length) : Offset(Offset), Length(Length) {}
+
+  /// \brief Accessors.
+  /// @{
+  unsigned getOffset() const { return Offset; }
+  unsigned getLength() const { return Length; }
+  /// @}
+
+  /// \name Range Predicates
+  /// @{
+  /// \brief Whether this range overlaps with \p RHS or not.
+  bool overlapsWith(Range RHS) const {
+    return Offset + Length > RHS.Offset && Offset < RHS.Offset + RHS.Length;
+  }
+
+  /// \brief Whether this range contains \p RHS or not.
+  bool contains(Range RHS) const {
+    return RHS.Offset >= Offset &&
+           (RHS.Offset + RHS.Length) <= (Offset + Length);
+  }
+  /// @}
+
+private:
+  unsigned Offset;
+  unsigned Length;
+};
+
+/// \brief A text replacement.
+///
+/// Represents a SourceManager independent replacement of a range of text in a
+/// specific file.
+class Replacement {
+public:
+  /// \brief Creates an invalid (not applicable) replacement.
+  Replacement();
+
+  /// \brief Creates a replacement of the range [Offset, Offset+Length) in
+  /// FilePath with ReplacementText.
+  ///
+  /// \param FilePath A source file accessible via a SourceManager.
+  /// \param Offset The byte offset of the start of the range in the file.
+  /// \param Length The length of the range in bytes.
+  Replacement(StringRef FilePath, unsigned Offset,
+              unsigned Length, StringRef ReplacementText);
+
+  /// \brief Creates a Replacement of the range [Start, Start+Length) with
+  /// ReplacementText.
+  Replacement(const SourceManager &Sources, SourceLocation Start, unsigned Length,
+              StringRef ReplacementText);
+
+  /// \brief Creates a Replacement of the given range with ReplacementText.
+  Replacement(const SourceManager &Sources, const CharSourceRange &Range,
+              StringRef ReplacementText);
+
+  /// \brief Creates a Replacement of the node with ReplacementText.
+  template <typename Node>
+  Replacement(const SourceManager &Sources, const Node &NodeToReplace,
+              StringRef ReplacementText);
+
+  /// \brief Returns whether this replacement can be applied to a file.
+  ///
+  /// Only replacements that are in a valid file can be applied.
+  bool isApplicable() const;
+
+  /// \brief Accessors.
+  /// @{
+  StringRef getFilePath() const { return FilePath; }
+  unsigned getOffset() const { return ReplacementRange.getOffset(); }
+  unsigned getLength() const { return ReplacementRange.getLength(); }
+  StringRef getReplacementText() const { return ReplacementText; }
+  /// @}
+
+  /// \brief Applies the replacement on the Rewriter.
+  bool apply(Rewriter &Rewrite) const;
+
+  /// \brief Returns a human readable string representation.
+  std::string toString() const;
+
+ private:
+  void setFromSourceLocation(const SourceManager &Sources, SourceLocation Start,
+                             unsigned Length, StringRef ReplacementText);
+  void setFromSourceRange(const SourceManager &Sources,
+                          const CharSourceRange &Range,
+                          StringRef ReplacementText);
+
+  std::string FilePath;
+  Range ReplacementRange;
+  std::string ReplacementText;
+};
+
+/// \brief Less-than operator between two Replacements.
+bool operator<(const Replacement &LHS, const Replacement &RHS);
+
+/// \brief Equal-to operator between two Replacements.
+bool operator==(const Replacement &LHS, const Replacement &RHS);
+
+/// \brief A set of Replacements.
+/// FIXME: Change to a vector and deduplicate in the RefactoringTool.
+typedef std::set<Replacement> Replacements;
+
+/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
+///
+/// Replacement applications happen independently of the success of
+/// other applications.
+///
+/// \returns true if all replacements apply. false otherwise.
+bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite);
+
+/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
+///
+/// Replacement applications happen independently of the success of
+/// other applications.
+///
+/// \returns true if all replacements apply. false otherwise.
+bool applyAllReplacements(const std::vector<Replacement> &Replaces,
+                          Rewriter &Rewrite);
+
+/// \brief Applies all replacements in \p Replaces to \p Code.
+///
+/// This completely ignores the path stored in each replacement. If one or more
+/// replacements cannot be applied, this returns an empty \c string.
+std::string applyAllReplacements(StringRef Code, const Replacements &Replaces);
+
+/// \brief Calculates how a code \p Position is shifted when \p Replaces are
+/// applied.
+unsigned shiftedCodePosition(const Replacements& Replaces, unsigned Position);
+
+/// \brief Calculates how a code \p Position is shifted when \p Replaces are
+/// applied.
+///
+/// \pre Replaces[i].getOffset() <= Replaces[i+1].getOffset().
+unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
+                             unsigned Position);
+
+/// \brief Removes duplicate Replacements and reports if Replacements conflict
+/// with one another. All Replacements are assumed to be in the same file.
+///
+/// \post Replaces[i].getOffset() <= Replaces[i+1].getOffset().
+///
+/// This function sorts \p Replaces so that conflicts can be reported simply by
+/// offset into \p Replaces and number of elements in the conflict.
+void deduplicate(std::vector<Replacement> &Replaces,
+                 std::vector<Range> &Conflicts);
+
+/// \brief Collection of Replacements generated from a single translation unit.
+struct TranslationUnitReplacements {
+  /// Name of the main source for the translation unit.
+  std::string MainSourceFile;
+
+  /// A freeform chunk of text to describe the context of the replacements.
+  /// Will be printed, for example, when detecting conflicts during replacement
+  /// deduplication.
+  std::string Context;
+
+  std::vector<Replacement> Replacements;
+};
+
+/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
+///
+/// Replacement applications happen independently of the success of
+/// other applications.
+///
+/// \returns true if all replacements apply. false otherwise.
+bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite);
+
+/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
+///
+/// Replacement applications happen independently of the success of
+/// other applications.
+///
+/// \returns true if all replacements apply. false otherwise.
+bool applyAllReplacements(const std::vector<Replacement> &Replaces,
+                          Rewriter &Rewrite);
+
+/// \brief Applies all replacements in \p Replaces to \p Code.
+///
+/// This completely ignores the path stored in each replacement. If one or more
+/// replacements cannot be applied, this returns an empty \c string.
+std::string applyAllReplacements(StringRef Code, const Replacements &Replaces);
+
+template <typename Node>
+Replacement::Replacement(const SourceManager &Sources,
+                         const Node &NodeToReplace, StringRef ReplacementText) {
+  const CharSourceRange Range =
+      CharSourceRange::getTokenRange(NodeToReplace->getSourceRange());
+  setFromSourceRange(Sources, Range, ReplacementText);
+}
+
+} // end namespace tooling
+} // end namespace clang
+
+#endif // LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H
index 6eb7b07c6b3c0844a6bbdedc56839f62b2769451..e3e7f83c38c838f286e9ba9e2a003657abae1c8f 100644 (file)
 #ifndef LLVM_CLANG_TOOLING_REFACTORING_H
 #define LLVM_CLANG_TOOLING_REFACTORING_H
 
-#include "clang/Basic/SourceLocation.h"
+#include "clang/Tooling/Core/Replacement.h"
 #include "clang/Tooling/Tooling.h"
-#include "llvm/ADT/StringRef.h"
-#include <set>
 #include <string>
 
 namespace clang {
 
 class Rewriter;
-class SourceLocation;
 
 namespace tooling {
 
-/// \brief A source range independent of the \c SourceManager.
-class Range {
-public:
-  Range() : Offset(0), Length(0) {}
-  Range(unsigned Offset, unsigned Length) : Offset(Offset), Length(Length) {}
-
-  /// \brief Accessors.
-  /// @{
-  unsigned getOffset() const { return Offset; }
-  unsigned getLength() const { return Length; }
-  /// @}
-
-  /// \name Range Predicates
-  /// @{
-  /// \brief Whether this range overlaps with \p RHS or not.
-  bool overlapsWith(Range RHS) const {
-    return Offset + Length > RHS.Offset && Offset < RHS.Offset + RHS.Length;
-  }
-
-  /// \brief Whether this range contains \p RHS or not.
-  bool contains(Range RHS) const {
-    return RHS.Offset >= Offset &&
-           (RHS.Offset + RHS.Length) <= (Offset + Length);
-  }
-  /// @}
-
-private:
-  unsigned Offset;
-  unsigned Length;
-};
-
-/// \brief A text replacement.
-///
-/// Represents a SourceManager independent replacement of a range of text in a
-/// specific file.
-class Replacement {
-public:
-  /// \brief Creates an invalid (not applicable) replacement.
-  Replacement();
-
-  /// \brief Creates a replacement of the range [Offset, Offset+Length) in
-  /// FilePath with ReplacementText.
-  ///
-  /// \param FilePath A source file accessible via a SourceManager.
-  /// \param Offset The byte offset of the start of the range in the file.
-  /// \param Length The length of the range in bytes.
-  Replacement(StringRef FilePath, unsigned Offset,
-              unsigned Length, StringRef ReplacementText);
-
-  /// \brief Creates a Replacement of the range [Start, Start+Length) with
-  /// ReplacementText.
-  Replacement(const SourceManager &Sources, SourceLocation Start, unsigned Length,
-              StringRef ReplacementText);
-
-  /// \brief Creates a Replacement of the given range with ReplacementText.
-  Replacement(const SourceManager &Sources, const CharSourceRange &Range,
-              StringRef ReplacementText);
-
-  /// \brief Creates a Replacement of the node with ReplacementText.
-  template <typename Node>
-  Replacement(const SourceManager &Sources, const Node &NodeToReplace,
-              StringRef ReplacementText);
-
-  /// \brief Returns whether this replacement can be applied to a file.
-  ///
-  /// Only replacements that are in a valid file can be applied.
-  bool isApplicable() const;
-
-  /// \brief Accessors.
-  /// @{
-  StringRef getFilePath() const { return FilePath; }
-  unsigned getOffset() const { return ReplacementRange.getOffset(); }
-  unsigned getLength() const { return ReplacementRange.getLength(); }
-  StringRef getReplacementText() const { return ReplacementText; }
-  /// @}
-
-  /// \brief Applies the replacement on the Rewriter.
-  bool apply(Rewriter &Rewrite) const;
-
-  /// \brief Returns a human readable string representation.
-  std::string toString() const;
-
- private:
-  void setFromSourceLocation(const SourceManager &Sources, SourceLocation Start,
-                             unsigned Length, StringRef ReplacementText);
-  void setFromSourceRange(const SourceManager &Sources,
-                          const CharSourceRange &Range,
-                          StringRef ReplacementText);
-
-  std::string FilePath;
-  Range ReplacementRange;
-  std::string ReplacementText;
-};
-
-/// \brief Less-than operator between two Replacements.
-bool operator<(const Replacement &LHS, const Replacement &RHS);
-
-/// \brief Equal-to operator between two Replacements.
-bool operator==(const Replacement &LHS, const Replacement &RHS);
-
-/// \brief A set of Replacements.
-/// FIXME: Change to a vector and deduplicate in the RefactoringTool.
-typedef std::set<Replacement> Replacements;
-
-/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
-///
-/// Replacement applications happen independently of the success of
-/// other applications.
-///
-/// \returns true if all replacements apply. false otherwise.
-bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite);
-
-/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
-///
-/// Replacement applications happen independently of the success of
-/// other applications.
-///
-/// \returns true if all replacements apply. false otherwise.
-bool applyAllReplacements(const std::vector<Replacement> &Replaces,
-                          Rewriter &Rewrite);
-
-/// \brief Applies all replacements in \p Replaces to \p Code.
-///
-/// This completely ignores the path stored in each replacement. If one or more
-/// replacements cannot be applied, this returns an empty \c string.
-std::string applyAllReplacements(StringRef Code, const Replacements &Replaces);
-
-/// \brief Calculates how a code \p Position is shifted when \p Replaces are
-/// applied.
-unsigned shiftedCodePosition(const Replacements& Replaces, unsigned Position);
-
-/// \brief Calculates how a code \p Position is shifted when \p Replaces are
-/// applied.
-///
-/// \pre Replaces[i].getOffset() <= Replaces[i+1].getOffset().
-unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
-                             unsigned Position);
-
-/// \brief Removes duplicate Replacements and reports if Replacements conflict
-/// with one another. All Replacements are assumed to be in the same file.
-///
-/// \post Replaces[i].getOffset() <= Replaces[i+1].getOffset().
-///
-/// This function sorts \p Replaces so that conflicts can be reported simply by
-/// offset into \p Replaces and number of elements in the conflict.
-void deduplicate(std::vector<Replacement> &Replaces,
-                 std::vector<Range> &Conflicts);
-
-/// \brief Collection of Replacements generated from a single translation unit.
-struct TranslationUnitReplacements {
-  /// Name of the main source for the translation unit.
-  std::string MainSourceFile;
-
-  /// A freeform chunk of text to describe the context of the replacements.
-  /// Will be printed, for example, when detecting conflicts during replacement
-  /// deduplication.
-  std::string Context;
-
-  std::vector<Replacement> Replacements;
-};
-
 /// \brief A tool to run refactorings.
 ///
 /// This is a refactoring specific version of \see ClangTool. FrontendActions
@@ -230,14 +66,6 @@ private:
   Replacements Replace;
 };
 
-template <typename Node>
-Replacement::Replacement(const SourceManager &Sources,
-                         const Node &NodeToReplace, StringRef ReplacementText) {
-  const CharSourceRange Range =
-      CharSourceRange::getTokenRange(NodeToReplace->getSourceRange());
-  setFromSourceRange(Sources, Range, ReplacementText);
-}
-
 } // end namespace tooling
 } // end namespace clang
 
index 47e15bd08a3f9fb0527accc8e8d73c9e7d42f709..3f08d9d0b5e4d0f9aafc27ecbcf7dca664e85bfa 100644 (file)
@@ -12,5 +12,5 @@ add_clang_library(clangFormat
   LINK_LIBS
   clangBasic
   clangLex
-  clangTooling
+  clangToolingCore
   )
index 2bf9652fa376feeaacb7e25a1a2b2cc1c43ad0f5..b5c3d54e5fc1070c789c387a3b93dac6385a1cf4 100644 (file)
@@ -1,5 +1,7 @@
 set(LLVM_LINK_COMPONENTS support)
 
+add_subdirectory(Core)
+
 add_clang_library(clangTooling
   ArgumentsAdjusters.cpp
   CommonOptionsParser.cpp
@@ -18,4 +20,5 @@ add_clang_library(clangTooling
   clangFrontend
   clangLex
   clangRewrite
+  clangToolingCore
   )
diff --git a/lib/Tooling/Core/CMakeLists.txt b/lib/Tooling/Core/CMakeLists.txt
new file mode 100644 (file)
index 0000000..fcf3666
--- /dev/null
@@ -0,0 +1,10 @@
+set(LLVM_LINK_COMPONENTS support)
+
+add_clang_library(clangToolingCore
+  Replacement.cpp
+
+  LINK_LIBS
+  clangBasic
+  clangDriver
+  clangRewrite
+  )
diff --git a/lib/Tooling/Core/Makefile b/lib/Tooling/Core/Makefile
new file mode 100644 (file)
index 0000000..366466c
--- /dev/null
@@ -0,0 +1,13 @@
+##===- clang/lib/Tooling/Core/Makefile ---------------------*- Makefile -*-===##
+#
+#                     The LLVM Compiler Infrastructure
+#
+# This file is distributed under the University of Illinois Open Source
+# License. See LICENSE.TXT for details.
+#
+##===----------------------------------------------------------------------===##
+
+CLANG_LEVEL := ../../..
+LIBRARYNAME := clangToolingCore
+
+include $(CLANG_LEVEL)/Makefile
diff --git a/lib/Tooling/Core/Replacement.cpp b/lib/Tooling/Core/Replacement.cpp
new file mode 100644 (file)
index 0000000..525f7df
--- /dev/null
@@ -0,0 +1,289 @@
+//===--- Replacement.cpp - Framework for clang refactoring tools ----------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//  Implements classes to support/store refactorings.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_os_ostream.h"
+
+namespace clang {
+namespace tooling {
+
+static const char * const InvalidLocation = "";
+
+Replacement::Replacement()
+  : FilePath(InvalidLocation) {}
+
+Replacement::Replacement(StringRef FilePath, unsigned Offset, unsigned Length,
+                         StringRef ReplacementText)
+    : FilePath(FilePath), ReplacementRange(Offset, Length),
+      ReplacementText(ReplacementText) {}
+
+Replacement::Replacement(const SourceManager &Sources, SourceLocation Start,
+                         unsigned Length, StringRef ReplacementText) {
+  setFromSourceLocation(Sources, Start, Length, ReplacementText);
+}
+
+Replacement::Replacement(const SourceManager &Sources,
+                         const CharSourceRange &Range,
+                         StringRef ReplacementText) {
+  setFromSourceRange(Sources, Range, ReplacementText);
+}
+
+bool Replacement::isApplicable() const {
+  return FilePath != InvalidLocation;
+}
+
+bool Replacement::apply(Rewriter &Rewrite) const {
+  SourceManager &SM = Rewrite.getSourceMgr();
+  const FileEntry *Entry = SM.getFileManager().getFile(FilePath);
+  if (!Entry)
+    return false;
+  FileID ID;
+  // FIXME: Use SM.translateFile directly.
+  SourceLocation Location = SM.translateFileLineCol(Entry, 1, 1);
+  ID = Location.isValid() ?
+    SM.getFileID(Location) :
+    SM.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
+  // FIXME: We cannot check whether Offset + Length is in the file, as
+  // the remapping API is not public in the RewriteBuffer.
+  const SourceLocation Start =
+    SM.getLocForStartOfFile(ID).
+    getLocWithOffset(ReplacementRange.getOffset());
+  // ReplaceText returns false on success.
+  // ReplaceText only fails if the source location is not a file location, in
+  // which case we already returned false earlier.
+  bool RewriteSucceeded = !Rewrite.ReplaceText(
+      Start, ReplacementRange.getLength(), ReplacementText);
+  assert(RewriteSucceeded);
+  return RewriteSucceeded;
+}
+
+std::string Replacement::toString() const {
+  std::string result;
+  llvm::raw_string_ostream stream(result);
+  stream << FilePath << ": " << ReplacementRange.getOffset() << ":+"
+         << ReplacementRange.getLength() << ":\"" << ReplacementText << "\"";
+  return result;
+}
+
+bool operator<(const Replacement &LHS, const Replacement &RHS) {
+  if (LHS.getOffset() != RHS.getOffset())
+    return LHS.getOffset() < RHS.getOffset();
+  if (LHS.getLength() != RHS.getLength())
+    return LHS.getLength() < RHS.getLength();
+  if (LHS.getFilePath() != RHS.getFilePath())
+    return LHS.getFilePath() < RHS.getFilePath();
+  return LHS.getReplacementText() < RHS.getReplacementText();
+}
+
+bool operator==(const Replacement &LHS, const Replacement &RHS) {
+  return LHS.getOffset() == RHS.getOffset() &&
+         LHS.getLength() == RHS.getLength() &&
+         LHS.getFilePath() == RHS.getFilePath() &&
+         LHS.getReplacementText() == RHS.getReplacementText();
+}
+
+void Replacement::setFromSourceLocation(const SourceManager &Sources,
+                                        SourceLocation Start, unsigned Length,
+                                        StringRef ReplacementText) {
+  const std::pair<FileID, unsigned> DecomposedLocation =
+      Sources.getDecomposedLoc(Start);
+  const FileEntry *Entry = Sources.getFileEntryForID(DecomposedLocation.first);
+  if (Entry) {
+    // Make FilePath absolute so replacements can be applied correctly when
+    // relative paths for files are used.
+    llvm::SmallString<256> FilePath(Entry->getName());
+    std::error_code EC = llvm::sys::fs::make_absolute(FilePath);
+    this->FilePath = EC ? FilePath.c_str() : Entry->getName();
+  } else {
+    this->FilePath = InvalidLocation;
+  }
+  this->ReplacementRange = Range(DecomposedLocation.second, Length);
+  this->ReplacementText = ReplacementText;
+}
+
+// FIXME: This should go into the Lexer, but we need to figure out how
+// to handle ranges for refactoring in general first - there is no obvious
+// good way how to integrate this into the Lexer yet.
+static int getRangeSize(const SourceManager &Sources,
+                        const CharSourceRange &Range) {
+  SourceLocation SpellingBegin = Sources.getSpellingLoc(Range.getBegin());
+  SourceLocation SpellingEnd = Sources.getSpellingLoc(Range.getEnd());
+  std::pair<FileID, unsigned> Start = Sources.getDecomposedLoc(SpellingBegin);
+  std::pair<FileID, unsigned> End = Sources.getDecomposedLoc(SpellingEnd);
+  if (Start.first != End.first) return -1;
+  if (Range.isTokenRange())
+    End.second += Lexer::MeasureTokenLength(SpellingEnd, Sources,
+                                            LangOptions());
+  return End.second - Start.second;
+}
+
+void Replacement::setFromSourceRange(const SourceManager &Sources,
+                                     const CharSourceRange &Range,
+                                     StringRef ReplacementText) {
+  setFromSourceLocation(Sources, Sources.getSpellingLoc(Range.getBegin()),
+                        getRangeSize(Sources, Range), ReplacementText);
+}
+
+unsigned shiftedCodePosition(const Replacements &Replaces, unsigned Position) {
+  unsigned NewPosition = Position;
+  for (Replacements::iterator I = Replaces.begin(), E = Replaces.end(); I != E;
+       ++I) {
+    if (I->getOffset() >= Position)
+      break;
+    if (I->getOffset() + I->getLength() > Position)
+      NewPosition += I->getOffset() + I->getLength() - Position;
+    NewPosition += I->getReplacementText().size() - I->getLength();
+  }
+  return NewPosition;
+}
+
+// FIXME: Remove this function when Replacements is implemented as std::vector
+// instead of std::set.
+unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
+                             unsigned Position) {
+  unsigned NewPosition = Position;
+  for (std::vector<Replacement>::const_iterator I = Replaces.begin(),
+                                                E = Replaces.end();
+       I != E; ++I) {
+    if (I->getOffset() >= Position)
+      break;
+    if (I->getOffset() + I->getLength() > Position)
+      NewPosition += I->getOffset() + I->getLength() - Position;
+    NewPosition += I->getReplacementText().size() - I->getLength();
+  }
+  return NewPosition;
+}
+
+void deduplicate(std::vector<Replacement> &Replaces,
+                 std::vector<Range> &Conflicts) {
+  if (Replaces.empty())
+    return;
+
+  auto LessNoPath = [](const Replacement &LHS, const Replacement &RHS) {
+    if (LHS.getOffset() != RHS.getOffset())
+      return LHS.getOffset() < RHS.getOffset();
+    if (LHS.getLength() != RHS.getLength())
+      return LHS.getLength() < RHS.getLength();
+    return LHS.getReplacementText() < RHS.getReplacementText();
+  };
+
+  auto EqualNoPath = [](const Replacement &LHS, const Replacement &RHS) {
+    return LHS.getOffset() == RHS.getOffset() &&
+           LHS.getLength() == RHS.getLength() &&
+           LHS.getReplacementText() == RHS.getReplacementText();
+  };
+
+  // Deduplicate. We don't want to deduplicate based on the path as we assume
+  // that all replacements refer to the same file (or are symlinks).
+  std::sort(Replaces.begin(), Replaces.end(), LessNoPath);
+  Replaces.erase(std::unique(Replaces.begin(), Replaces.end(), EqualNoPath),
+                 Replaces.end());
+
+  // Detect conflicts
+  Range ConflictRange(Replaces.front().getOffset(),
+                      Replaces.front().getLength());
+  unsigned ConflictStart = 0;
+  unsigned ConflictLength = 1;
+  for (unsigned i = 1; i < Replaces.size(); ++i) {
+    Range Current(Replaces[i].getOffset(), Replaces[i].getLength());
+    if (ConflictRange.overlapsWith(Current)) {
+      // Extend conflicted range
+      ConflictRange = Range(ConflictRange.getOffset(),
+                            std::max(ConflictRange.getLength(),
+                                     Current.getOffset() + Current.getLength() -
+                                         ConflictRange.getOffset()));
+      ++ConflictLength;
+    } else {
+      if (ConflictLength > 1)
+        Conflicts.push_back(Range(ConflictStart, ConflictLength));
+      ConflictRange = Current;
+      ConflictStart = i;
+      ConflictLength = 1;
+    }
+  }
+
+  if (ConflictLength > 1)
+    Conflicts.push_back(Range(ConflictStart, ConflictLength));
+}
+
+bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite) {
+  bool Result = true;
+  for (Replacements::const_iterator I = Replaces.begin(),
+                                    E = Replaces.end();
+       I != E; ++I) {
+    if (I->isApplicable()) {
+      Result = I->apply(Rewrite) && Result;
+    } else {
+      Result = false;
+    }
+  }
+  return Result;
+}
+
+// FIXME: Remove this function when Replacements is implemented as std::vector
+// instead of std::set.
+bool applyAllReplacements(const std::vector<Replacement> &Replaces,
+                          Rewriter &Rewrite) {
+  bool Result = true;
+  for (std::vector<Replacement>::const_iterator I = Replaces.begin(),
+                                                E = Replaces.end();
+       I != E; ++I) {
+    if (I->isApplicable()) {
+      Result = I->apply(Rewrite) && Result;
+    } else {
+      Result = false;
+    }
+  }
+  return Result;
+}
+
+std::string applyAllReplacements(StringRef Code, const Replacements &Replaces) {
+  FileManager Files((FileSystemOptions()));
+  DiagnosticsEngine Diagnostics(
+      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
+      new DiagnosticOptions);
+  SourceManager SourceMgr(Diagnostics, Files);
+  Rewriter Rewrite(SourceMgr, LangOptions());
+  std::unique_ptr<llvm::MemoryBuffer> Buf =
+      llvm::MemoryBuffer::getMemBuffer(Code, "<stdin>");
+  const clang::FileEntry *Entry =
+      Files.getVirtualFile("<stdin>", Buf->getBufferSize(), 0);
+  SourceMgr.overrideFileContents(Entry, std::move(Buf));
+  FileID ID =
+      SourceMgr.createFileID(Entry, SourceLocation(), clang::SrcMgr::C_User);
+  for (Replacements::const_iterator I = Replaces.begin(), E = Replaces.end();
+       I != E; ++I) {
+    Replacement Replace("<stdin>", I->getOffset(), I->getLength(),
+                        I->getReplacementText());
+    if (!Replace.apply(Rewrite))
+      return "";
+  }
+  std::string Result;
+  llvm::raw_string_ostream OS(Result);
+  Rewrite.getEditBuffer(ID).write(OS);
+  OS.flush();
+  return Result;
+}
+
+} // end namespace tooling
+} // end namespace clang
+
index 0d2e7a29bcf96ef7e47d31650e6c39d8b547d661..7ea85a8908d6c6c44cb3d6a0524289e51fdc99f5 100644 (file)
@@ -9,5 +9,6 @@
 
 CLANG_LEVEL := ../..
 LIBRARYNAME := clangTooling
+PARALLEL_DIRS := Core
 
 include $(CLANG_LEVEL)/Makefile
index 1dadaa7a384c6ba6dfed7c57df9d6a36cbc14c06..c8173060d8c11c30d369ca784cd58fb563f8a764 100644 (file)
 namespace clang {
 namespace tooling {
 
-static const char * const InvalidLocation = "";
-
-Replacement::Replacement()
-  : FilePath(InvalidLocation) {}
-
-Replacement::Replacement(StringRef FilePath, unsigned Offset, unsigned Length,
-                         StringRef ReplacementText)
-    : FilePath(FilePath), ReplacementRange(Offset, Length),
-      ReplacementText(ReplacementText) {}
-
-Replacement::Replacement(const SourceManager &Sources, SourceLocation Start,
-                         unsigned Length, StringRef ReplacementText) {
-  setFromSourceLocation(Sources, Start, Length, ReplacementText);
-}
-
-Replacement::Replacement(const SourceManager &Sources,
-                         const CharSourceRange &Range,
-                         StringRef ReplacementText) {
-  setFromSourceRange(Sources, Range, ReplacementText);
-}
-
-bool Replacement::isApplicable() const {
-  return FilePath != InvalidLocation;
-}
-
-bool Replacement::apply(Rewriter &Rewrite) const {
-  SourceManager &SM = Rewrite.getSourceMgr();
-  const FileEntry *Entry = SM.getFileManager().getFile(FilePath);
-  if (!Entry)
-    return false;
-  FileID ID;
-  // FIXME: Use SM.translateFile directly.
-  SourceLocation Location = SM.translateFileLineCol(Entry, 1, 1);
-  ID = Location.isValid() ?
-    SM.getFileID(Location) :
-    SM.createFileID(Entry, SourceLocation(), SrcMgr::C_User);
-  // FIXME: We cannot check whether Offset + Length is in the file, as
-  // the remapping API is not public in the RewriteBuffer.
-  const SourceLocation Start =
-    SM.getLocForStartOfFile(ID).
-    getLocWithOffset(ReplacementRange.getOffset());
-  // ReplaceText returns false on success.
-  // ReplaceText only fails if the source location is not a file location, in
-  // which case we already returned false earlier.
-  bool RewriteSucceeded = !Rewrite.ReplaceText(
-      Start, ReplacementRange.getLength(), ReplacementText);
-  assert(RewriteSucceeded);
-  return RewriteSucceeded;
-}
-
-std::string Replacement::toString() const {
-  std::string result;
-  llvm::raw_string_ostream stream(result);
-  stream << FilePath << ": " << ReplacementRange.getOffset() << ":+"
-         << ReplacementRange.getLength() << ":\"" << ReplacementText << "\"";
-  return result;
-}
-
-bool operator<(const Replacement &LHS, const Replacement &RHS) {
-  if (LHS.getOffset() != RHS.getOffset())
-    return LHS.getOffset() < RHS.getOffset();
-  if (LHS.getLength() != RHS.getLength())
-    return LHS.getLength() < RHS.getLength();
-  if (LHS.getFilePath() != RHS.getFilePath())
-    return LHS.getFilePath() < RHS.getFilePath();
-  return LHS.getReplacementText() < RHS.getReplacementText();
-}
-
-bool operator==(const Replacement &LHS, const Replacement &RHS) {
-  return LHS.getOffset() == RHS.getOffset() &&
-         LHS.getLength() == RHS.getLength() &&
-         LHS.getFilePath() == RHS.getFilePath() &&
-         LHS.getReplacementText() == RHS.getReplacementText();
-}
-
-void Replacement::setFromSourceLocation(const SourceManager &Sources,
-                                        SourceLocation Start, unsigned Length,
-                                        StringRef ReplacementText) {
-  const std::pair<FileID, unsigned> DecomposedLocation =
-      Sources.getDecomposedLoc(Start);
-  const FileEntry *Entry = Sources.getFileEntryForID(DecomposedLocation.first);
-  if (Entry) {
-    // Make FilePath absolute so replacements can be applied correctly when
-    // relative paths for files are used.
-    llvm::SmallString<256> FilePath(Entry->getName());
-    std::error_code EC = llvm::sys::fs::make_absolute(FilePath);
-    this->FilePath = EC ? FilePath.c_str() : Entry->getName();
-  } else {
-    this->FilePath = InvalidLocation;
-  }
-  this->ReplacementRange = Range(DecomposedLocation.second, Length);
-  this->ReplacementText = ReplacementText;
-}
-
-// FIXME: This should go into the Lexer, but we need to figure out how
-// to handle ranges for refactoring in general first - there is no obvious
-// good way how to integrate this into the Lexer yet.
-static int getRangeSize(const SourceManager &Sources,
-                        const CharSourceRange &Range) {
-  SourceLocation SpellingBegin = Sources.getSpellingLoc(Range.getBegin());
-  SourceLocation SpellingEnd = Sources.getSpellingLoc(Range.getEnd());
-  std::pair<FileID, unsigned> Start = Sources.getDecomposedLoc(SpellingBegin);
-  std::pair<FileID, unsigned> End = Sources.getDecomposedLoc(SpellingEnd);
-  if (Start.first != End.first) return -1;
-  if (Range.isTokenRange())
-    End.second += Lexer::MeasureTokenLength(SpellingEnd, Sources,
-                                            LangOptions());
-  return End.second - Start.second;
-}
-
-void Replacement::setFromSourceRange(const SourceManager &Sources,
-                                     const CharSourceRange &Range,
-                                     StringRef ReplacementText) {
-  setFromSourceLocation(Sources, Sources.getSpellingLoc(Range.getBegin()),
-                        getRangeSize(Sources, Range), ReplacementText);
-}
-
-bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite) {
-  bool Result = true;
-  for (Replacements::const_iterator I = Replaces.begin(),
-                                    E = Replaces.end();
-       I != E; ++I) {
-    if (I->isApplicable()) {
-      Result = I->apply(Rewrite) && Result;
-    } else {
-      Result = false;
-    }
-  }
-  return Result;
-}
-
-// FIXME: Remove this function when Replacements is implemented as std::vector
-// instead of std::set.
-bool applyAllReplacements(const std::vector<Replacement> &Replaces,
-                          Rewriter &Rewrite) {
-  bool Result = true;
-  for (std::vector<Replacement>::const_iterator I = Replaces.begin(),
-                                                E = Replaces.end();
-       I != E; ++I) {
-    if (I->isApplicable()) {
-      Result = I->apply(Rewrite) && Result;
-    } else {
-      Result = false;
-    }
-  }
-  return Result;
-}
-
-std::string applyAllReplacements(StringRef Code, const Replacements &Replaces) {
-  FileManager Files((FileSystemOptions()));
-  DiagnosticsEngine Diagnostics(
-      IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs),
-      new DiagnosticOptions);
-  Diagnostics.setClient(new TextDiagnosticPrinter(
-      llvm::outs(), &Diagnostics.getDiagnosticOptions()));
-  SourceManager SourceMgr(Diagnostics, Files);
-  Rewriter Rewrite(SourceMgr, LangOptions());
-  std::unique_ptr<llvm::MemoryBuffer> Buf =
-      llvm::MemoryBuffer::getMemBuffer(Code, "<stdin>");
-  const clang::FileEntry *Entry =
-      Files.getVirtualFile("<stdin>", Buf->getBufferSize(), 0);
-  SourceMgr.overrideFileContents(Entry, std::move(Buf));
-  FileID ID =
-      SourceMgr.createFileID(Entry, SourceLocation(), clang::SrcMgr::C_User);
-  for (Replacements::const_iterator I = Replaces.begin(), E = Replaces.end();
-       I != E; ++I) {
-    Replacement Replace("<stdin>", I->getOffset(), I->getLength(),
-                        I->getReplacementText());
-    if (!Replace.apply(Rewrite))
-      return "";
-  }
-  std::string Result;
-  llvm::raw_string_ostream OS(Result);
-  Rewrite.getEditBuffer(ID).write(OS);
-  OS.flush();
-  return Result;
-}
-
-unsigned shiftedCodePosition(const Replacements &Replaces, unsigned Position) {
-  unsigned NewPosition = Position;
-  for (Replacements::iterator I = Replaces.begin(), E = Replaces.end(); I != E;
-       ++I) {
-    if (I->getOffset() >= Position)
-      break;
-    if (I->getOffset() + I->getLength() > Position)
-      NewPosition += I->getOffset() + I->getLength() - Position;
-    NewPosition += I->getReplacementText().size() - I->getLength();
-  }
-  return NewPosition;
-}
-
-// FIXME: Remove this function when Replacements is implemented as std::vector
-// instead of std::set.
-unsigned shiftedCodePosition(const std::vector<Replacement> &Replaces,
-                             unsigned Position) {
-  unsigned NewPosition = Position;
-  for (std::vector<Replacement>::const_iterator I = Replaces.begin(),
-                                                E = Replaces.end();
-       I != E; ++I) {
-    if (I->getOffset() >= Position)
-      break;
-    if (I->getOffset() + I->getLength() > Position)
-      NewPosition += I->getOffset() + I->getLength() - Position;
-    NewPosition += I->getReplacementText().size() - I->getLength();
-  }
-  return NewPosition;
-}
-
-void deduplicate(std::vector<Replacement> &Replaces,
-                 std::vector<Range> &Conflicts) {
-  if (Replaces.empty())
-    return;
-
-  auto LessNoPath = [](const Replacement &LHS, const Replacement &RHS) {
-    if (LHS.getOffset() != RHS.getOffset())
-      return LHS.getOffset() < RHS.getOffset();
-    if (LHS.getLength() != RHS.getLength())
-      return LHS.getLength() < RHS.getLength();
-    return LHS.getReplacementText() < RHS.getReplacementText();
-  };
-
-  auto EqualNoPath = [](const Replacement &LHS, const Replacement &RHS) {
-    return LHS.getOffset() == RHS.getOffset() &&
-           LHS.getLength() == RHS.getLength() &&
-           LHS.getReplacementText() == RHS.getReplacementText();
-  };
-
-  // Deduplicate. We don't want to deduplicate based on the path as we assume
-  // that all replacements refer to the same file (or are symlinks).
-  std::sort(Replaces.begin(), Replaces.end(), LessNoPath);
-  Replaces.erase(std::unique(Replaces.begin(), Replaces.end(), EqualNoPath),
-                 Replaces.end());
-
-  // Detect conflicts
-  Range ConflictRange(Replaces.front().getOffset(),
-                      Replaces.front().getLength());
-  unsigned ConflictStart = 0;
-  unsigned ConflictLength = 1;
-  for (unsigned i = 1; i < Replaces.size(); ++i) {
-    Range Current(Replaces[i].getOffset(), Replaces[i].getLength());
-    if (ConflictRange.overlapsWith(Current)) {
-      // Extend conflicted range
-      ConflictRange = Range(ConflictRange.getOffset(),
-                            std::max(ConflictRange.getLength(),
-                                     Current.getOffset() + Current.getLength() -
-                                         ConflictRange.getOffset()));
-      ++ConflictLength;
-    } else {
-      if (ConflictLength > 1)
-        Conflicts.push_back(Range(ConflictStart, ConflictLength));
-      ConflictRange = Current;
-      ConflictStart = i;
-      ConflictLength = 1;
-    }
-  }
-
-  if (ConflictLength > 1)
-    Conflicts.push_back(Range(ConflictStart, ConflictLength));
-}
-
-
 RefactoringTool::RefactoringTool(const CompilationDatabase &Compilations,
                                  ArrayRef<std::string> SourcePaths)
   : ClangTool(Compilations, SourcePaths) {}
index f80a3ec9c91fb446afaa8e64f7c47b1900dcb3e8..0f73203d1f66c49ddd6faa53761ae5e47d6433fb 100644 (file)
@@ -9,7 +9,6 @@ target_link_libraries(clang-format
   clangFormat
   clangLex
   clangRewrite
-  clangTooling
   )
 
 install(TARGETS clang-format RUNTIME DESTINATION bin)
index a26ef59822be23b1bfde3a899d699dccd1bec8ff..76e31cc1a0725bc70aebd3a57771536860bcdcff 100644 (file)
@@ -16,9 +16,7 @@ TOOL_NO_EXPORTS = 1
 
 include $(CLANG_LEVEL)/../../Makefile.config
 LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
-USEDLIBS = clangFormat.a clangTooling.a clangFrontend.a clangSerialization.a \
-          clangDriver.a clangParse.a clangSema.a clangAnalysis.a \
-           clangRewriteFrontend.a clangRewrite.a clangEdit.a clangAST.a \
+USEDLIBS = clangFormat.a clangToolingCore.a clangDriver.a clangRewrite.a \
            clangLex.a clangBasic.a 
 
 include $(CLANG_LEVEL)/Makefile
index 9e65a41f7d7771499a7ff3fd5a196ea68ec53868..97f663cde478d6312afd5e77df5eae199c68397d 100644 (file)
@@ -20,7 +20,7 @@ LINK_COMPONENTS := AsmParser BitReader Core MC MCParser Option Support
 USEDLIBS = clangIndex.a clangARCMigrate.a \
           clangRewriteFrontend.a \
           clangFormat.a \
-          clangTooling.a \
+          clangTooling.a clangToolingCore.a \
           clangFrontend.a clangDriver.a \
           clangSerialization.a \
           clangParse.a clangSema.a \
index 700efd5ddb06d8845597265991f388fb0817fc2c..4a7ab794187b7790669a68b890ff20c4f4c7549b 100644 (file)
@@ -11,5 +11,5 @@ add_clang_unittest(FormatTests
 
 target_link_libraries(FormatTests
   clangFormat
-  clangTooling
+  clangToolingCore
   )
index e6dce4d8e814f0e62af7f1e175411eea388ab80c..f95d6d34127bc0e04d9e3e830074d58cdfc9a99c 100644 (file)
@@ -11,8 +11,8 @@ CLANG_LEVEL = ../..
 TESTNAME = Format
 include $(CLANG_LEVEL)/../../Makefile.config
 LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
-USEDLIBS = clangFormat.a clangTooling.a clangFrontend.a clangSerialization.a \
-           clangDriver.a clangParse.a clangRewrite.a \
+USEDLIBS = clangFormat.a clangTooling.a clangToolingCore.a clangFrontend.a \
+          clangSerialization.a clangDriver.a clangParse.a clangRewrite.a \
            clangRewriteFrontend.a clangSema.a clangAnalysis.a clangEdit.a \
            clangAST.a clangASTMatchers.a clangLex.a clangBasic.a
 
index 46af8a11bba1e71a97d776ca75704403795411ee..514e80bd03098746f56c795ab146d229d45adfa1 100644 (file)
@@ -11,7 +11,8 @@ CLANG_LEVEL = ../..
 TESTNAME = Tooling
 include $(CLANG_LEVEL)/../../Makefile.config
 LINK_COMPONENTS := $(TARGETS_TO_BUILD) asmparser bitreader support mc option
-USEDLIBS = clangTooling.a clangFrontend.a clangSerialization.a clangDriver.a \
+USEDLIBS = clangTooling.a clangToolingCore.a clangFrontend.a \
+          clangSerialization.a clangDriver.a \
            clangParse.a clangRewrite.a clangRewriteFrontend.a \
           clangSema.a clangAnalysis.a clangEdit.a \
            clangAST.a clangASTMatchers.a clangLex.a clangBasic.a