Eric Liu | 495b211 | 2016-09-19 17:40:32 +0000 | [diff] [blame] | 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" |
Eric Liu | c265b02 | 2016-12-01 17:25:55 +0000 | [diff] [blame] | 16 | #include "llvm/Support/Regex.h" |
Eric Liu | 495b211 | 2016-09-19 17:40:32 +0000 | [diff] [blame] | 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. |
Eric Liu | 97f87ad | 2016-12-07 20:08:02 +0000 | [diff] [blame] | 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. |
Eric Liu | 495b211 | 2016-09-19 17:40:32 +0000 | [diff] [blame] | 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 { |
Eric Liu | 97f87ad | 2016-12-07 20:08:02 +0000 | [diff] [blame] | 44 | // class A { ::a::FWD *fwd; } |
Eric Liu | 495b211 | 2016-09-19 17:40:32 +0000 | [diff] [blame] | 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, |
Eric Liu | 7fccc99 | 2017-02-24 11:54:45 +0000 | [diff] [blame] | 53 | llvm::ArrayRef<std::string> WhiteListedSymbolPatterns, |
Eric Liu | 495b211 | 2016-09-19 17:40:32 +0000 | [diff] [blame] | 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, |
Eric Liu | 41552d6 | 2016-12-07 14:20:52 +0000 | [diff] [blame] | 71 | const NamedDecl *FwdDecl); |
Eric Liu | 495b211 | 2016-09-19 17:40:32 +0000 | [diff] [blame] | 72 | |
| 73 | void replaceQualifiedSymbolInDeclContext( |
| 74 | const ast_matchers::MatchFinder::MatchResult &Result, |
Eric Liu | b9bf1b5 | 2016-11-08 22:44:17 +0000 | [diff] [blame] | 75 | const DeclContext *DeclContext, SourceLocation Start, SourceLocation End, |
| 76 | const NamedDecl *FromDecl); |
Eric Liu | 495b211 | 2016-09-19 17:40:32 +0000 | [diff] [blame] | 77 | |
| 78 | void fixTypeLoc(const ast_matchers::MatchFinder::MatchResult &Result, |
| 79 | SourceLocation Start, SourceLocation End, TypeLoc Type); |
| 80 | |
Eric Liu | 68765a8 | 2016-09-21 15:06:12 +0000 | [diff] [blame] | 81 | void fixUsingShadowDecl(const ast_matchers::MatchFinder::MatchResult &Result, |
| 82 | const UsingDecl *UsingDeclaration); |
| 83 | |
Eric Liu | da22b3c | 2016-11-29 14:15:14 +0000 | [diff] [blame] | 84 | void fixDeclRefExpr(const ast_matchers::MatchFinder::MatchResult &Result, |
| 85 | const DeclContext *UseContext, const NamedDecl *From, |
| 86 | const DeclRefExpr *Ref); |
| 87 | |
Eric Liu | 495b211 | 2016-09-19 17:40:32 +0000 | [diff] [blame] | 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. |
Eric Liu | cc83c66 | 2016-09-19 17:58:59 +0000 | [diff] [blame] | 99 | FileID FID; |
| 100 | SourceManager *SourceMgr; |
Eric Liu | 495b211 | 2016-09-19 17:40:32 +0000 | [diff] [blame] | 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; |
Eric Liu | c265b02 | 2016-12-01 17:25:55 +0000 | [diff] [blame] | 139 | llvm::Regex FilePatternRE; |
Eric Liu | 495b211 | 2016-09-19 17:40:32 +0000 | [diff] [blame] | 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; |
Eric Liu | b9bf1b5 | 2016-11-08 22:44:17 +0000 | [diff] [blame] | 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; |
Eric Liu | 180dac6 | 2016-12-23 10:47:09 +0000 | [diff] [blame] | 158 | // Records all namespace alias declarations, which can be used to shorten |
| 159 | // namespace specifiers. |
| 160 | llvm::SmallPtrSet<const NamespaceAliasDecl *, 8> NamespaceAliasDecls; |
Eric Liu | ff51f01 | 2016-11-16 16:54:53 +0000 | [diff] [blame] | 161 | // TypeLocs of CXXCtorInitializer. Types of CXXCtorInitializers do not need to |
| 162 | // be fixed. |
| 163 | llvm::SmallVector<TypeLoc, 8> BaseCtorInitializerTypeLocs; |
Eric Liu | e3f35e4 | 2016-12-20 14:39:04 +0000 | [diff] [blame] | 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; |
Eric Liu | 7fccc99 | 2017-02-24 11:54:45 +0000 | [diff] [blame] | 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; |
Eric Liu | 495b211 | 2016-09-19 17:40:32 +0000 | [diff] [blame] | 171 | }; |
| 172 | |
| 173 | } // namespace change_namespace |
| 174 | } // namespace clang |
| 175 | |
| 176 | #endif // LLVM_CLANG_TOOLS_EXTRA_CHANGE_NAMESPACE_CHANGENAMESPACE_H |