Index: clang-move/ClangMove.h =================================================================== --- clang-move/ClangMove.h +++ clang-move/ClangMove.h @@ -135,6 +135,10 @@ std::vector &getMovedDecls() { return MovedDecls; } + /// Add declatrations which are being moved to new.h/cc and being deleted in + /// old.h/cc. + void addMovedAndDeletedDecl(const NamedDecl *Decl); + /// Add declarations being removed from old.h/cc. For each declarations, the /// method also records the mapping relationship between the corresponding /// FilePath and its FileID. @@ -153,6 +157,7 @@ void moveDeclsToNewFiles(); void moveAll(SourceManager& SM, StringRef OldFile, StringRef NewFile); + // Stores all MatchCallbacks created by this tool. std::vector> MatchCallbacks; Index: clang-move/ClangMove.cpp =================================================================== --- clang-move/ClangMove.cpp +++ clang-move/ClangMove.cpp @@ -151,9 +151,22 @@ const clang::NamedDecl *D = FD; if (const auto *FTD = FD->getDescribedFunctionTemplate()) D = FTD; - MoveTool->getMovedDecls().push_back(D); - MoveTool->getUnremovedDeclsInOldHeader().erase(D); - MoveTool->addRemovedDecl(D); + MoveTool->addMovedAndDeletedDecl(D); + } + +private: + ClangMoveTool *MoveTool; +}; + +class EnumDeclarationMatch : public MatchFinder::MatchCallback { +public: + explicit EnumDeclarationMatch(ClangMoveTool *MoveTool) + : MoveTool(MoveTool) {} + + void run(const MatchFinder::MatchResult &Result) override { + const auto *ED = Result.Nodes.getNodeAs("enum"); + assert(ED); + MoveTool->addMovedAndDeletedDecl(ED); } private: @@ -196,9 +209,7 @@ void MatchClassStaticVariable(const clang::NamedDecl *VD, clang::SourceManager* SM) { - MoveTool->getMovedDecls().push_back(VD); - MoveTool->addRemovedDecl(VD); - MoveTool->getUnremovedDeclsInOldHeader().erase(VD); + MoveTool->addMovedAndDeletedDecl(VD); } void MatchClassDeclaration(const clang::CXXRecordDecl *CD, @@ -434,6 +445,12 @@ CCIncludes.push_back("#include \"" + Context->Spec.NewHeader + "\"\n"); } +void ClangMoveTool::addMovedAndDeletedDecl(const NamedDecl *D) { + MovedDecls.push_back(D); + addRemovedDecl(D); + UnremovedDeclsInOldHeader.erase(D); +} + void ClangMoveTool::addRemovedDecl(const NamedDecl *Decl) { const auto &SM = Decl->getASTContext().getSourceManager(); auto Loc = Decl->getLocation(); @@ -449,6 +466,8 @@ auto InOldFiles = anyOf(InOldHeader, InOldCC); auto ForwardDecls = cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition()))); + auto TopLevelDecl = + hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl())); //============================================================================ // Matchers for old header @@ -544,11 +563,9 @@ // Create a MatchCallback for class declarations. MatchCallbacks.push_back(llvm::make_unique(this)); // Match moved class declarations. - auto MovedClass = - cxxRecordDecl( - InOldFiles, *HasAnySymbolNames, isDefinition(), - hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl()))) - .bind("moved_class"); + auto MovedClass = cxxRecordDecl(InOldFiles, *HasAnySymbolNames, + isDefinition(), TopLevelDecl) + .bind("moved_class"); Finder->addMatcher(MovedClass, MatchCallbacks.back().get()); // Match moved class methods (static methods included) which are defined // outside moved class declaration. @@ -564,11 +581,16 @@ MatchCallbacks.back().get()); MatchCallbacks.push_back(llvm::make_unique(this)); - Finder->addMatcher(functionDecl(InOldFiles, *HasAnySymbolNames, - anyOf(hasDeclContext(namespaceDecl()), - hasDeclContext(translationUnitDecl()))) + Finder->addMatcher(functionDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl) .bind("function"), MatchCallbacks.back().get()); + + // Match enum declarations. + MatchCallbacks.push_back(llvm::make_unique(this)); + Finder->addMatcher( + enumDecl(InOldHeader, *HasAnySymbolNames, isDefinition(), TopLevelDecl) + .bind("enum"), + MatchCallbacks.back().get()); } void ClangMoveTool::run(const ast_matchers::MatchFinder::MatchResult &Result) { @@ -802,6 +824,7 @@ case Decl::Kind::FunctionTemplate: case Decl::Kind::ClassTemplate: case Decl::Kind::CXXRecord: + case Decl::Kind::Enum: return true; default: return false; Index: test/clang-move/Inputs/enum.h =================================================================== --- /dev/null +++ test/clang-move/Inputs/enum.h @@ -0,0 +1,9 @@ +namespace a { +enum E1 { Green, Red }; + +enum class E2 { Yellow }; + +class C { + enum E3 { Blue }; +}; +} // namespace a Index: test/clang-move/move-enum-decl.cpp =================================================================== --- /dev/null +++ test/clang-move/move-enum-decl.cpp @@ -0,0 +1,44 @@ +// RUN: mkdir -p %T/move-enum +// RUN: cp %S/Inputs/enum.h %T/move-enum/enum.h +// RUN: echo '#include "enum.h"' > %T/move-enum/enum.cpp +// RUN: cd %T/move-enum +// +// ----------------------------------------------------------------------------- +// Test moving enum declarations. +// ----------------------------------------------------------------------------- +// RUN: clang-move -names="a::E1" -new_cc=%T/move-enum/new_test.cpp -new_header=%T/move-enum/new_test.h -old_cc=%T/move-enum/enum.cpp -old_header=%T/move-enum/enum.h %T/move-enum/enum.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%T/move-enum/new_test.h -check-prefix=CHECK-NEW-TEST-H-CASE1 %s +// RUN: FileCheck -input-file=%T/move-enum/enum.h -check-prefix=CHECK-OLD-TEST-H-CASE1 %s +// +// CHECK-NEW-TEST-H-CASE1: namespace a { +// CHECK-NEW-TEST-H-CASE1-NEXT: enum E1 { Green, Red }; +// CHECK-NEW-TEST-H-CASE1-NEXT: } + +// CHECK-OLD-TEST-H-CASE1-NOT: enum E1 { Green, Red }; + + +// ----------------------------------------------------------------------------- +// Test moving scoped enum declarations. +// ----------------------------------------------------------------------------- +// RUN: cp %S/Inputs/enum.h %T/move-enum/enum.h +// RUN: echo '#include "enum.h"' > %T/move-enum/enum.cpp +// RUN: clang-move -names="a::E2" -new_cc=%T/move-enum/new_test.cpp -new_header=%T/move-enum/new_test.h -old_cc=%T/move-enum/enum.cpp -old_header=%T/move-enum/enum.h %T/move-enum/enum.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%T/move-enum/new_test.h -check-prefix=CHECK-NEW-TEST-H-CASE2 %s +// RUN: FileCheck -input-file=%T/move-enum/enum.h -check-prefix=CHECK-OLD-TEST-H-CASE2 %s + +// CHECK-NEW-TEST-H-CASE2: namespace a { +// CHECK-NEW-TEST-H-CASE2-NEXT: enum class E2 { Yellow }; +// CHECK-NEW-TEST-H-CASE2-NEXT: } + +// CHECK-OLD-TEST-H-CASE2-NOT: enum class E2 { Yellow }; + + +// ----------------------------------------------------------------------------- +// Test not moving class-insided enum declarations. +// ----------------------------------------------------------------------------- +// RUN: cp %S/Inputs/enum.h %T/move-enum/enum.h +// RUN: echo '#include "enum.h"' > %T/move-enum/enum.cpp +// RUN: clang-move -names="a::C::E3" -new_cc=%T/move-enum/new_test.cpp -new_header=%T/move-enum/new_test.h -old_cc=%T/move-enum/enum.cpp -old_header=%T/move-enum/enum.h %T/move-enum/enum.cpp -- -std=c++11 +// RUN: FileCheck -input-file=%T/move-enum/new_test.h -allow-empty -check-prefix=CHECK-EMPTY %s + +// CHECK-EMPTY: {{^}}{{$}} Index: unittests/clang-move/ClangMoveTests.cpp =================================================================== --- unittests/clang-move/ClangMoveTests.cpp +++ unittests/clang-move/ClangMoveTests.cpp @@ -370,7 +370,6 @@ std::vector TestHeaders = { "typedef int Int;\nclass A {\npublic:\n int f();\n};\n", "using Int = int;\nclass A {\npublic:\n int f();\n};\n", - "enum Color { RED };\nclass A {\npublic:\n int f();\n};\n", }; move::MoveDefinitionSpec Spec; Spec.Names.push_back("A");