diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp --- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp @@ -29,6 +29,7 @@ #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.h" #include "llvm/Support/Error.h" +#include "llvm/Support/raw_ostream.h" #include #include @@ -132,8 +133,9 @@ // inside a macro body. if (Ref.Qualifier || Ref.Targets.empty() || Ref.NameLoc.isMacroID()) return; - // Qualify return type - if (Ref.NameLoc != FD->getReturnTypeSourceRange().getBegin()) + // Only qualify return type and function name. + if (Ref.NameLoc != FD->getReturnTypeSourceRange().getBegin() && + Ref.NameLoc != FD->getLocation()) return; for (const NamedDecl *ND : Ref.Targets) { @@ -178,8 +180,6 @@ if (!QualifiedFunc) return QualifiedFunc.takeError(); return QualifiedFunc->substr(FuncBegin, FuncEnd - FuncBegin + 1); - - // FIXME: Qualify function name depending on the target context. } struct InsertionPoint { @@ -276,6 +276,7 @@ return llvm::createStringError(Buffer.getError(), Buffer.getError().message()); auto Contents = Buffer->get()->getBuffer(); + llvm::errs() << "Got file: " << Contents << '\n'; auto InsertionPoint = getInsertionPoint(Contents, Source->getQualifiedNameAsString(), getFormatStyleForFile(*CCFile, Contents, &FS)); @@ -285,9 +286,7 @@ auto FuncDef = getFunctionSourceCode(Source, InsertionPoint->EnclosingNamespace); if (!FuncDef) - return llvm::createStringError( - llvm::inconvertibleErrorCode(), - "Couldn't get full source for function definition."); + return FuncDef.takeError(); SourceManagerForFile SMFF(*CCFile, Contents); const tooling::Replacement InsertFunctionDef( diff --git a/clang-tools-extra/clangd/unittests/TweakTests.cpp b/clang-tools-extra/clangd/unittests/TweakTests.cpp --- a/clang-tools-extra/clangd/unittests/TweakTests.cpp +++ b/clang-tools-extra/clangd/unittests/TweakTests.cpp @@ -1807,7 +1807,7 @@ Bar foo() ; } })cpp", - "a::Foo::Bar foo() { return {}; }\n"}, + "a::Foo::Bar a::Foo::foo() { return {}; }\n"}, {R"cpp( class Foo; Foo fo^o() { return; })cpp", @@ -1825,6 +1825,50 @@ } } +TEST_F(DefineOutlineTest, QualifyFunctionName) { + FileName = "Test.hpp"; + struct { + llvm::StringRef Test; + llvm::StringRef SourceFile; + llvm::StringRef ExpectedHeader; + llvm::StringRef ExpectedSource; + } Cases[] = { + {R"cpp( + namespace a { + namespace b { + class Foo { + void fo^o() {} + }; + } + })cpp", + "", + R"cpp( + namespace a { + namespace b { + class Foo { + void foo() ; + }; + } + })cpp", + "void a::b::Foo::foo() {}\n"}, + {"namespace a { namespace b { void f^oo() {} } }", "namespace a{}", + "namespace a { namespace b { void foo() ; } }", + "namespace a{void b::foo() {} }"}, + {"namespace a { namespace b { void f^oo() {} } }", "using namespace a;", + "namespace a { namespace b { void foo() ; } }", + // FIXME: Take using namespace directives in the source file into + // account. This can be spelled as b::foo instead. + "using namespace a;void a::b::foo() {} "}, + }; + llvm::StringMap EditedFiles; + for (auto &Case : Cases) { + ExtraFiles["Test.cpp"] = Case.SourceFile; + EXPECT_EQ(apply(Case.Test, &EditedFiles), Case.ExpectedHeader); + EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents( + testPath("Test.cpp"), Case.ExpectedSource))) + << Case.Test; + } +} } // namespace } // namespace clangd } // namespace clang