Index: clang-tools-extra/trunk/clang-move/ClangMove.h =================================================================== --- clang-tools-extra/trunk/clang-move/ClangMove.h +++ clang-tools-extra/trunk/clang-move/ClangMove.h @@ -24,11 +24,78 @@ namespace clang { namespace move { -// FIXME: Make it support more types, e.g. function definitions. -// Currently only support moving class definition. +// A reporter which collects and reports declarations in old header. +class DeclarationReporter { +public: + DeclarationReporter() = default; + ~DeclarationReporter() = default; + + void reportDeclaration(llvm::StringRef DeclarationName, + llvm::StringRef Type) { + DeclarationList.emplace_back(DeclarationName, Type); + }; + + // A pair. + // The DeclarationName is a fully qualified name for the declaration, like + // A::B::Foo. The DeclarationKind is a string represents the kind of the + // declaration, currently only "Function" and "Class" are supported. + typedef std::pair DeclarationPair; + + const std::vector getDeclarationList() const { + return DeclarationList; + } + +private: + std::vector DeclarationList; +}; + +// Specify declarations being moved. It contains all information of the moved +// declarations. +struct MoveDefinitionSpec { + // The list of fully qualified names, e.g. Foo, a::Foo, b::Foo. + SmallVector Names; + // The file path of old header, can be relative path and absolute path. + std::string OldHeader; + // The file path of old cc, can be relative path and absolute path. + std::string OldCC; + // The file path of new header, can be relative path and absolute path. + std::string NewHeader; + // The file path of new cc, can be relative path and absolute path. + std::string NewCC; + // Whether old.h depends on new.h. If true, #include "new.h" will be added + // in old.h. + bool OldDependOnNew = false; + // Whether new.h depends on old.h. If true, #include "old.h" will be added + // in new.h. + bool NewDependOnOld = false; +}; + +// A Context which contains extra options which are used in ClangMoveTool. +struct ClangMoveContext { + MoveDefinitionSpec Spec; + // The Key is file path, value is the replacements being applied to the file. + std::map &FileToReplacements; + // The original working directory where the local clang-move binary runs. + // + // clang-move will change its current working directory to the build + // directory when analyzing the source file. We save the original working + // directory in order to get the absolute file path for the fields in Spec. + std::string OriginalRunningDirectory; + // The name of a predefined code style. + std::string FallbackStyle; + // Whether dump all declarations in old header. + bool DumpDeclarations; +}; + +// This tool is used to move class/function definitions from the given source +// files (old.h/cc) to new files (new.h/cc). When moving a class, all its +// members are also moved. In addition, all helper functions (anonymous +// namespace declarations, static declarations, using declarations) in old.cc +// and forward class declarations in old.h are copied to the new files. +// The goal of this tool is to make the new files as compliable as possible. // -// When moving all class declarations in old header, all code in old.h/cc will -// be moved. +// Note: When all declarations in old header are being moved, all code in +// old.h/cc will be moved, which means old.h/cc are empty. class ClangMoveTool : public ast_matchers::MatchFinder::MatchCallback { public: // Information about the declaration being moved. @@ -42,29 +109,8 @@ : Decl(Decl), SM(SM) {} }; - struct MoveDefinitionSpec { - // The list of fully qualified names, e.g. Foo, a::Foo, b::Foo. - SmallVector Names; - // The file path of old header, can be relative path and absolute path. - std::string OldHeader; - // The file path of old cc, can be relative path and absolute path. - std::string OldCC; - // The file path of new header, can be relative path and absolute path. - std::string NewHeader; - // The file path of new cc, can be relative path and absolute path. - std::string NewCC; - // Whether old.h depends on new.h. If true, #include "new.h" will be added - // in old.h. - bool OldDependOnNew = false; - // Whether new.h depends on old.h. If true, #include "old.h" will be added - // in new.h. - bool NewDependOnOld = false; - }; - - ClangMoveTool( - const MoveDefinitionSpec &MoveSpec, - std::map &FileToReplacements, - llvm::StringRef OriginalRunningDirectory, llvm::StringRef Style); + ClangMoveTool(ClangMoveContext *const Context, + DeclarationReporter *const Reporter); void registerMatchers(ast_matchers::MatchFinder *Finder); @@ -80,8 +126,8 @@ /// \param SearchPath The search path which was used to find the IncludeHeader /// in the file system. It can be a relative path or an absolute path. /// \param FileName The name of file where the IncludeHeader comes from. - /// \param IncludeFilenameRange The source range for the written file name in #include - /// (i.e. "old.h" for #include "old.h") in old.cc. + /// \param IncludeFilenameRange The source range for the written file name in + /// #include (i.e. "old.h" for #include "old.h") in old.cc. /// \param SM The SourceManager. void addIncludes(llvm::StringRef IncludeHeader, bool IsAngled, llvm::StringRef SearchPath, llvm::StringRef FileName, @@ -108,12 +154,9 @@ void moveClassDefinitionToNewFiles(); void moveAll(SourceManager& SM, StringRef OldFile, StringRef NewFile); - MoveDefinitionSpec Spec; // Stores all MatchCallbacks created by this tool. std::vector> MatchCallbacks; - // The Key is file path, value is the replacements being applied to the file. - std::map &FileToReplacements; // All declarations (the class decl being moved, forward decls) that need to // be moved/copy to the new files, saving in an AST-visited order. std::vector MovedDecls; @@ -123,14 +166,6 @@ std::vector HeaderIncludes; // The #includes in old_cc.cc. std::vector CCIncludes; - // The original working directory where the local clang-move binary runs. - // - // clang-move will change its current working directory to the build - // directory when analyzing the source file. We save the original working - // directory in order to get the absolute file path for the fields in Spec. - std::string OriginalRunningDirectory; - // The name of a predefined code style. - std::string FallbackStyle; // The unmoved named declarations in old header. llvm::SmallPtrSet UnremovedDeclsInOldHeader; /// The source range for the written file name in #include (i.e. "old.h" for @@ -140,16 +175,17 @@ /// Mapping from FilePath to FileID, which can be used in post processes like /// cleanup around replacements. llvm::StringMap FilePathToFileID; + /// A context contains all running options. It is not owned. + ClangMoveContext *const Context; + /// A reporter to report all declarations from old header. It is not owned. + DeclarationReporter *const Reporter; }; class ClangMoveAction : public clang::ASTFrontendAction { public: - ClangMoveAction( - const ClangMoveTool::MoveDefinitionSpec &spec, - std::map &FileToReplacements, - llvm::StringRef OriginalRunningDirectory, llvm::StringRef FallbackStyle) - : MoveTool(spec, FileToReplacements, OriginalRunningDirectory, - FallbackStyle) { + ClangMoveAction(ClangMoveContext *const Context, + DeclarationReporter *const Reporter) + : MoveTool(Context, Reporter) { MoveTool.registerMatchers(&MatchFinder); } @@ -166,24 +202,18 @@ class ClangMoveActionFactory : public tooling::FrontendActionFactory { public: - ClangMoveActionFactory( - const ClangMoveTool::MoveDefinitionSpec &Spec, - std::map &FileToReplacements, - llvm::StringRef OriginalRunningDirectory, llvm::StringRef FallbackStyle) - : Spec(Spec), FileToReplacements(FileToReplacements), - OriginalRunningDirectory(OriginalRunningDirectory), - FallbackStyle(FallbackStyle) {} + ClangMoveActionFactory(ClangMoveContext *const Context, + DeclarationReporter *const Reporter = nullptr) + : Context(Context), Reporter(Reporter) {} clang::FrontendAction *create() override { - return new ClangMoveAction(Spec, FileToReplacements, - OriginalRunningDirectory, FallbackStyle); + return new ClangMoveAction(Context, Reporter); } private: - const ClangMoveTool::MoveDefinitionSpec &Spec; - std::map &FileToReplacements; - std::string OriginalRunningDirectory; - std::string FallbackStyle; + // Not owned. + ClangMoveContext *const Context; + DeclarationReporter *const Reporter; }; } // namespace move Index: clang-tools-extra/trunk/clang-move/ClangMove.cpp =================================================================== --- clang-tools-extra/trunk/clang-move/ClangMove.cpp +++ clang-tools-extra/trunk/clang-move/ClangMove.cpp @@ -401,15 +401,11 @@ return MatchFinder.newASTConsumer(); } -ClangMoveTool::ClangMoveTool( - const MoveDefinitionSpec &MoveSpec, - std::map &FileToReplacements, - llvm::StringRef OriginalRunningDirectory, llvm::StringRef FallbackStyle) - : Spec(MoveSpec), FileToReplacements(FileToReplacements), - OriginalRunningDirectory(OriginalRunningDirectory), - FallbackStyle(FallbackStyle) { - if (!Spec.NewHeader.empty()) - CCIncludes.push_back("#include \"" + Spec.NewHeader + "\"\n"); +ClangMoveTool::ClangMoveTool(ClangMoveContext *const Context, + DeclarationReporter *const Reporter) + : Context(Context), Reporter(Reporter) { + if (!Context->Spec.NewHeader.empty()) + CCIncludes.push_back("#include \"" + Context->Spec.NewHeader + "\"\n"); } void ClangMoveTool::addRemovedDecl(const MovedDecl &Decl) { @@ -421,24 +417,10 @@ } void ClangMoveTool::registerMatchers(ast_matchers::MatchFinder *Finder) { - Optional> HasAnySymbolNames; - for (StringRef SymbolName: Spec.Names) { - llvm::StringRef GlobalSymbolName = SymbolName.trim().ltrim(':'); - const auto HasName = hasName(("::" + GlobalSymbolName).str()); - HasAnySymbolNames = - HasAnySymbolNames ? anyOf(*HasAnySymbolNames, HasName) : HasName; - } - if (!HasAnySymbolNames) { - llvm::errs() << "No symbols being moved.\n"; - return; - } - - auto InOldHeader = isExpansionInFile(makeAbsolutePath(Spec.OldHeader)); - auto InOldCC = isExpansionInFile(makeAbsolutePath(Spec.OldCC)); + auto InOldHeader = + isExpansionInFile(makeAbsolutePath(Context->Spec.OldHeader)); + auto InOldCC = isExpansionInFile(makeAbsolutePath(Context->Spec.OldCC)); auto InOldFiles = anyOf(InOldHeader, InOldCC); - auto InMovedClass = - hasOutermostEnclosingClass(cxxRecordDecl(*HasAnySymbolNames)); - auto ForwardDecls = cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition()))); @@ -448,15 +430,21 @@ // Match all top-level named declarations (e.g. function, variable, enum) in // old header, exclude forward class declarations and namespace declarations. // - // The old header which contains only one declaration being moved and forward - // declarations is considered to be moved totally. + // We consider declarations inside a class belongs to the class. So these + // declarations will be ignored. auto AllDeclsInHeader = namedDecl( unless(ForwardDecls), unless(namespaceDecl()), - unless(usingDirectiveDecl()), // using namespace decl. + unless(usingDirectiveDecl()), // using namespace decl. unless(classTemplateDecl(has(ForwardDecls))), // template forward decl. InOldHeader, - hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl())))); + hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))), + hasDeclContext(decl(anyOf(namespaceDecl(), translationUnitDecl())))); Finder->addMatcher(AllDeclsInHeader.bind("decls_in_header"), this); + + // Don't register other matchers when dumping all declarations in header. + if (Context->DumpDeclarations) + return; + // Match forward declarations in old header. Finder->addMatcher(namedDecl(ForwardDecls, InOldHeader).bind("fwd_decl"), this); @@ -484,6 +472,20 @@ // Match static functions/variable definitions which are defined in named // namespaces. + Optional> HasAnySymbolNames; + for (StringRef SymbolName : Context->Spec.Names) { + llvm::StringRef GlobalSymbolName = SymbolName.trim().ltrim(':'); + const auto HasName = hasName(("::" + GlobalSymbolName).str()); + HasAnySymbolNames = + HasAnySymbolNames ? anyOf(*HasAnySymbolNames, HasName) : HasName; + } + + if (!HasAnySymbolNames) { + llvm::errs() << "No symbols being moved.\n"; + return; + } + auto InMovedClass = + hasOutermostEnclosingClass(cxxRecordDecl(*HasAnySymbolNames)); auto IsOldCCStaticDefinition = allOf(isDefinition(), unless(InMovedClass), InOldCCNamedOrGlobalNamespace, isStaticStorageClass()); @@ -531,7 +533,7 @@ UnremovedDeclsInOldHeader.insert(D); } else if (const auto *FWD = Result.Nodes.getNodeAs("fwd_decl")) { - // Skip all forwad declarations which appear after moved class declaration. + // Skip all forward declarations which appear after moved class declaration. if (RemovedDecls.empty()) { if (const auto *DCT = FWD->getDescribedClassTemplate()) MovedDecls.emplace_back(DCT, &Result.Context->getSourceManager()); @@ -551,7 +553,7 @@ } std::string ClangMoveTool::makeAbsolutePath(StringRef Path) { - return MakeAbsolutePath(OriginalRunningDirectory, Path); + return MakeAbsolutePath(Context->OriginalRunningDirectory, Path); } void ClangMoveTool::addIncludes(llvm::StringRef IncludeHeader, bool IsAngled, @@ -561,7 +563,7 @@ const SourceManager &SM) { SmallVector HeaderWithSearchPath; llvm::sys::path::append(HeaderWithSearchPath, SearchPath, IncludeHeader); - std::string AbsoluteOldHeader = makeAbsolutePath(Spec.OldHeader); + std::string AbsoluteOldHeader = makeAbsolutePath(Context->Spec.OldHeader); // FIXME: Add old.h to the new.cc/h when the new target has dependencies on // old.h/c. For instance, when moved class uses another class defined in // old.h, the old.h should be added in new.h. @@ -579,7 +581,7 @@ std::string AbsoluteCurrentFile = MakeAbsolutePath(SM, FileName); if (AbsoluteOldHeader == AbsoluteCurrentFile) { HeaderIncludes.push_back(IncludeLine); - } else if (makeAbsolutePath(Spec.OldCC) == AbsoluteCurrentFile) { + } else if (makeAbsolutePath(Context->Spec.OldCC) == AbsoluteCurrentFile) { CCIncludes.push_back(IncludeLine); } } @@ -594,20 +596,22 @@ clang::CharSourceRange::getCharRange(Range.getBegin(), Range.getEnd()), ""); std::string FilePath = RemoveReplacement.getFilePath().str(); - auto Err = FileToReplacements[FilePath].add(RemoveReplacement); + auto Err = Context->FileToReplacements[FilePath].add(RemoveReplacement); if (Err) llvm::errs() << llvm::toString(std::move(Err)) << "\n"; } const SourceManager* SM = RemovedDecls[0].SM; // Post process of cleanup around all the replacements. - for (auto& FileAndReplacements: FileToReplacements) { + for (auto &FileAndReplacements : Context->FileToReplacements) { StringRef FilePath = FileAndReplacements.first; // Add #include of new header to old header. - if (Spec.OldDependOnNew && - MakeAbsolutePath(*SM, FilePath) == makeAbsolutePath(Spec.OldHeader)) { + if (Context->Spec.OldDependOnNew && + MakeAbsolutePath(*SM, FilePath) == + makeAbsolutePath(Context->Spec.OldHeader)) { // FIXME: Minimize the include path like include-fixer. - std::string IncludeNewH = "#include \"" + Spec.NewHeader + "\"\n"; + std::string IncludeNewH = + "#include \"" + Context->Spec.NewHeader + "\"\n"; // This replacment for inserting header will be cleaned up at the end. auto Err = FileAndReplacements.second.add( tooling::Replacement(FilePath, UINT_MAX, 0, IncludeNewH)); @@ -620,15 +624,15 @@ if (SI == FilePathToFileID.end()) continue; llvm::StringRef Code = SM->getBufferData(SI->second); format::FormatStyle Style = - format::getStyle("file", FilePath, FallbackStyle); + format::getStyle("file", FilePath, Context->FallbackStyle); auto CleanReplacements = format::cleanupAroundReplacements( - Code, FileToReplacements[FilePath], Style); + Code, Context->FileToReplacements[FilePath], Style); if (!CleanReplacements) { llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n"; continue; } - FileToReplacements[FilePath] = *CleanReplacements; + Context->FileToReplacements[FilePath] = *CleanReplacements; } } @@ -636,23 +640,27 @@ std::vector NewHeaderDecls; std::vector NewCCDecls; for (const auto &MovedDecl : MovedDecls) { - if (isInHeaderFile(*MovedDecl.SM, MovedDecl.Decl, OriginalRunningDirectory, - Spec.OldHeader)) + if (isInHeaderFile(*MovedDecl.SM, MovedDecl.Decl, + Context->OriginalRunningDirectory, + Context->Spec.OldHeader)) NewHeaderDecls.push_back(MovedDecl); else NewCCDecls.push_back(MovedDecl); } - if (!Spec.NewHeader.empty()) { + if (!Context->Spec.NewHeader.empty()) { std::string OldHeaderInclude = - Spec.NewDependOnOld ? "#include \"" + Spec.OldHeader + "\"\n" : ""; - FileToReplacements[Spec.NewHeader] = createInsertedReplacements( - HeaderIncludes, NewHeaderDecls, Spec.NewHeader, /*IsHeader=*/true, - OldHeaderInclude); - } - if (!Spec.NewCC.empty()) - FileToReplacements[Spec.NewCC] = - createInsertedReplacements(CCIncludes, NewCCDecls, Spec.NewCC); + Context->Spec.NewDependOnOld + ? "#include \"" + Context->Spec.OldHeader + "\"\n" + : ""; + Context->FileToReplacements[Context->Spec.NewHeader] = + createInsertedReplacements(HeaderIncludes, NewHeaderDecls, + Context->Spec.NewHeader, /*IsHeader=*/true, + OldHeaderInclude); + } + if (!Context->Spec.NewCC.empty()) + Context->FileToReplacements[Context->Spec.NewCC] = + createInsertedReplacements(CCIncludes, NewCCDecls, Context->Spec.NewCC); } // Move all contents from OldFile to NewFile. @@ -669,7 +677,8 @@ clang::tooling::Replacement RemoveAll ( SM, clang::CharSourceRange::getCharRange(Begin, End), ""); std::string FilePath = RemoveAll.getFilePath().str(); - FileToReplacements[FilePath] = clang::tooling::Replacements(RemoveAll); + Context->FileToReplacements[FilePath] = + clang::tooling::Replacements(RemoveAll); StringRef Code = SM.getBufferData(ID); if (!NewFile.empty()) { @@ -677,22 +686,36 @@ clang::tooling::Replacement(NewFile, 0, 0, Code)); // If we are moving from old.cc, an extra step is required: excluding // the #include of "old.h", instead, we replace it with #include of "new.h". - if (Spec.NewCC == NewFile && OldHeaderIncludeRange.isValid()) { + if (Context->Spec.NewCC == NewFile && OldHeaderIncludeRange.isValid()) { AllCode = AllCode.merge( clang::tooling::Replacements(clang::tooling::Replacement( - SM, OldHeaderIncludeRange, '"' + Spec.NewHeader + '"'))); + SM, OldHeaderIncludeRange, '"' + Context->Spec.NewHeader + '"'))); } - FileToReplacements[NewFile] = std::move(AllCode); + Context->FileToReplacements[NewFile] = std::move(AllCode); } } void ClangMoveTool::onEndOfTranslationUnit() { + if (Context->DumpDeclarations) { + assert(Reporter); + for (const auto *Decl : UnremovedDeclsInOldHeader) { + auto Kind = Decl->getKind(); + const std::string QualifiedName = Decl->getQualifiedNameAsString(); + if (Kind == Decl::Kind::Function || Kind == Decl::Kind::FunctionTemplate) + Reporter->reportDeclaration(QualifiedName, "Function"); + else if (Kind == Decl::Kind::ClassTemplate || + Kind == Decl::Kind::CXXRecord) + Reporter->reportDeclaration(QualifiedName, "Class"); + } + return; + } + if (RemovedDecls.empty()) return; - if (UnremovedDeclsInOldHeader.empty() && !Spec.OldHeader.empty()) { + if (UnremovedDeclsInOldHeader.empty() && !Context->Spec.OldHeader.empty()) { auto &SM = *RemovedDecls[0].SM; - moveAll(SM, Spec.OldHeader, Spec.NewHeader); - moveAll(SM, Spec.OldCC, Spec.NewCC); + moveAll(SM, Context->Spec.OldHeader, Context->Spec.NewHeader); + moveAll(SM, Context->Spec.OldCC, Context->Spec.NewCC); return; } removeClassDefinitionInOldFiles(); Index: clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp =================================================================== --- clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp +++ clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp @@ -38,7 +38,7 @@ cl::OptionCategory ClangMoveCategory("clang-move options"); -cl::list Names("names", cl::CommaSeparated, cl::OneOrMore, +cl::list Names("names", cl::CommaSeparated, cl::desc("The list of the names of classes being " "moved, e.g. \"Foo,a::Foo,b::Foo\"."), cl::cat(ClangMoveCategory)); @@ -84,6 +84,13 @@ cl::desc("Dump results in JSON format to stdout."), cl::cat(ClangMoveCategory)); +cl::opt DumpDecls( + "dump_decls", + cl::desc("Dump all declarations in old header (JSON format) to stdout. If " + "the option is specified, other command options will be ignored. " + "An empty JSON will be returned if old header isn't specified."), + cl::cat(ClangMoveCategory)); + } // namespace int main(int argc, const char **argv) { @@ -110,7 +117,7 @@ tooling::RefactoringTool Tool(OptionsParser.getCompilations(), OptionsParser.getSourcePathList()); - move::ClangMoveTool::MoveDefinitionSpec Spec; + move::MoveDefinitionSpec Spec; Spec.Names = {Names.begin(), Names.end()}; Spec.OldHeader = OldHeader; Spec.NewHeader = NewHeader; @@ -124,13 +131,34 @@ llvm::report_fatal_error("Cannot detect current path: " + Twine(EC.message())); + move::ClangMoveContext Context{Spec, Tool.getReplacements(), + InitialDirectory.str(), Style, DumpDecls}; + move::DeclarationReporter Reporter; auto Factory = llvm::make_unique( - Spec, Tool.getReplacements(), InitialDirectory.str(), Style); + &Context, &Reporter); int CodeStatus = Tool.run(Factory.get()); if (CodeStatus) return CodeStatus; + if (DumpDecls) { + llvm::outs() << "[\n"; + const auto &Declarations = Reporter.getDeclarationList(); + for (auto DeclPair : Declarations) { + llvm::outs() << " {\n"; + llvm::outs() << " \"DeclarationName\": \"" << DeclPair.first + << "\",\n"; + llvm::outs() << " \"DeclarationType\": \"" << DeclPair.second + << "\"\n"; + llvm::outs() << " }"; + // Don't print trailing "," at the end of last element. + if (DeclPair != *(--Declarations.end())) + llvm::outs() << ",\n"; + } + llvm::outs() << "\n]\n"; + return 0; + } + if (!NewCC.empty()) { std::error_code EC = CreateNewFile(NewCC); if (EC) { Index: clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp =================================================================== --- clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp +++ clang-tools-extra/trunk/unittests/clang-move/ClangMoveTests.cpp @@ -180,9 +180,10 @@ "} // namespace a\n"; std::map -runClangMoveOnCode(const move::ClangMoveTool::MoveDefinitionSpec &Spec, +runClangMoveOnCode(const move::MoveDefinitionSpec &Spec, const char *const Header = TestHeader, - const char *const CC = TestCC) { + const char *const CC = TestCC, + DeclarationReporter *const Reporter = nullptr) { clang::RewriterTestContext Context; std::map FileToFileID; @@ -205,8 +206,12 @@ std::error_code EC = llvm::sys::fs::current_path(InitialDirectory); assert(!EC); (void)EC; + ClangMoveContext MoveContext = {Spec, FileToReplacements, + InitialDirectory.str(), "LLVM", + Reporter != nullptr}; + auto Factory = llvm::make_unique( - Spec, FileToReplacements, InitialDirectory.str(), "LLVM"); + &MoveContext, Reporter); tooling::runToolOnCodeWithArgs( Factory->create(), CC, {"-std=c++11", "-fparse-all-comments"}, @@ -223,7 +228,7 @@ } TEST(ClangMove, MoveHeaderAndCC) { - move::ClangMoveTool::MoveDefinitionSpec Spec; + move::MoveDefinitionSpec Spec; Spec.Names = {std::string("a::b::Foo")}; Spec.OldHeader = "foo.h"; Spec.OldCC = "foo.cc"; @@ -238,7 +243,7 @@ } TEST(ClangMove, MoveHeaderOnly) { - move::ClangMoveTool::MoveDefinitionSpec Spec; + move::MoveDefinitionSpec Spec; Spec.Names = {std::string("a::b::Foo")}; Spec.OldHeader = "foo.h"; Spec.NewHeader = "new_foo.h"; @@ -249,7 +254,7 @@ } TEST(ClangMove, MoveCCOnly) { - move::ClangMoveTool::MoveDefinitionSpec Spec; + move::MoveDefinitionSpec Spec; Spec.Names = {std::string("a::b::Foo")}; Spec.OldCC = "foo.cc"; Spec.NewCC = "new_foo.cc"; @@ -261,7 +266,7 @@ } TEST(ClangMove, MoveNonExistClass) { - move::ClangMoveTool::MoveDefinitionSpec Spec; + move::MoveDefinitionSpec Spec; Spec.Names = {std::string("NonExistFoo")}; Spec.OldHeader = "foo.h"; Spec.OldCC = "foo.cc"; @@ -282,7 +287,7 @@ "namespace a {}\nusing namespace a;\nclass A {\npublic:\n int f();\n};", }; const char Code[] = "#include \"foo.h\"\nint A::f() { return 0; }"; - move::ClangMoveTool::MoveDefinitionSpec Spec; + move::MoveDefinitionSpec Spec; Spec.Names.push_back("A"); Spec.OldHeader = "foo.h"; Spec.OldCC = "foo.cc"; @@ -297,7 +302,7 @@ } TEST(ClangMove, MoveAllMultipleClasses) { - move::ClangMoveTool::MoveDefinitionSpec Spec; + move::MoveDefinitionSpec Spec; std::vector TestHeaders = { "class C;\nclass A {\npublic:\n int f();\n};\nclass B {};", "class C;\nclass B;\nclass A {\npublic:\n int f();\n};\nclass B {};", @@ -331,7 +336,7 @@ "void f() {};\nclass A {\npublic:\n int f();\n};\n", "enum Color { RED };\nclass A {\npublic:\n int f();\n};\n", }; - move::ClangMoveTool::MoveDefinitionSpec Spec; + move::MoveDefinitionSpec Spec; Spec.Names.push_back("A"); Spec.OldHeader = "foo.h"; Spec.OldCC = "foo.cc"; @@ -354,7 +359,7 @@ "INT A::f() { return 0; }\n"; const char ExpectedNewCode[] = "#include \"new_foo.h\"\n\n" "INT A::f() { return 0; }\n"; - move::ClangMoveTool::MoveDefinitionSpec Spec; + move::MoveDefinitionSpec Spec; Spec.Names.push_back("A"); Spec.OldHeader = "foo.h"; Spec.OldCC = "foo.cc"; @@ -407,7 +412,7 @@ "\n" "#endif // NEW_FOO_H\n"; const std::string ExpectedNewCC = "#include \"new_foo.h\"\n" + CommonCode; - move::ClangMoveTool::MoveDefinitionSpec Spec; + move::MoveDefinitionSpec Spec; Spec.Names.push_back("a::b::c::A"); Spec.Names.push_back("a::d::e::B"); Spec.OldHeader = "foo.h"; @@ -430,7 +435,7 @@ "class A {};\n" "\n" "#endif // NEW_FOO_H\n"; - move::ClangMoveTool::MoveDefinitionSpec Spec; + move::MoveDefinitionSpec Spec; Spec.Names.push_back("A"); Spec.OldHeader = "foo.h"; Spec.OldCC = "foo.cc"; @@ -455,7 +460,7 @@ "\n" "#endif // NEW_FOO_H\n"; const char ExpectedOldHeader[] = "class A {};\n"; - move::ClangMoveTool::MoveDefinitionSpec Spec; + move::MoveDefinitionSpec Spec; Spec.Names.push_back("B"); Spec.OldHeader = "foo.h"; Spec.OldCC = "foo.cc"; @@ -467,6 +472,64 @@ EXPECT_EQ(ExpectedOldHeader, Results[Spec.OldHeader]); } +TEST(ClangMove, DumpDecls) { + const char TestHeader[] = "template \n" + "class A {\n" + " public:\n" + " void f();\n" + " template void h();\n" + " static int b;\n" + "};\n" + "\n" + "template void A::f() {}\n" + "\n" + "template \n" + "template \n" + "void A::h() {}\n" + "\n" + "template int A::b = 2;\n" + "\n" + "template <> class A {};\n" + "\n" + "class B {};\n" + "\n" + "namespace a {\n" + "class Move1 {};\n" + "void f1() {}\n" + "void f2();\n" + "} // namespace a\n" + "\n" + "namespace a {\n" + "namespace b {\n" + "class Move1 { public : void f(); };\n" + "void f() {}\n" + "} // namespace b\n" + "} // namespace a\n"; + const char TestCode[] = "#include \"foo.h\"\n"; + move::MoveDefinitionSpec Spec; + Spec.Names.push_back("B"); + Spec.OldHeader = "foo.h"; + Spec.OldCC = "foo.cc"; + Spec.NewHeader = "new_foo.h"; + Spec.NewCC = "new_foo.cc"; + DeclarationReporter Reporter; + std::vector ExpectedDeclarations = { + {"A", "Class"}, {"B", "Class"}, {"a::Move1", "Class"}, + {"a::f1", "Function"}, {"a::f2", "Function"}, {"a::b::Move1", "Class"}, + {"a::b::f", "Function"}}; + runClangMoveOnCode(Spec, TestHeader, TestCode, &Reporter); + const auto& Results = Reporter.getDeclarationList(); + auto ActualDeclIter = Results.begin(); + auto ExpectedDeclIter = ExpectedDeclarations.begin(); + while (ActualDeclIter != Results.end() && ExpectedDeclIter != Results.end()) { + EXPECT_EQ(*ActualDeclIter, *ExpectedDeclIter); + ++ActualDeclIter; + ++ExpectedDeclIter; + } + ASSERT_TRUE(ActualDeclIter == Results.end()); + ASSERT_TRUE(ExpectedDeclIter == ExpectedDeclarations.end()); +} + } // namespace } // namespce move } // namespace clang