summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKadir Cetinkaya <kadircet@google.com>2019-11-22 13:56:02 +0100
committerKadir Cetinkaya <kadircet@google.com>2019-12-04 08:21:09 +0100
commitddcce0f3d665b66a8232a80ca918d349c8485fe4 (patch)
tree67b5a95aff09a4dab967eed40bc287f3d7d8bbf6
parente4609ec0e8cfddf697ffc3eccf9bef6a830bc6f0 (diff)
downloadbcm5719-llvm-ddcce0f3d665b66a8232a80ca918d349c8485fe4.tar.gz
bcm5719-llvm-ddcce0f3d665b66a8232a80ca918d349c8485fe4.zip
[clangd] Define out-of-line qualify function name
Summary: When moving function definitions to a different context, the function name might need a different spelling, for example in the header it might be: ``` namespace a { void foo() {} } ``` And we might want to move it into a context which doesn't have `namespace a` as a parent, then we must re-spell the function name, i.e: ``` void a::foo() {} ``` This patch implements a version of this which ignores using namespace declarations in the source file. Reviewers: hokein Subscribers: ilya-biryukov, MaskRay, jkorous, arphaman, usaxena95, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D70656
-rw-r--r--clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp14
-rw-r--r--clang-tools-extra/clangd/unittests/TweakTests.cpp54
2 files changed, 59 insertions, 9 deletions
diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
index 1bd70b72aa1..6b44edb8cd7 100644
--- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
+++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp
@@ -136,7 +136,6 @@ getFunctionSourceAfterReplacements(const FunctionDecl *FD,
// Contains function signature, body and template parameters if applicable.
// No need to qualify parameters, as they are looked up in the context
// containing the function/method.
-// FIXME: Qualify function name depending on the target context.
llvm::Expected<std::string>
getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace) {
auto &SM = FD->getASTContext().getSourceManager();
@@ -149,16 +148,17 @@ getFunctionSourceCode(const FunctionDecl *FD, llvm::StringRef TargetNamespace) {
llvm::Error Errors = llvm::Error::success();
tooling::Replacements QualifierInsertions;
- // Finds the first unqualified name in function return type and qualifies it
- // to be valid in TargetContext.
+ // Finds the first unqualified name in function return type and name, then
+ // qualifies those to be valid in TargetContext.
findExplicitReferences(FD, [&](ReferenceLoc Ref) {
// It is enough to qualify the first qualifier, so skip references with a
// qualifier. Also we can't do much if there are no targets or name is
// 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) {
@@ -293,9 +293,7 @@ public:
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
index 9710465335d..1149a0e6497 100644
--- a/clang-tools-extra/clangd/unittests/TweakTests.cpp
+++ b/clang-tools-extra/clangd/unittests/TweakTests.cpp
@@ -2004,7 +2004,7 @@ TEST_F(DefineOutlineTest, QualifyReturnValue) {
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",
@@ -2022,6 +2022,58 @@ TEST_F(DefineOutlineTest, QualifyReturnValue) {
}
}
+TEST_F(DefineOutlineTest, QualifyFunctionName) {
+ FileName = "Test.hpp";
+ struct {
+ llvm::StringRef TestHeader;
+ llvm::StringRef TestSource;
+ 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<std::string> EditedFiles;
+ for (auto &Case : Cases) {
+ ExtraFiles["Test.cpp"] = Case.TestSource;
+ EXPECT_EQ(apply(Case.TestHeader, &EditedFiles), Case.ExpectedHeader);
+ EXPECT_THAT(EditedFiles, testing::ElementsAre(FileWithContents(
+ testPath("Test.cpp"), Case.ExpectedSource)))
+ << Case.TestHeader;
+ }
+}
} // namespace
} // namespace clangd
} // namespace clang
OpenPOWER on IntegriCloud