Line data Source code
1 : //===-- 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 "llvm/Support/Regex.h"
17 : #include <string>
18 :
19 : namespace clang {
20 : namespace 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.
27 : // 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.
30 : // 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 {
44 : // class A { ::a::FWD *fwd; }
45 : // } // x
46 : // FIXME: support moving typedef, enums across namespaces.
47 : class ChangeNamespaceTool : public ast_matchers::MatchFinder::MatchCallback {
48 : public:
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,
53 : llvm::ArrayRef<std::string> WhiteListedSymbolPatterns,
54 : 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 :
65 : private:
66 : void moveOldNamespace(const ast_matchers::MatchFinder::MatchResult &Result,
67 : const NamespaceDecl *NsDecl);
68 :
69 : void moveClassForwardDeclaration(
70 : const ast_matchers::MatchFinder::MatchResult &Result,
71 : const NamedDecl *FwdDecl);
72 :
73 : void replaceQualifiedSymbolInDeclContext(
74 : const ast_matchers::MatchFinder::MatchResult &Result,
75 : const DeclContext *DeclContext, SourceLocation Start, SourceLocation End,
76 : const NamedDecl *FromDecl);
77 :
78 : void fixTypeLoc(const ast_matchers::MatchFinder::MatchResult &Result,
79 : SourceLocation Start, SourceLocation End, TypeLoc Type);
80 :
81 : void fixUsingShadowDecl(const ast_matchers::MatchFinder::MatchResult &Result,
82 : const UsingDecl *UsingDeclaration);
83 :
84 : void fixDeclRefExpr(const ast_matchers::MatchFinder::MatchResult &Result,
85 : const DeclContext *UseContext, const NamedDecl *From,
86 : const DeclRefExpr *Ref);
87 :
88 : // 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.
99 : FileID FID;
100 : SourceManager *SourceMgr;
101 : };
102 :
103 : // Information about inserting a class forward declaration.
104 7 : 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;
139 : llvm::Regex FilePatternRE;
140 : // 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;
152 : // 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;
158 : // Records all namespace alias declarations, which can be used to shorten
159 : // namespace specifiers.
160 : llvm::SmallPtrSet<const NamespaceAliasDecl *, 8> NamespaceAliasDecls;
161 : // TypeLocs of CXXCtorInitializer. Types of CXXCtorInitializers do not need to
162 : // be fixed.
163 : llvm::SmallVector<TypeLoc, 8> BaseCtorInitializerTypeLocs;
164 : // 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;
168 : // Patterns of symbol names whose references are not expected to be updated
169 : // when changing namespaces around them.
170 : std::vector<llvm::Regex> WhiteListedSymbolRegexes;
171 : };
172 :
173 : } // namespace change_namespace
174 : } // namespace clang
175 :
176 : #endif // LLVM_CLANG_TOOLS_EXTRA_CHANGE_NAMESPACE_CHANGENAMESPACE_H
|