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 @@ -325,6 +325,14 @@ // initializers. SourceRange getDeletionRange(const FunctionDecl *FD, const syntax::TokenBuffer &TokBuf) { + if (FD->isExplicitlyDefaulted()) { + auto Toks = + TokBuf.expandedTokens({FD->getTypeSpecEndLoc(), FD->getDefaultLoc()}); + Toks = Toks.drop_until( + [](const syntax::Token &Tok) { return Tok.kind() == tok::equal; }); + assert(Toks.size() == 2); + return {Toks.front().location(), Toks.back().endLocation()}; + } auto DeletionRange = FD->getBody()->getSourceRange(); if (auto *CD = llvm::dyn_cast(FD)) { // AST doesn't contain the location for ":" in ctor initializers. Therefore @@ -395,7 +403,10 @@ Source = getSelectedFunction(Sel.ASTSelection.commonAncestor()); // Bail out if the selection is not a in-line function definition. - if (!Source || !Source->doesThisDeclarationHaveABody() || + // unless its a not-trivial special member function + if (!Source || + (!Source->doesThisDeclarationHaveABody() && + (!Source->isExplicitlyDefaulted() || Source->isTrivial())) || Source->isOutOfLine()) return false; diff --git a/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp --- a/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp +++ b/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp @@ -110,6 +110,22 @@ }; } // namespace )cpp"); + + // Not available on trivially defaulted functions + EXPECT_UNAVAILABLE(R"cpp( + struct A { A (); }; + struct B { + A a; + B^() = default; + }; + )cpp"); + EXPECT_UNAVAILABLE(R"cpp( + struct A { ~A (); }; + struct B { + A a; + ~B^() = default; + }; + )cpp"); } TEST_F(DefineOutlineTest, FailsWithoutSource) { @@ -325,6 +341,17 @@ "class A { ~A(); };", "A::~A(){} ", }, + // Defaulted Functions + { + "class A { A^() = default; };", + "class A { A() ; };", + "A::A() = default;", + }, + { + "class A { ~A^() = default; };", + "class A { ~A() ; };", + "A::~A() = default;", + }, }; for (const auto &Case : Cases) { SCOPED_TRACE(Case.Test);