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" |
| 16 | #include <string> |
| 17 | |
| 18 | namespace clang { |
| 19 | namespace 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. |
| 43 | class ChangeNamespaceTool : public ast_matchers::MatchFinder::MatchCallback { |
| 44 | public: |
| 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 | |
| 60 | private: |
| 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 Liu | 68765a8 | 2016-09-21 15:06:12 +0000 | [diff] [blame^] | 76 | void fixUsingShadowDecl(const ast_matchers::MatchFinder::MatchResult &Result, |
| 77 | const UsingDecl *UsingDeclaration); |
| 78 | |
Eric Liu | 495b211 | 2016-09-19 17:40:32 +0000 | [diff] [blame] | 79 | // 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 Liu | cc83c66 | 2016-09-19 17:58:59 +0000 | [diff] [blame] | 90 | FileID FID; |
| 91 | SourceManager *SourceMgr; |
Eric Liu | 495b211 | 2016-09-19 17:40:32 +0000 | [diff] [blame] | 92 | }; |
| 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 |