https://github.com/dbartol updated 
https://github.com/llvm/llvm-project/pull/186257

>From 2e1b6387c7ea700e729bc6a41120aaa81190c324 Mon Sep 17 00:00:00 2001
From: Dave Bartolomeo <[email protected]>
Date: Fri, 13 Mar 2026 12:15:33 -0400
Subject: [PATCH] [clang] Allow using part of `libClangToolingCore` without
 depending on Clang

I'm about to make a PR that starts using `libClangToolingCore` in tblgen (to 
emit fixits as YAML), but since the Clang build depends on tblgen, this would 
create a circular dependency. To break this cycle, I have factored the parts of 
`libClangToolingCore` that don't depend on Clang into a separate library, 
`libClangToolingCoreNoClang`. To do this, I removed the Clang header includes 
from the "clang/tooling/Core" headers, made a few fixups to let those headers 
compile without the Clang types being complete, and then split the 
implementations in the ".cpp" files into separate files for the Clang 
dependencies. I then updated the CMake configuration to build the `NoClang` 
library first, then have the existing library depend on that.

A few random fixups were needed elsewhere in places where code was depending on 
a stray `using namespace llvm;` somewhere in a header that is no longer 
included by the tooling headers.

I also created a separate header to define a new enum, `DiagnosticLevel`, that 
is independent of the rest of Clang. Thus, it can be used in the tooling 
library or within Clang. I've updated `DiagnosticIDs::Level` to depend on this 
new enum. In the future we should just use this enum directly for all of the 
various enums that currently have separated definitions with the same values.
---
 .../IncludeFixerContext.cpp                   |   2 +-
 .../clang-include-fixer/IncludeFixerContext.h |   4 +-
 .../clang-tidy/ClangTidyDiagnosticConsumer.h  |   1 +
 clang/include/clang/Basic/DiagnosticIDs.h     |  10 +-
 clang/include/clang/Basic/DiagnosticLevel.h   |  36 ++++
 clang/include/clang/Tooling/Core/Diagnostic.h |  21 +-
 .../include/clang/Tooling/Core/Replacement.h  |  54 ++++--
 .../include/clang/Tooling/ReplacementsYaml.h  |   7 +-
 clang/lib/Tooling/Core/CMakeLists.txt         |  20 +-
 clang/lib/Tooling/Core/Diagnostic.cpp         |  29 +--
 clang/lib/Tooling/Core/DiagnosticClang.cpp    |  48 +++++
 clang/lib/Tooling/Core/Replacement.cpp        | 143 +-------------
 clang/lib/Tooling/Core/ReplacementClang.cpp   | 182 ++++++++++++++++++
 13 files changed, 357 insertions(+), 200 deletions(-)
 create mode 100644 clang/include/clang/Basic/DiagnosticLevel.h
 create mode 100644 clang/lib/Tooling/Core/DiagnosticClang.cpp
 create mode 100644 clang/lib/Tooling/Core/ReplacementClang.cpp

diff --git a/clang-tools-extra/clang-include-fixer/IncludeFixerContext.cpp 
b/clang-tools-extra/clang-include-fixer/IncludeFixerContext.cpp
index 4eac0617ed4a9..9f6fc33efa340 100644
--- a/clang-tools-extra/clang-include-fixer/IncludeFixerContext.cpp
+++ b/clang-tools-extra/clang-include-fixer/IncludeFixerContext.cpp
@@ -75,7 +75,7 @@ std::string createQualifiedNameForReplacement(
 } // anonymous namespace
 
 IncludeFixerContext::IncludeFixerContext(
-    StringRef FilePath, std::vector<QuerySymbolInfo> QuerySymbols,
+    llvm::StringRef FilePath, std::vector<QuerySymbolInfo> QuerySymbols,
     std::vector<find_all_symbols::SymbolInfo> Symbols)
     : FilePath(FilePath), QuerySymbolInfos(std::move(QuerySymbols)),
       MatchedSymbols(std::move(Symbols)) {
diff --git a/clang-tools-extra/clang-include-fixer/IncludeFixerContext.h 
b/clang-tools-extra/clang-include-fixer/IncludeFixerContext.h
index e819d30b29156..a381631520f74 100644
--- a/clang-tools-extra/clang-include-fixer/IncludeFixerContext.h
+++ b/clang-tools-extra/clang-include-fixer/IncludeFixerContext.h
@@ -46,7 +46,7 @@ class IncludeFixerContext {
   };
 
   IncludeFixerContext() = default;
-  IncludeFixerContext(StringRef FilePath,
+  IncludeFixerContext(llvm::StringRef FilePath,
                       std::vector<QuerySymbolInfo> QuerySymbols,
                       std::vector<find_all_symbols::SymbolInfo> Symbols);
 
@@ -61,7 +61,7 @@ class IncludeFixerContext {
   }
 
   /// Get the file path to the file being processed.
-  StringRef getFilePath() const { return FilePath; }
+  llvm::StringRef getFilePath() const { return FilePath; }
 
   /// Get header information.
   const std::vector<HeaderInfo> &getHeaderInfos() const { return HeaderInfos; }
diff --git a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h 
b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
index 8de5778dfefb0..b97a3a019e072 100644
--- a/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
+++ b/clang-tools-extra/clang-tidy/ClangTidyDiagnosticConsumer.h
@@ -14,6 +14,7 @@
 #include "FileExtensionsSet.h"
 #include "NoLintDirectiveHandler.h"
 #include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LangOptions.h"
 #include "clang/Tooling/Core/Diagnostic.h"
 #include "llvm/ADT/DenseMap.h"
 #include "llvm/ADT/StringSet.h"
diff --git a/clang/include/clang/Basic/DiagnosticIDs.h 
b/clang/include/clang/Basic/DiagnosticIDs.h
index 09e2d12dd040e..09c357cb83d66 100644
--- a/clang/include/clang/Basic/DiagnosticIDs.h
+++ b/clang/include/clang/Basic/DiagnosticIDs.h
@@ -15,6 +15,7 @@
 #define LLVM_CLANG_BASIC_DIAGNOSTICIDS_H
 
 #include "clang/Basic/DiagnosticCategories.h"
+#include "clang/Basic/DiagnosticLevel.h"
 #include "clang/Basic/LLVM.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/StringRef.h"
@@ -182,7 +183,14 @@ class DiagnosticMapping {
 class DiagnosticIDs : public RefCountedBase<DiagnosticIDs> {
 public:
   /// The level of the diagnostic, after it has been through mapping.
-  enum Level : uint8_t { Ignored, Note, Remark, Warning, Error, Fatal };
+  enum Level : uint8_t {
+    Ignored = static_cast<uint8_t>(DiagnosticLevel::Ignored),
+    Note = static_cast<uint8_t>(DiagnosticLevel::Note),
+    Remark = static_cast<uint8_t>(DiagnosticLevel::Remark),
+    Warning = static_cast<uint8_t>(DiagnosticLevel::Warning),
+    Error = static_cast<uint8_t>(DiagnosticLevel::Error),
+    Fatal = static_cast<uint8_t>(DiagnosticLevel::Fatal)
+  };
 
   // Diagnostic classes.
   enum Class {
diff --git a/clang/include/clang/Basic/DiagnosticLevel.h 
b/clang/include/clang/Basic/DiagnosticLevel.h
new file mode 100644
index 0000000000000..e7fbd8f6b945e
--- /dev/null
+++ b/clang/include/clang/Basic/DiagnosticLevel.h
@@ -0,0 +1,36 @@
+//===--- DiagnosticLevel.h - Diagnostic Severity Level-----------*- C++ 
-*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// Defines the DiagnosticLevel enum.
+///
+/// This file has no other dependencies on Clang headers, to ensure that it can
+/// be included from tblgen.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_BASIC_DIAGNOSTICLEVEL_H
+#define LLVM_CLANG_BASIC_DIAGNOSTICLEVEL_H
+
+#include <cstdint>
+
+namespace clang {
+
+/// The level of the diagnostic, after it has been through mapping.
+enum class DiagnosticLevel : uint8_t {
+  Ignored,
+  Note,
+  Remark,
+  Warning,
+  Error,
+  Fatal
+};
+
+} // namespace clang
+
+#endif
diff --git a/clang/include/clang/Tooling/Core/Diagnostic.h 
b/clang/include/clang/Tooling/Core/Diagnostic.h
index 4553380bcf00e..00c5e81ca2bd8 100644
--- a/clang/include/clang/Tooling/Core/Diagnostic.h
+++ b/clang/include/clang/Tooling/Core/Diagnostic.h
@@ -16,8 +16,13 @@
 #ifndef LLVM_CLANG_TOOLING_CORE_DIAGNOSTIC_H
 #define LLVM_CLANG_TOOLING_CORE_DIAGNOSTIC_H
 
+// Please do not #include Clang headers in this file. This file can be used
+// from clang-tblgen, and consuming Clang headers here will create a circular
+// dependency. It _is_ acceptable to forward-declare types from the "clang"
+// namespace, as long as the consuming code in clang-tblgen does not need to 
use
+// any of the functions that use the forward-declared types.
 #include "Replacement.h"
-#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticLevel.h" // OK because it only defines the 
enum.
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
@@ -67,19 +72,19 @@ struct DiagnosticMessage {
 /// fixes to be applied.
 struct Diagnostic {
   enum Level {
-    Remark = DiagnosticsEngine::Remark,
-    Warning = DiagnosticsEngine::Warning,
-    Error = DiagnosticsEngine::Error
+    Remark = static_cast<uint8_t>(DiagnosticLevel::Remark),
+    Warning = static_cast<uint8_t>(DiagnosticLevel::Warning),
+    Error = static_cast<uint8_t>(DiagnosticLevel::Error)
   };
 
   Diagnostic() = default;
 
   Diagnostic(llvm::StringRef DiagnosticName, Level DiagLevel,
-             StringRef BuildDirectory);
+             llvm::StringRef BuildDirectory);
 
   Diagnostic(llvm::StringRef DiagnosticName, const DiagnosticMessage &Message,
-             const SmallVector<DiagnosticMessage, 1> &Notes, Level DiagLevel,
-             llvm::StringRef BuildDirectory);
+             const llvm::SmallVector<DiagnosticMessage, 1> &Notes,
+             Level DiagLevel, llvm::StringRef BuildDirectory);
 
   /// Name identifying the Diagnostic.
   std::string DiagnosticName;
@@ -88,7 +93,7 @@ struct Diagnostic {
   DiagnosticMessage Message;
 
   /// Potential notes about the diagnostic.
-  SmallVector<DiagnosticMessage, 1> Notes;
+  llvm::SmallVector<DiagnosticMessage, 1> Notes;
 
   /// Diagnostic level. Can indicate either an error or a warning.
   Level DiagLevel;
diff --git a/clang/include/clang/Tooling/Core/Replacement.h 
b/clang/include/clang/Tooling/Core/Replacement.h
index f9452111e147f..b2cafad8d0042 100644
--- a/clang/include/clang/Tooling/Core/Replacement.h
+++ b/clang/include/clang/Tooling/Core/Replacement.h
@@ -18,8 +18,11 @@
 #ifndef LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H
 #define LLVM_CLANG_TOOLING_CORE_REPLACEMENT_H
 
-#include "clang/Basic/LangOptions.h"
-#include "clang/Basic/SourceLocation.h"
+// Please do not #include Clang headers in this file. This file can be used
+// from clang-tblgen, and consuming Clang headers here will create a circular
+// dependency. It _is_ acceptable to forward-declare types from the "clang"
+// namespace, as long as the consuming code in clang-tblgen does not need to 
use
+// any of the functions that use the forward-declared types.
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Error.h"
@@ -34,9 +37,13 @@
 
 namespace clang {
 
+class CharSourceRange;
 class FileManager;
 class Rewriter;
+class SourceLocation;
 class SourceManager;
+class SourceRange;
+class LangOptions;
 
 namespace tooling {
 
@@ -91,24 +98,24 @@ class Replacement {
   /// \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);
+  Replacement(llvm::StringRef FilePath, unsigned Offset, unsigned Length,
+              llvm::StringRef ReplacementText);
 
   /// Creates a Replacement of the range [Start, Start+Length) with
   /// ReplacementText.
   Replacement(const SourceManager &Sources, SourceLocation Start,
-              unsigned Length, StringRef ReplacementText);
+              unsigned Length, llvm::StringRef ReplacementText);
 
   /// Creates a Replacement of the given range with ReplacementText.
   Replacement(const SourceManager &Sources, const CharSourceRange &Range,
-              StringRef ReplacementText,
-              const LangOptions &LangOpts = LangOptions());
+              llvm::StringRef ReplacementText,
+              const LangOptions &LangOpts = DefaultLangOptions);
 
   /// Creates a Replacement of the node with ReplacementText.
   template <typename Node>
   Replacement(const SourceManager &Sources, const Node &NodeToReplace,
-              StringRef ReplacementText,
-              const LangOptions &LangOpts = LangOptions());
+              llvm::StringRef ReplacementText,
+              const LangOptions &LangOpts = DefaultLangOptions);
 
   /// Returns whether this replacement can be applied to a file.
   ///
@@ -117,10 +124,10 @@ class Replacement {
 
   /// Accessors.
   /// @{
-  StringRef getFilePath() const { return FilePath; }
+  llvm::StringRef getFilePath() const { return FilePath; }
   unsigned getOffset() const { return ReplacementRange.getOffset(); }
   unsigned getLength() const { return ReplacementRange.getLength(); }
-  StringRef getReplacementText() const { return ReplacementText; }
+  llvm::StringRef getReplacementText() const { return ReplacementText; }
   /// @}
 
   /// Applies the replacement on the Rewriter.
@@ -131,11 +138,20 @@ class Replacement {
 
 private:
   void setFromSourceLocation(const SourceManager &Sources, SourceLocation 
Start,
-                             unsigned Length, StringRef ReplacementText);
+                             unsigned Length, llvm::StringRef ReplacementText);
   void setFromSourceRange(const SourceManager &Sources,
                           const CharSourceRange &Range,
-                          StringRef ReplacementText,
+                          llvm::StringRef ReplacementText,
                           const LangOptions &LangOpts);
+  void setFromSourceRange(const SourceManager &Sources,
+                          const SourceRange &Range,
+                          llvm::StringRef ReplacementText,
+                          const LangOptions &LangOpts);
+
+  // Used as a default argument to avoid requiring LangOptions to be complete 
in
+  // this header.
+  static const LangOptions DefaultLangOptions;
+  static const char *const InvalidLocation;
 
   std::string FilePath;
   Range ReplacementRange;
@@ -167,7 +183,7 @@ class ReplacementError : public 
llvm::ErrorInfo<ReplacementError> {
 
   std::string message() const override;
 
-  void log(raw_ostream &OS) const override { OS << message(); }
+  void log(llvm::raw_ostream &OS) const override { OS << message(); }
 
   replacement_error get() const { return Err; }
 
@@ -328,7 +344,7 @@ bool applyAllReplacements(const Replacements &Replaces, 
Rewriter &Rewrite);
 /// replacements applied; otherwise, an llvm::Error carrying llvm::StringError
 /// is returned (the Error message can be converted to string using
 /// `llvm::toString()` and 'std::error_code` in the `Error` should be ignored).
-llvm::Expected<std::string> applyAllReplacements(StringRef Code,
+llvm::Expected<std::string> applyAllReplacements(llvm::StringRef Code,
                                                  const Replacements &Replaces);
 
 /// Collection of Replacements generated from a single translation unit.
@@ -360,11 +376,11 @@ std::map<std::string, Replacements> 
groupReplacementsByFile(
 
 template <typename Node>
 Replacement::Replacement(const SourceManager &Sources,
-                         const Node &NodeToReplace, StringRef ReplacementText,
+                         const Node &NodeToReplace,
+                         llvm::StringRef ReplacementText,
                          const LangOptions &LangOpts) {
-  const CharSourceRange Range =
-      CharSourceRange::getTokenRange(NodeToReplace->getSourceRange());
-  setFromSourceRange(Sources, Range, ReplacementText, LangOpts);
+  setFromSourceRange(Sources, NodeToReplace->getSourceRange(), ReplacementText,
+                     LangOpts);
 }
 
 } // namespace tooling
diff --git a/clang/include/clang/Tooling/ReplacementsYaml.h 
b/clang/include/clang/Tooling/ReplacementsYaml.h
index 838f87fd19785..29825bf0eb440 100644
--- a/clang/include/clang/Tooling/ReplacementsYaml.h
+++ b/clang/include/clang/Tooling/ReplacementsYaml.h
@@ -15,7 +15,12 @@
 #ifndef LLVM_CLANG_TOOLING_REPLACEMENTSYAML_H
 #define LLVM_CLANG_TOOLING_REPLACEMENTSYAML_H
 
-#include "clang/Tooling/Refactoring.h"
+// Please do not #include Clang headers in this file. This file can be used
+// from clang-tblgen, and consuming Clang headers here will create a circular
+// dependency. It _is_ acceptable to forward-declare types from the "clang"
+// namespace, as long as the consuming code in clang-tblgen does not need to 
use
+// any of the functions that use the forward-declared types.
+#include "clang/Tooling/Core/Replacement.h"
 #include "llvm/Support/YAMLTraits.h"
 #include <string>
 
diff --git a/clang/lib/Tooling/Core/CMakeLists.txt 
b/clang/lib/Tooling/Core/CMakeLists.txt
index e523ca45301e2..ae5dbd55fc9c6 100644
--- a/clang/lib/Tooling/Core/CMakeLists.txt
+++ b/clang/lib/Tooling/Core/CMakeLists.txt
@@ -1,11 +1,29 @@
 set(LLVM_LINK_COMPONENTS support)
 
-add_clang_library(clangToolingCore
+set(LLVM_COMMON_DEPENDS_OLD ${LLVM_COMMON_DEPENDS})
+
+# Drop clang-tablegen-targets from LLVM_COMMON_DEPENDS.
+# so that we could use clangToolingCoreNoClang within clang-tblgen.
+list(REMOVE_ITEM LLVM_COMMON_DEPENDS clang-tablegen-targets)
+
+add_clang_library(clangToolingCoreNoClang
   Diagnostic.cpp
   Replacement.cpp
 
+  PARTIAL_SOURCES_INTENDED
+  )
+
+set(LLVM_COMMON_DEPENDS ${LLVM_COMMON_DEPENDS_OLD})
+
+add_clang_library(clangToolingCore
+  DiagnosticClang.cpp
+  ReplacementClang.cpp
+
+  PARTIAL_SOURCES_INTENDED
+
   LINK_LIBS
   clangBasic
   clangLex
   clangRewrite
+  clangToolingCoreNoClang
   )
diff --git a/clang/lib/Tooling/Core/Diagnostic.cpp 
b/clang/lib/Tooling/Core/Diagnostic.cpp
index fb3358024692d..8d55accfb881f 100644
--- a/clang/lib/Tooling/Core/Diagnostic.cpp
+++ b/clang/lib/Tooling/Core/Diagnostic.cpp
@@ -11,40 +11,17 @@
 
//===----------------------------------------------------------------------===//
 
 #include "clang/Tooling/Core/Diagnostic.h"
-#include "clang/Basic/SourceLocation.h"
-#include "clang/Basic/SourceManager.h"
 #include "llvm/ADT/STLExtras.h"
 
+using llvm::SmallVector;
+using llvm::StringRef;
+
 namespace clang {
 namespace tooling {
 
 DiagnosticMessage::DiagnosticMessage(llvm::StringRef Message)
     : Message(Message), FileOffset(0) {}
 
-DiagnosticMessage::DiagnosticMessage(llvm::StringRef Message,
-                                     const SourceManager &Sources,
-                                     SourceLocation Loc)
-    : Message(Message), FileOffset(0) {
-  assert(Loc.isValid() && Loc.isFileID());
-  FilePath = std::string(Sources.getFilename(Loc));
-
-  // Don't store offset in the scratch space. It doesn't tell anything to the
-  // user. Moreover, it depends on the history of macro expansions and thus
-  // prevents deduplication of warnings in headers.
-  if (!FilePath.empty())
-    FileOffset = Sources.getFileOffset(Loc);
-}
-
-FileByteRange::FileByteRange(
-    const SourceManager &Sources, CharSourceRange Range)
-    : FileOffset(0), Length(0) {
-  FilePath = std::string(Sources.getFilename(Range.getBegin()));
-  if (!FilePath.empty()) {
-    FileOffset = Sources.getFileOffset(Range.getBegin());
-    Length = Sources.getFileOffset(Range.getEnd()) - FileOffset;
-  }
-}
-
 Diagnostic::Diagnostic(llvm::StringRef DiagnosticName,
                        Diagnostic::Level DiagLevel, StringRef BuildDirectory)
     : DiagnosticName(DiagnosticName), DiagLevel(DiagLevel),
diff --git a/clang/lib/Tooling/Core/DiagnosticClang.cpp 
b/clang/lib/Tooling/Core/DiagnosticClang.cpp
new file mode 100644
index 0000000000000..a659338f7c6a1
--- /dev/null
+++ b/clang/lib/Tooling/Core/DiagnosticClang.cpp
@@ -0,0 +1,48 @@
+//===--- Diagnostic.cpp - Framework for clang diagnostics tools ----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  Implements classes to support/store diagnostics refactoring. This file
+//  contains all of the code that depends on Clang, so that Diagnostic.cpp can
+//  be used from tools used to build Clang, like tblgen.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Tooling/Core/Diagnostic.h"
+#include "llvm/ADT/STLExtras.h"
+
+namespace clang {
+namespace tooling {
+
+DiagnosticMessage::DiagnosticMessage(llvm::StringRef Message,
+                                     const SourceManager &Sources,
+                                     SourceLocation Loc)
+    : Message(Message), FileOffset(0) {
+  assert(Loc.isValid() && Loc.isFileID());
+  FilePath = std::string(Sources.getFilename(Loc));
+
+  // Don't store offset in the scratch space. It doesn't tell anything to the
+  // user. Moreover, it depends on the history of macro expansions and thus
+  // prevents deduplication of warnings in headers.
+  if (!FilePath.empty())
+    FileOffset = Sources.getFileOffset(Loc);
+}
+
+FileByteRange::FileByteRange(const SourceManager &Sources,
+                             CharSourceRange Range)
+    : FileOffset(0), Length(0) {
+  FilePath = std::string(Sources.getFilename(Range.getBegin()));
+  if (!FilePath.empty()) {
+    FileOffset = Sources.getFileOffset(Range.getBegin());
+    Length = Sources.getFileOffset(Range.getEnd()) - FileOffset;
+  }
+}
+
+} // end namespace tooling
+} // end namespace clang
diff --git a/clang/lib/Tooling/Core/Replacement.cpp 
b/clang/lib/Tooling/Core/Replacement.cpp
index 10bdc223e33f2..0891ce8847e1f 100644
--- a/clang/lib/Tooling/Core/Replacement.cpp
+++ b/clang/lib/Tooling/Core/Replacement.cpp
@@ -11,15 +11,6 @@
 
//===----------------------------------------------------------------------===//
 
 #include "clang/Tooling/Core/Replacement.h"
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/DiagnosticIDs.h"
-#include "clang/Basic/DiagnosticOptions.h"
-#include "clang/Basic/FileManager.h"
-#include "clang/Basic/FileSystemOptions.h"
-#include "clang/Basic/SourceLocation.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Rewrite/Core/Rewriter.h"
 #include "llvm/ADT/IntrusiveRefCntPtr.h"
 #include "llvm/ADT/RewriteBuffer.h"
 #include "llvm/ADT/SmallPtrSet.h"
@@ -39,9 +30,9 @@
 
 using namespace clang;
 using namespace tooling;
+using llvm::StringRef;
 
-static const char * const InvalidLocation = "";
-
+const char *const Replacement::InvalidLocation = "";
 Replacement::Replacement() : FilePath(InvalidLocation) {}
 
 Replacement::Replacement(StringRef FilePath, unsigned Offset, unsigned Length,
@@ -49,41 +40,10 @@ Replacement::Replacement(StringRef FilePath, unsigned 
Offset, unsigned Length,
     : FilePath(std::string(FilePath)), ReplacementRange(Offset, Length),
       ReplacementText(std::string(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,
-                         const LangOptions &LangOpts) {
-  setFromSourceRange(Sources, Range, ReplacementText, LangOpts);
-}
-
 bool Replacement::isApplicable() const {
   return FilePath != InvalidLocation;
 }
 
-bool Replacement::apply(Rewriter &Rewrite) const {
-  SourceManager &SM = Rewrite.getSourceMgr();
-  auto Entry = SM.getFileManager().getOptionalFileRef(FilePath);
-  if (!Entry)
-    return false;
-
-  FileID ID = SM.getOrCreateFileID(*Entry, SrcMgr::C_User);
-  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);
@@ -117,42 +77,6 @@ bool operator==(const Replacement &LHS, const Replacement 
&RHS) {
 } // namespace tooling
 } // namespace clang
 
-void Replacement::setFromSourceLocation(const SourceManager &Sources,
-                                        SourceLocation Start, unsigned Length,
-                                        StringRef ReplacementText) {
-  const FileIDAndOffset DecomposedLocation = Sources.getDecomposedLoc(Start);
-  OptionalFileEntryRef Entry =
-      Sources.getFileEntryRefForID(DecomposedLocation.first);
-  this->FilePath = std::string(Entry ? Entry->getName() : InvalidLocation);
-  this->ReplacementRange = Range(DecomposedLocation.second, Length);
-  this->ReplacementText = std::string(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,
-                        const LangOptions &LangOpts) {
-  SourceLocation SpellingBegin = Sources.getSpellingLoc(Range.getBegin());
-  SourceLocation SpellingEnd = Sources.getSpellingLoc(Range.getEnd());
-  FileIDAndOffset Start = Sources.getDecomposedLoc(SpellingBegin);
-  FileIDAndOffset End = Sources.getDecomposedLoc(SpellingEnd);
-  if (Start.first != End.first) return -1;
-  if (Range.isTokenRange())
-    End.second += Lexer::MeasureTokenLength(SpellingEnd, Sources, LangOpts);
-  return End.second - Start.second;
-}
-
-void Replacement::setFromSourceRange(const SourceManager &Sources,
-                                     const CharSourceRange &Range,
-                                     StringRef ReplacementText,
-                                     const LangOptions &LangOpts) {
-  setFromSourceLocation(Sources, Sources.getSpellingLoc(Range.getBegin()),
-                        getRangeSize(Sources, Range, LangOpts),
-                        ReplacementText);
-}
-
 Replacement
 Replacements::getReplacementInChangedCode(const Replacement &R) const {
   unsigned NewStart = getShiftedCodePosition(R.getOffset());
@@ -560,66 +484,3 @@ unsigned Replacements::getShiftedCodePosition(unsigned 
Position) const {
   }
   return Position + Offset;
 }
-
-namespace clang {
-namespace tooling {
-
-bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite) {
-  bool Result = true;
-  for (auto I = Replaces.rbegin(), E = Replaces.rend(); I != E; ++I) {
-    if (I->isApplicable()) {
-      Result = I->apply(Rewrite) && Result;
-    } else {
-      Result = false;
-    }
-  }
-  return Result;
-}
-
-llvm::Expected<std::string> applyAllReplacements(StringRef Code,
-                                                const Replacements &Replaces) {
-  if (Replaces.empty())
-    return Code.str();
-
-  auto InMemoryFileSystem =
-      llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
-  FileManager Files(FileSystemOptions(), InMemoryFileSystem);
-  DiagnosticOptions DiagOpts;
-  DiagnosticsEngine Diagnostics(DiagnosticIDs::create(), DiagOpts);
-  SourceManager SourceMgr(Diagnostics, Files);
-  Rewriter Rewrite(SourceMgr, LangOptions());
-  InMemoryFileSystem->addFile(
-      "<stdin>", 0, llvm::MemoryBuffer::getMemBuffer(Code, "<stdin>"));
-  FileID ID = SourceMgr.createFileID(*Files.getOptionalFileRef("<stdin>"),
-                                     SourceLocation(),
-                                     clang::SrcMgr::C_User);
-  for (auto I = Replaces.rbegin(), E = Replaces.rend(); I != E; ++I) {
-    Replacement Replace("<stdin>", I->getOffset(), I->getLength(),
-                        I->getReplacementText());
-    if (!Replace.apply(Rewrite))
-      return llvm::make_error<ReplacementError>(
-          replacement_error::fail_to_apply, Replace);
-  }
-  std::string Result;
-  llvm::raw_string_ostream OS(Result);
-  Rewrite.getEditBuffer(ID).write(OS);
-  return Result;
-}
-
-std::map<std::string, Replacements> groupReplacementsByFile(
-    FileManager &FileMgr,
-    const std::map<std::string, Replacements> &FileToReplaces) {
-  std::map<std::string, Replacements> Result;
-  llvm::SmallPtrSet<const FileEntry *, 16> ProcessedFileEntries;
-  for (const auto &Entry : FileToReplaces) {
-    auto FE = FileMgr.getOptionalFileRef(Entry.first);
-    if (!FE)
-      llvm::errs() << "File path " << Entry.first << " is invalid.\n";
-    else if (ProcessedFileEntries.insert(*FE).second)
-      Result[Entry.first] = std::move(Entry.second);
-  }
-  return Result;
-}
-
-} // namespace tooling
-} // namespace clang
diff --git a/clang/lib/Tooling/Core/ReplacementClang.cpp 
b/clang/lib/Tooling/Core/ReplacementClang.cpp
new file mode 100644
index 0000000000000..bf02d23fe74c7
--- /dev/null
+++ b/clang/lib/Tooling/Core/ReplacementClang.cpp
@@ -0,0 +1,182 @@
+//===- ReplacementNoClang.cpp - Framework for clang refactoring tools 
-----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM 
Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+//  Implements classes to support/store refactorings. This file contains all
+//  of the code that depends on Clang, so that Replacement.cpp can be used from
+//  tools used to build Clang, like tblgen.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/DiagnosticIDs.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/FileSystemOptions.h"
+#include "clang/Basic/SourceLocation.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/ADT/IntrusiveRefCntPtr.h"
+#include "llvm/ADT/RewriteBuffer.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/VirtualFileSystem.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <limits>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace clang;
+using namespace tooling;
+
+const LangOptions Replacement::DefaultLangOptions;
+
+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,
+                         const LangOptions &LangOpts) {
+  setFromSourceRange(Sources, Range, ReplacementText, LangOpts);
+}
+
+bool Replacement::apply(Rewriter &Rewrite) const {
+  SourceManager &SM = Rewrite.getSourceMgr();
+  auto Entry = SM.getFileManager().getOptionalFileRef(FilePath);
+  if (!Entry)
+    return false;
+
+  FileID ID = SM.getOrCreateFileID(*Entry, SrcMgr::C_User);
+  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;
+}
+
+void Replacement::setFromSourceLocation(const SourceManager &Sources,
+                                        SourceLocation Start, unsigned Length,
+                                        StringRef ReplacementText) {
+  const FileIDAndOffset DecomposedLocation = Sources.getDecomposedLoc(Start);
+  OptionalFileEntryRef Entry =
+      Sources.getFileEntryRefForID(DecomposedLocation.first);
+  this->FilePath = std::string(Entry ? Entry->getName() : InvalidLocation);
+  this->ReplacementRange = Range(DecomposedLocation.second, Length);
+  this->ReplacementText = std::string(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,
+                        const LangOptions &LangOpts) {
+  SourceLocation SpellingBegin = Sources.getSpellingLoc(Range.getBegin());
+  SourceLocation SpellingEnd = Sources.getSpellingLoc(Range.getEnd());
+  FileIDAndOffset Start = Sources.getDecomposedLoc(SpellingBegin);
+  FileIDAndOffset End = Sources.getDecomposedLoc(SpellingEnd);
+  if (Start.first != End.first)
+    return -1;
+  if (Range.isTokenRange())
+    End.second += Lexer::MeasureTokenLength(SpellingEnd, Sources, LangOpts);
+  return End.second - Start.second;
+}
+
+void Replacement::setFromSourceRange(const SourceManager &Sources,
+                                     const CharSourceRange &Range,
+                                     StringRef ReplacementText,
+                                     const LangOptions &LangOpts) {
+  setFromSourceLocation(Sources, Sources.getSpellingLoc(Range.getBegin()),
+                        getRangeSize(Sources, Range, LangOpts),
+                        ReplacementText);
+}
+
+void Replacement::setFromSourceRange(const SourceManager &Sources,
+                                     const SourceRange &Range,
+                                     StringRef ReplacementText,
+                                     const LangOptions &LangOpts) {
+  setFromSourceRange(Sources, CharSourceRange::getTokenRange(Range),
+                     ReplacementText, LangOpts);
+}
+
+namespace clang {
+namespace tooling {
+
+bool applyAllReplacements(const Replacements &Replaces, Rewriter &Rewrite) {
+  bool Result = true;
+  for (auto I = Replaces.rbegin(), E = Replaces.rend(); I != E; ++I) {
+    if (I->isApplicable()) {
+      Result = I->apply(Rewrite) && Result;
+    } else {
+      Result = false;
+    }
+  }
+  return Result;
+}
+
+llvm::Expected<std::string> applyAllReplacements(StringRef Code,
+                                                 const Replacements &Replaces) 
{
+  if (Replaces.empty())
+    return Code.str();
+
+  auto InMemoryFileSystem =
+      llvm::makeIntrusiveRefCnt<llvm::vfs::InMemoryFileSystem>();
+  FileManager Files(FileSystemOptions(), InMemoryFileSystem);
+  DiagnosticOptions DiagOpts;
+  DiagnosticsEngine Diagnostics(DiagnosticIDs::create(), DiagOpts);
+  SourceManager SourceMgr(Diagnostics, Files);
+  Rewriter Rewrite(SourceMgr, LangOptions());
+  InMemoryFileSystem->addFile(
+      "<stdin>", 0, llvm::MemoryBuffer::getMemBuffer(Code, "<stdin>"));
+  FileID ID = SourceMgr.createFileID(*Files.getOptionalFileRef("<stdin>"),
+                                     SourceLocation(), clang::SrcMgr::C_User);
+  for (auto I = Replaces.rbegin(), E = Replaces.rend(); I != E; ++I) {
+    Replacement Replace("<stdin>", I->getOffset(), I->getLength(),
+                        I->getReplacementText());
+    if (!Replace.apply(Rewrite))
+      return llvm::make_error<ReplacementError>(
+          replacement_error::fail_to_apply, Replace);
+  }
+  std::string Result;
+  llvm::raw_string_ostream OS(Result);
+  Rewrite.getEditBuffer(ID).write(OS);
+  return Result;
+}
+
+std::map<std::string, Replacements> groupReplacementsByFile(
+    FileManager &FileMgr,
+    const std::map<std::string, Replacements> &FileToReplaces) {
+  std::map<std::string, Replacements> Result;
+  llvm::SmallPtrSet<const FileEntry *, 16> ProcessedFileEntries;
+  for (const auto &Entry : FileToReplaces) {
+    auto FE = FileMgr.getOptionalFileRef(Entry.first);
+    if (!FE)
+      llvm::errs() << "File path " << Entry.first << " is invalid.\n";
+    else if (ProcessedFileEntries.insert(*FE).second)
+      Result[Entry.first] = std::move(Entry.second);
+  }
+  return Result;
+}
+
+} // namespace tooling
+} // namespace clang

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to