clang-tools  7.0.0
ChangeNamespace.h
Go to the documentation of this file.
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`.
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  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
void registerMatchers(ast_matchers::MatchFinder *Finder)
void run(const ast_matchers::MatchFinder::MatchResult &Result) override
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
ChangeNamespaceTool(llvm::StringRef OldNs, llvm::StringRef NewNs, llvm::StringRef FilePattern, llvm::ArrayRef< std::string > WhiteListedSymbolPatterns, std::map< std::string, tooling::Replacements > *FileToReplacements, llvm::StringRef FallbackStyle="LLVM")