summaryrefslogtreecommitdiffstats
path: root/clang-change-namespace/tool/ClangChangeNamespace.cpp
diff options
context:
space:
mode:
authorJordan Rupprecht <rupprecht@google.com>2019-05-14 21:58:59 +0000
committerJordan Rupprecht <rupprecht@google.com>2019-05-14 21:58:59 +0000
commit46054fed6aeeabea27b9ba4a3ef81ab5ff9b9645 (patch)
treed12279f80b5729d0324f066002c838baa736fbd2 /clang-change-namespace/tool/ClangChangeNamespace.cpp
parent5026a9a16d10a2edf09be54c7225f49b5789c69e (diff)
parent0eb1ac6d1df856f065717226ef34d00679a211fe (diff)
Creating branches/google/stable and tags/google/stable/2019-05-14 from r360103upstream/stable
git-svn-id: https://llvm.org/svn/llvm-project/clang-tools-extra/branches/google/stable@360714 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'clang-change-namespace/tool/ClangChangeNamespace.cpp')
-rw-r--r--clang-change-namespace/tool/ClangChangeNamespace.cpp177
1 files changed, 177 insertions, 0 deletions
diff --git a/clang-change-namespace/tool/ClangChangeNamespace.cpp b/clang-change-namespace/tool/ClangChangeNamespace.cpp
new file mode 100644
index 00000000..d5f06552
--- /dev/null
+++ b/clang-change-namespace/tool/ClangChangeNamespace.cpp
@@ -0,0 +1,177 @@
+//===-- ClangChangeNamespace.cpp - Standalone change namespace ------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+// This tool can be used to change the surrounding namespaces of class/function
+// definitions.
+//
+// Example: test.cc
+// namespace na {
+// class X {};
+// namespace nb {
+// class Y { X x; };
+// } // namespace nb
+// } // namespace na
+// To move the definition of class Y from namespace "na::nb" to "x::y", run:
+// clang-change-namespace --old_namespace "na::nb" \
+// --new_namespace "x::y" --file_pattern "test.cc" test.cc --
+// Output:
+// namespace na {
+// class X {};
+// } // namespace na
+// namespace x {
+// namespace y {
+// class Y { na::X x; };
+// } // namespace y
+// } // namespace x
+
+#include "ChangeNamespace.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/YAMLTraits.h"
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+
+cl::OptionCategory ChangeNamespaceCategory("Change namespace.");
+
+cl::opt<std::string> OldNamespace("old_namespace", cl::Required,
+ cl::desc("Old namespace."),
+ cl::cat(ChangeNamespaceCategory));
+
+cl::opt<std::string> NewNamespace("new_namespace", cl::Required,
+ cl::desc("New namespace."),
+ cl::cat(ChangeNamespaceCategory));
+
+cl::opt<std::string> FilePattern(
+ "file_pattern", cl::Required,
+ cl::desc("Only rename namespaces in files that match the given pattern."),
+ cl::cat(ChangeNamespaceCategory));
+
+cl::opt<bool> Inplace("i", cl::desc("Inplace edit <file>s, if specified."),
+ cl::cat(ChangeNamespaceCategory));
+
+cl::opt<bool>
+ DumpYAML("dump_result",
+ cl::desc("Dump new file contents in YAML, if specified."),
+ cl::cat(ChangeNamespaceCategory));
+
+cl::opt<std::string> Style("style",
+ cl::desc("The style name used for reformatting."),
+ cl::init("LLVM"), cl::cat(ChangeNamespaceCategory));
+
+cl::opt<std::string> WhiteListFile(
+ "whitelist_file",
+ cl::desc("A file containing regexes of symbol names that are not expected "
+ "to be updated when changing namespaces around them."),
+ cl::init(""), cl::cat(ChangeNamespaceCategory));
+
+llvm::ErrorOr<std::vector<std::string>> GetWhiteListedSymbolPatterns() {
+ std::vector<std::string> Patterns;
+ if (WhiteListFile.empty())
+ return Patterns;
+
+ llvm::SmallVector<StringRef, 8> Lines;
+ llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>> File =
+ llvm::MemoryBuffer::getFile(WhiteListFile);
+ if (!File)
+ return File.getError();
+ llvm::StringRef Content = File.get()->getBuffer();
+ Content.split(Lines, '\n', /*MaxSplit=*/-1, /*KeepEmpty=*/false);
+ for (auto Line : Lines)
+ Patterns.push_back(Line.trim());
+ return Patterns;
+}
+
+} // anonymous namespace
+
+int main(int argc, const char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+ tooling::CommonOptionsParser OptionsParser(argc, argv,
+ ChangeNamespaceCategory);
+ const auto &Files = OptionsParser.getSourcePathList();
+ tooling::RefactoringTool Tool(OptionsParser.getCompilations(), Files);
+ llvm::ErrorOr<std::vector<std::string>> WhiteListPatterns =
+ GetWhiteListedSymbolPatterns();
+ if (!WhiteListPatterns) {
+ llvm::errs() << "Failed to open whitelist file " << WhiteListFile << ". "
+ << WhiteListPatterns.getError().message() << "\n";
+ return 1;
+ }
+ change_namespace::ChangeNamespaceTool NamespaceTool(
+ OldNamespace, NewNamespace, FilePattern, *WhiteListPatterns,
+ &Tool.getReplacements(), Style);
+ ast_matchers::MatchFinder Finder;
+ NamespaceTool.registerMatchers(&Finder);
+ std::unique_ptr<tooling::FrontendActionFactory> Factory =
+ tooling::newFrontendActionFactory(&Finder);
+
+ if (int Result = Tool.run(Factory.get()))
+ return Result;
+ LangOptions DefaultLangOptions;
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+ &DiagnosticPrinter, false);
+ auto &FileMgr = Tool.getFiles();
+ SourceManager Sources(Diagnostics, FileMgr);
+ Rewriter Rewrite(Sources, DefaultLangOptions);
+
+ if (!formatAndApplyAllReplacements(Tool.getReplacements(), Rewrite, Style)) {
+ llvm::errs() << "Failed applying all replacements.\n";
+ return 1;
+ }
+ if (Inplace)
+ return Rewrite.overwriteChangedFiles();
+
+ std::set<llvm::StringRef> ChangedFiles;
+ for (const auto &it : Tool.getReplacements())
+ ChangedFiles.insert(it.first);
+
+ if (DumpYAML) {
+ auto WriteToYAML = [&](llvm::raw_ostream &OS) {
+ OS << "[\n";
+ for (auto I = ChangedFiles.begin(), E = ChangedFiles.end(); I != E; ++I) {
+ OS << " {\n";
+ OS << " \"FilePath\": \"" << *I << "\",\n";
+ const auto *Entry = FileMgr.getFile(*I);
+ auto ID = Sources.getOrCreateFileID(Entry, SrcMgr::C_User);
+ std::string Content;
+ llvm::raw_string_ostream ContentStream(Content);
+ Rewrite.getEditBuffer(ID).write(ContentStream);
+ OS << " \"SourceText\": \""
+ << llvm::yaml::escape(ContentStream.str()) << "\"\n";
+ OS << " }";
+ if (I != std::prev(E))
+ OS << ",\n";
+ }
+ OS << "\n]\n";
+ };
+ WriteToYAML(llvm::outs());
+ return 0;
+ }
+
+ for (const auto &File : ChangedFiles) {
+ const auto *Entry = FileMgr.getFile(File);
+
+ auto ID = Sources.getOrCreateFileID(Entry, SrcMgr::C_User);
+ outs() << "============== " << File << " ==============\n";
+ Rewrite.getEditBuffer(ID).write(llvm::outs());
+ outs() << "\n============================================\n";
+ }
+
+ return 0;
+}