Index: change-namespace/ChangeNamespace.cpp =================================================================== --- change-namespace/ChangeNamespace.cpp +++ change-namespace/ChangeNamespace.cpp @@ -322,7 +322,7 @@ Finder->addMatcher( typeLoc(IsInMovedNs, loc(qualType(hasDeclaration(DeclMatcher.bind("from_decl")))), - unless(anyOf(hasParent(typeLoc(loc(qualType( + unless(anyOf(hasAncestor(typeLoc(loc(qualType( allOf(hasDeclaration(DeclMatcher), unless(templateSpecializationType())))))), hasParent(nestedNameSpecifierLoc()))), @@ -520,7 +520,13 @@ // Delete the forward declaration from the code to be moved. const auto Deletion = createReplacement(Start, End, "", *Result.SourceManager); - addOrMergeReplacement(Deletion, &FileToReplacements[Deletion.getFilePath()]); + auto Err = FileToReplacements[Deletion.getFilePath()].add(Deletion); + if (Err) { + llvm::errs() << "Failed to add replacements: " << Deletion.toString() + << "\n" + << llvm::toString(std::move(Err)) << "\n"; + assert(false); + } llvm::StringRef Code = Lexer::getSourceText( CharSourceRange::getTokenRange( Result.SourceManager->getSpellingLoc(Start), @@ -606,7 +612,12 @@ if (NestedName == ReplaceName) return; auto R = createReplacement(Start, End, ReplaceName, *Result.SourceManager); - addOrMergeReplacement(R, &FileToReplacements[R.getFilePath()]); + auto Err = FileToReplacements[R.getFilePath()].add(R); + if (Err) { + llvm::errs() << "Failed to add replacements: " << R.toString() << "\n" + << llvm::toString(std::move(Err)) << "\n"; + assert(false); + } } // Replace the [Start, End] of `Type` with the shortest qualified name when the @@ -667,7 +678,12 @@ // Use fully qualified name in UsingDecl for now. auto R = createReplacement(Start, End, "using ::" + TargetDeclName, *Result.SourceManager); - addOrMergeReplacement(R, &FileToReplacements[R.getFilePath()]); + auto Err = FileToReplacements[R.getFilePath()].add(R); + if (Err) { + llvm::errs() << "Failed to add replacements: " << R.toString() << "\n" + << llvm::toString(std::move(Err)) << "\n"; + assert(false); + } } void ChangeNamespaceTool::onEndOfTranslationUnit() { Index: unittests/change-namespace/ChangeNamespaceTests.cpp =================================================================== --- unittests/change-namespace/ChangeNamespaceTests.cpp +++ unittests/change-namespace/ChangeNamespaceTests.cpp @@ -1005,6 +1005,35 @@ EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code)); } +TEST_F(ChangeNamespaceTest, DerivedClassWithConstructors) { + std::string Code = + "namespace nx { namespace ny { class X { public: X(int i) {} }; } }\n" + "namespace na {\n" + "namespace nb {\n" + "class A : public nx::ny::X {\n" + "public:\n" + " A() : X::X(0) {}\n" + " A(int i);\n" + "};\n" + "A::A(int i) : X::X(i) {}\n" + "} // namespace nb\n" + "} // namespace na\n"; + std::string Expected = + "namespace nx { namespace ny { class X { public: X(int i) {} }; } }\n" + "\n\n" + "namespace x {\n" + "namespace y {\n" + "class A : public nx::ny::X {\n" + "public:\n" + " A() : X::X(0) {}\n" + " A(int i);\n" + "};\n" + "A::A(int i) : X::X(i) {}\n" + "} // namespace y\n" + "} // namespace x\n"; + EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code)); +} + } // anonymous namespace } // namespace change_namespace } // namespace clang