blob: 79a102d1ba9a84395399eb9e7282b8dd0416636c [file] [log] [blame]
Eric Liu495b2112016-09-19 17:40:32 +00001//===-- ChangeNamespace.h -- Change namespace ------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef LLVM_CLANG_TOOLS_EXTRA_CHANGE_NAMESPACE_CHANGENAMESPACE_H
11#define LLVM_CLANG_TOOLS_EXTRA_CHANGE_NAMESPACE_CHANGENAMESPACE_H
12
13#include "clang/ASTMatchers/ASTMatchFinder.h"
14#include "clang/Format/Format.h"
15#include "clang/Tooling/Core/Replacement.h"
16#include <string>
17
18namespace clang {
19namespace change_namespace {
20
21// This tool can be used to change the surrounding namespaces of class/function
22// definitions. Classes/functions in the moved namespace will have new
23// namespaces while references to symbols (e.g. types, functions) which are not
24// defined in the changed namespace will be correctly qualified by prepending
25// namespace specifiers before them.
26// For classes, only classes that are declared/defined in the given namespace in
27// speficifed files will be moved: forward declarations will remain in the old
28// namespace.
29// For example, changing "a" to "x":
30// Old code:
31// namespace a {
32// class FWD;
33// class A { FWD *fwd; }
34// } // a
35// New code:
36// namespace a {
37// class FWD;
38// } // a
39// namespace x {
40// class A { a::FWD *fwd; }
41// } // x
42// FIXME: support moving typedef, enums across namespaces.
43class ChangeNamespaceTool : public ast_matchers::MatchFinder::MatchCallback {
44public:
45 // Moves code in the old namespace `OldNs` to the new namespace `NewNs` in
46 // files matching `FilePattern`.
47 ChangeNamespaceTool(
48 llvm::StringRef OldNs, llvm::StringRef NewNs, llvm::StringRef FilePattern,
49 std::map<std::string, tooling::Replacements> *FileToReplacements,
50 llvm::StringRef FallbackStyle = "LLVM");
51
52 void registerMatchers(ast_matchers::MatchFinder *Finder);
53
54 void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
55
56 // Moves the changed code in old namespaces but leaves class forward
57 // declarations behind.
58 void onEndOfTranslationUnit() override;
59
60private:
61 void moveOldNamespace(const ast_matchers::MatchFinder::MatchResult &Result,
62 const NamespaceDecl *NsDecl);
63
64 void moveClassForwardDeclaration(
65 const ast_matchers::MatchFinder::MatchResult &Result,
66 const CXXRecordDecl *FwdDecl);
67
68 void replaceQualifiedSymbolInDeclContext(
69 const ast_matchers::MatchFinder::MatchResult &Result,
70 const Decl *DeclContext, SourceLocation Start, SourceLocation End,
71 llvm::StringRef DeclName);
72
73 void fixTypeLoc(const ast_matchers::MatchFinder::MatchResult &Result,
74 SourceLocation Start, SourceLocation End, TypeLoc Type);
75
Eric Liu68765a82016-09-21 15:06:12 +000076 void fixUsingShadowDecl(const ast_matchers::MatchFinder::MatchResult &Result,
77 const UsingDecl *UsingDeclaration);
78
Eric Liu495b2112016-09-19 17:40:32 +000079 // Information about moving an old namespace.
80 struct MoveNamespace {
81 // The start offset of the namespace block being moved in the original
82 // code.
83 unsigned Offset;
84 // The length of the namespace block in the original code.
85 unsigned Length;
86 // The offset at which the new namespace block will be inserted in the
87 // original code.
88 unsigned InsertionOffset;
89 // The file in which the namespace is declared.
Eric Liucc83c662016-09-19 17:58:59 +000090 FileID FID;
91 SourceManager *SourceMgr;
Eric Liu495b2112016-09-19 17:40:32 +000092 };
93
94 // Information about inserting a class forward declaration.
95 struct InsertForwardDeclaration {
96 // The offset at while the forward declaration will be inserted in the
97 // original code.
98 unsigned InsertionOffset;
99 // The code to be inserted.
100 std::string ForwardDeclText;
101 };
102
103 std::string FallbackStyle;
104 // In match callbacks, this contains replacements for replacing `typeLoc`s in
105 // and deleting forward declarations in the moved namespace blocks.
106 // In `onEndOfTranslationUnit` callback, the previous added replacements are
107 // applied (on the moved namespace blocks), and then changed code in old
108 // namespaces re moved to new namespaces, and previously deleted forward
109 // declarations are inserted back to old namespaces, from which they are
110 // deleted.
111 std::map<std::string, tooling::Replacements> &FileToReplacements;
112 // A fully qualified name of the old namespace without "::" prefix, e.g.
113 // "a::b::c".
114 std::string OldNamespace;
115 // A fully qualified name of the new namespace without "::" prefix, e.g.
116 // "x::y::z".
117 std::string NewNamespace;
118 // The longest suffix in the old namespace that does not overlap the new
119 // namespace.
120 // For example, if `OldNamespace` is "a::b::c" and `NewNamespace` is
121 // "a::x::y", then `DiffOldNamespace` will be "b::c".
122 std::string DiffOldNamespace;
123 // The longest suffix in the new namespace that does not overlap the old
124 // namespace.
125 // For example, if `OldNamespace` is "a::b::c" and `NewNamespace` is
126 // "a::x::y", then `DiffNewNamespace` will be "x::y".
127 std::string DiffNewNamespace;
128 // A regex pattern that matches files to be processed.
129 std::string FilePattern;
130 // Information about moved namespaces grouped by file.
131 // Since we are modifying code in old namespaces (e.g. add namespace
132 // spedifiers) as well as moving them, we store information about namespaces
133 // to be moved and only move them after all modifications are finished (i.e.
134 // in `onEndOfTranslationUnit`).
135 std::map<std::string, std::vector<MoveNamespace>> MoveNamespaces;
136 // Information about forward declaration insertions grouped by files.
137 // A class forward declaration is not moved, so it will be deleted from the
138 // moved code block and inserted back into the old namespace. The insertion
139 // will be done after removing the code from the old namespace and before
140 // inserting it to the new namespace.
141 std::map<std::string, std::vector<InsertForwardDeclaration>> InsertFwdDecls;
142};
143
144} // namespace change_namespace
145} // namespace clang
146
147#endif // LLVM_CLANG_TOOLS_EXTRA_CHANGE_NAMESPACE_CHANGENAMESPACE_H