brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.6 KiB · d35119b Raw
176 lines · c
1//===-- ChangeNamespace.h -- Change namespace  ------------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#ifndef LLVM_CLANG_TOOLS_EXTRA_CHANGE_NAMESPACE_CHANGENAMESPACE_H10#define LLVM_CLANG_TOOLS_EXTRA_CHANGE_NAMESPACE_CHANGENAMESPACE_H11 12#include "clang/ASTMatchers/ASTMatchFinder.h"13#include "clang/Format/Format.h"14#include "clang/Tooling/Core/Replacement.h"15#include "llvm/Support/Regex.h"16#include <string>17 18namespace clang {19namespace change_namespace {20 21// This tool can be used to change the surrounding namespaces of class/function22// definitions. Classes/functions in the moved namespace will have new23// namespaces while references to symbols (e.g. types, functions) which are not24// defined in the changed namespace will be correctly qualified by prepending25// namespace specifiers before them.26// This will try to add shortest namespace specifiers possible. When a symbol27// reference needs to be fully-qualified, this adds a "::" prefix to the28// namespace specifiers unless the new namespace is the global namespace.29// For classes, only classes that are declared/defined in the given namespace in30// specified files will be moved: forward declarations will remain in the old31// namespace.32// For example, changing "a" to "x":33// Old code:34//   namespace a {35//   class FWD;36//   class A { FWD *fwd; }37//   }  // a38// New code:39//   namespace a {40//   class FWD;41//   }  // a42//   namespace x {43//   class A { ::a::FWD *fwd; }44//   }  // x45// FIXME: support moving typedef, enums across namespaces.46class ChangeNamespaceTool : public ast_matchers::MatchFinder::MatchCallback {47public:48  // Moves code in the old namespace `OldNs` to the new namespace `NewNs` in49  // files matching `FilePattern`.50  ChangeNamespaceTool(51      llvm::StringRef OldNs, llvm::StringRef NewNs, llvm::StringRef FilePattern,52      llvm::ArrayRef<std::string> AllowedSymbolPatterns,53      std::map<std::string, tooling::Replacements> *FileToReplacements,54      llvm::StringRef FallbackStyle = "LLVM");55 56  void registerMatchers(ast_matchers::MatchFinder *Finder);57 58  void run(const ast_matchers::MatchFinder::MatchResult &Result) override;59 60  // Moves the changed code in old namespaces but leaves class forward61  // declarations behind.62  void onEndOfTranslationUnit() override;63 64private:65  void moveOldNamespace(const ast_matchers::MatchFinder::MatchResult &Result,66                        const NamespaceDecl *NsDecl);67 68  void moveClassForwardDeclaration(69      const ast_matchers::MatchFinder::MatchResult &Result,70      const NamedDecl *FwdDecl);71 72  void replaceQualifiedSymbolInDeclContext(73      const ast_matchers::MatchFinder::MatchResult &Result,74      const DeclContext *DeclContext, SourceLocation Start, SourceLocation End,75      const NamedDecl *FromDecl);76 77  void fixTypeLoc(const ast_matchers::MatchFinder::MatchResult &Result,78                  SourceLocation Start, SourceLocation End, TypeLoc Type);79 80  void fixUsingShadowDecl(const ast_matchers::MatchFinder::MatchResult &Result,81                          const UsingDecl *UsingDeclaration);82 83  void fixDeclRefExpr(const ast_matchers::MatchFinder::MatchResult &Result,84                      const DeclContext *UseContext, const NamedDecl *From,85                      const DeclRefExpr *Ref);86 87  // Information about moving an old namespace.88  struct MoveNamespace {89    // The start offset of the namespace block being moved in the original90    // code.91    unsigned Offset;92    // The length of the namespace block in the original code.93    unsigned Length;94    // The offset at which the new namespace block will be inserted in the95    // original code.96    unsigned InsertionOffset;97    // The file in which the namespace is declared.98    FileID FID;99    SourceManager *SourceMgr;100  };101 102  // Information about inserting a class forward declaration.103  struct InsertForwardDeclaration {104    // The offset at while the forward declaration will be inserted in the105    // original code.106    unsigned InsertionOffset;107    // The code to be inserted.108    std::string ForwardDeclText;109  };110 111  std::string FallbackStyle;112  // In match callbacks, this contains replacements for replacing `typeLoc`s in113  // and deleting forward declarations in the moved namespace blocks.114  // In `onEndOfTranslationUnit` callback, the previous added replacements are115  // applied (on the moved namespace blocks), and then changed code in old116  // namespaces re moved to new namespaces, and previously deleted forward117  // declarations are inserted back to old namespaces, from which they are118  // deleted.119  std::map<std::string, tooling::Replacements> &FileToReplacements;120  // A fully qualified name of the old namespace without "::" prefix, e.g.121  // "a::b::c".122  std::string OldNamespace;123  // A fully qualified name of the new namespace without "::" prefix, e.g.124  // "x::y::z".125  std::string NewNamespace;126  // The longest suffix in the old namespace that does not overlap the new127  // namespace.128  // For example, if `OldNamespace` is "a::b::c" and `NewNamespace` is129  // "a::x::y", then `DiffOldNamespace` will be "b::c".130  std::string DiffOldNamespace;131  // The longest suffix in the new namespace that does not overlap the old132  // namespace.133  // For example, if `OldNamespace` is "a::b::c" and `NewNamespace` is134  // "a::x::y", then `DiffNewNamespace` will be "x::y".135  std::string DiffNewNamespace;136  // A regex pattern that matches files to be processed.137  std::string FilePattern;138  llvm::Regex FilePatternRE;139  // Information about moved namespaces grouped by file.140  // Since we are modifying code in old namespaces (e.g. add namespace141  // specifiers) as well as moving them, we store information about namespaces142  // to be moved and only move them after all modifications are finished (i.e.143  // in `onEndOfTranslationUnit`).144  std::map<std::string, std::vector<MoveNamespace>> MoveNamespaces;145  // Information about forward declaration insertions grouped by files.146  // A class forward declaration is not moved, so it will be deleted from the147  // moved code block and inserted back into the old namespace. The insertion148  // will be done after removing the code from the old namespace and before149  // inserting it to the new namespace.150  std::map<std::string, std::vector<InsertForwardDeclaration>> InsertFwdDecls;151  // Records all using declarations, which can be used to shorten namespace152  // specifiers.153  llvm::SmallPtrSet<const UsingDecl *, 8> UsingDecls;154  // Records all using namespace declarations, which can be used to shorten155  // namespace specifiers.156  llvm::SmallPtrSet<const UsingDirectiveDecl *, 8> UsingNamespaceDecls;157  // Records all namespace alias declarations, which can be used to shorten158  // namespace specifiers.159  llvm::SmallPtrSet<const NamespaceAliasDecl *, 8> NamespaceAliasDecls;160  // TypeLocs of CXXCtorInitializer. Types of CXXCtorInitializers do not need to161  // be fixed.162  llvm::SmallVector<TypeLoc, 8> BaseCtorInitializerTypeLocs;163  // Since a DeclRefExpr for a function call can be matched twice (one as164  // CallExpr and one as DeclRefExpr), we record all DeclRefExpr's that have165  // been processed so that we don't handle them twice.166  llvm::SmallPtrSet<const clang::DeclRefExpr*, 16> ProcessedFuncRefs;167  // Patterns of symbol names whose references are not expected to be updated168  // when changing namespaces around them.169  std::vector<llvm::Regex> AllowedSymbolRegexes;170};171 172} // namespace change_namespace173} // namespace clang174 175#endif // LLVM_CLANG_TOOLS_EXTRA_CHANGE_NAMESPACE_CHANGENAMESPACE_H176