blob: cfe3cbc729dcbb1cce8d43e35f49afae9b78f3c1 [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"
Eric Liuc265b022016-12-01 17:25:55 +000016#include "llvm/Support/Regex.h"
Eric Liu495b2112016-09-19 17:40:32 +000017#include <string>
18
19namespace clang {
20namespace change_namespace {
21
22// This tool can be used to change the surrounding namespaces of class/function
23// definitions. Classes/functions in the moved namespace will have new
24// namespaces while references to symbols (e.g. types, functions) which are not
25// defined in the changed namespace will be correctly qualified by prepending
26// namespace specifiers before them.
Eric Liu97f87ad2016-12-07 20:08:02 +000027// This will try to add shortest namespace specifiers possible. When a symbol
28// reference needs to be fully-qualified, this adds a "::" prefix to the
29// namespace specifiers unless the new namespace is the global namespace.
Eric Liu495b2112016-09-19 17:40:32 +000030// For classes, only classes that are declared/defined in the given namespace in
31// speficifed files will be moved: forward declarations will remain in the old
32// namespace.
33// For example, changing "a" to "x":
34// Old code:
35// namespace a {
36// class FWD;
37// class A { FWD *fwd; }
38// } // a
39// New code:
40// namespace a {
41// class FWD;
42// } // a
43// namespace x {
Eric Liu97f87ad2016-12-07 20:08:02 +000044// class A { ::a::FWD *fwd; }
Eric Liu495b2112016-09-19 17:40:32 +000045// } // x
46// FIXME: support moving typedef, enums across namespaces.
47class ChangeNamespaceTool : public ast_matchers::MatchFinder::MatchCallback {
48public:
49 // Moves code in the old namespace `OldNs` to the new namespace `NewNs` in
50 // files matching `FilePattern`.
51 ChangeNamespaceTool(
52 llvm::StringRef OldNs, llvm::StringRef NewNs, llvm::StringRef FilePattern,
Eric Liu7fccc992017-02-24 11:54:45 +000053 llvm::ArrayRef<std::string> WhiteListedSymbolPatterns,
Eric Liu495b2112016-09-19 17:40:32 +000054 std::map<std::string, tooling::Replacements> *FileToReplacements,
55 llvm::StringRef FallbackStyle = "LLVM");
56
57 void registerMatchers(ast_matchers::MatchFinder *Finder);
58
59 void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
60
61 // Moves the changed code in old namespaces but leaves class forward
62 // declarations behind.
63 void onEndOfTranslationUnit() override;
64
65private:
66 void moveOldNamespace(const ast_matchers::MatchFinder::MatchResult &Result,
67 const NamespaceDecl *NsDecl);
68
69 void moveClassForwardDeclaration(
70 const ast_matchers::MatchFinder::MatchResult &Result,
Eric Liu41552d62016-12-07 14:20:52 +000071 const NamedDecl *FwdDecl);
Eric Liu495b2112016-09-19 17:40:32 +000072
73 void replaceQualifiedSymbolInDeclContext(
74 const ast_matchers::MatchFinder::MatchResult &Result,
Eric Liub9bf1b52016-11-08 22:44:17 +000075 const DeclContext *DeclContext, SourceLocation Start, SourceLocation End,
76 const NamedDecl *FromDecl);
Eric Liu495b2112016-09-19 17:40:32 +000077
78 void fixTypeLoc(const ast_matchers::MatchFinder::MatchResult &Result,
79 SourceLocation Start, SourceLocation End, TypeLoc Type);
80
Eric Liu68765a82016-09-21 15:06:12 +000081 void fixUsingShadowDecl(const ast_matchers::MatchFinder::MatchResult &Result,
82 const UsingDecl *UsingDeclaration);
83
Eric Liuda22b3c2016-11-29 14:15:14 +000084 void fixDeclRefExpr(const ast_matchers::MatchFinder::MatchResult &Result,
85 const DeclContext *UseContext, const NamedDecl *From,
86 const DeclRefExpr *Ref);
87
Eric Liu495b2112016-09-19 17:40:32 +000088 // Information about moving an old namespace.
89 struct MoveNamespace {
90 // The start offset of the namespace block being moved in the original
91 // code.
92 unsigned Offset;
93 // The length of the namespace block in the original code.
94 unsigned Length;
95 // The offset at which the new namespace block will be inserted in the
96 // original code.
97 unsigned InsertionOffset;
98 // The file in which the namespace is declared.
Eric Liucc83c662016-09-19 17:58:59 +000099 FileID FID;
100 SourceManager *SourceMgr;
Eric Liu495b2112016-09-19 17:40:32 +0000101 };
102
103 // Information about inserting a class forward declaration.
104 struct InsertForwardDeclaration {
105 // The offset at while the forward declaration will be inserted in the
106 // original code.
107 unsigned InsertionOffset;
108 // The code to be inserted.
109 std::string ForwardDeclText;
110 };
111
112 std::string FallbackStyle;
113 // In match callbacks, this contains replacements for replacing `typeLoc`s in
114 // and deleting forward declarations in the moved namespace blocks.
115 // In `onEndOfTranslationUnit` callback, the previous added replacements are
116 // applied (on the moved namespace blocks), and then changed code in old
117 // namespaces re moved to new namespaces, and previously deleted forward
118 // declarations are inserted back to old namespaces, from which they are
119 // deleted.
120 std::map<std::string, tooling::Replacements> &FileToReplacements;
121 // A fully qualified name of the old namespace without "::" prefix, e.g.
122 // "a::b::c".
123 std::string OldNamespace;
124 // A fully qualified name of the new namespace without "::" prefix, e.g.
125 // "x::y::z".
126 std::string NewNamespace;
127 // The longest suffix in the old namespace that does not overlap the new
128 // namespace.
129 // For example, if `OldNamespace` is "a::b::c" and `NewNamespace` is
130 // "a::x::y", then `DiffOldNamespace` will be "b::c".
131 std::string DiffOldNamespace;
132 // The longest suffix in the new namespace that does not overlap the old
133 // namespace.
134 // For example, if `OldNamespace` is "a::b::c" and `NewNamespace` is
135 // "a::x::y", then `DiffNewNamespace` will be "x::y".
136 std::string DiffNewNamespace;
137 // A regex pattern that matches files to be processed.
138 std::string FilePattern;
Eric Liuc265b022016-12-01 17:25:55 +0000139 llvm::Regex FilePatternRE;
Eric Liu495b2112016-09-19 17:40:32 +0000140 // Information about moved namespaces grouped by file.
141 // Since we are modifying code in old namespaces (e.g. add namespace
142 // spedifiers) as well as moving them, we store information about namespaces
143 // to be moved and only move them after all modifications are finished (i.e.
144 // in `onEndOfTranslationUnit`).
145 std::map<std::string, std::vector<MoveNamespace>> MoveNamespaces;
146 // Information about forward declaration insertions grouped by files.
147 // A class forward declaration is not moved, so it will be deleted from the
148 // moved code block and inserted back into the old namespace. The insertion
149 // will be done after removing the code from the old namespace and before
150 // inserting it to the new namespace.
151 std::map<std::string, std::vector<InsertForwardDeclaration>> InsertFwdDecls;
Eric Liub9bf1b52016-11-08 22:44:17 +0000152 // Records all using declarations, which can be used to shorten namespace
153 // specifiers.
154 llvm::SmallPtrSet<const UsingDecl *, 8> UsingDecls;
155 // Records all using namespace declarations, which can be used to shorten
156 // namespace specifiers.
157 llvm::SmallPtrSet<const UsingDirectiveDecl *, 8> UsingNamespaceDecls;
Eric Liu180dac62016-12-23 10:47:09 +0000158 // Records all namespace alias declarations, which can be used to shorten
159 // namespace specifiers.
160 llvm::SmallPtrSet<const NamespaceAliasDecl *, 8> NamespaceAliasDecls;
Eric Liuff51f012016-11-16 16:54:53 +0000161 // TypeLocs of CXXCtorInitializer. Types of CXXCtorInitializers do not need to
162 // be fixed.
163 llvm::SmallVector<TypeLoc, 8> BaseCtorInitializerTypeLocs;
Eric Liue3f35e42016-12-20 14:39:04 +0000164 // Since a DeclRefExpr for a function call can be matched twice (one as
165 // CallExpr and one as DeclRefExpr), we record all DeclRefExpr's that have
166 // been processed so that we don't handle them twice.
167 llvm::SmallPtrSet<const clang::DeclRefExpr*, 16> ProcessedFuncRefs;
Eric Liu7fccc992017-02-24 11:54:45 +0000168 // Patterns of symbol names whose references are not expected to be updated
169 // when changing namespaces around them.
170 std::vector<llvm::Regex> WhiteListedSymbolRegexes;
Eric Liu495b2112016-09-19 17:40:32 +0000171};
172
173} // namespace change_namespace
174} // namespace clang
175
176#endif // LLVM_CLANG_TOOLS_EXTRA_CHANGE_NAMESPACE_CHANGENAMESPACE_H