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 @@ -320,6 +320,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 @@ -390,7 +398,12 @@ Source = getSelectedFunction(Sel.ASTSelection.commonAncestor()); // Bail out if the selection is not a in-line function definition. - if (!Source || !Source->doesThisDeclarationHaveABody() || + // Defaulted destrucors are OK as they sometimes need to be defined out of + // line. + if (!Source || + (!Source->doesThisDeclarationHaveABody() && + (!isa(Source) || + !Source->isExplicitlyDefaulted())) || 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 @@ -325,6 +325,11 @@ "class A { ~A(); };", "A::~A(){} ", }, + { + "class A { ~A^() = default; };", + "class A { ~A() ; };", + "A::~A() = default;", + }, }; for (const auto &Case : Cases) { SCOPED_TRACE(Case.Test);