Author: Adrian Vogelsgesang Date: 2026-01-16T19:53:03+01:00 New Revision: 0ee7accf6610325c94cec5270b42f4160a4116fc
URL: https://github.com/llvm/llvm-project/commit/0ee7accf6610325c94cec5270b42f4160a4116fc DIFF: https://github.com/llvm/llvm-project/commit/0ee7accf6610325c94cec5270b42f4160a4116fc.diff LOG: [clangd] Support `=default` in DefineOutline to find insertion point (#175618) Since #128164, the DefineOutline tweak is looking for a good insertion point by looking at where neighboring functions are defined. That heuristic didn't yet handle `= default`. This commit adds support for it. Added: Modified: clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp Removed: ################################################################################ diff --git a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp index 45e7adeeefcd9..761ab013374ef 100644 --- a/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp +++ b/clang-tools-extra/clangd/refactor/tweaks/DefineOutline.cpp @@ -671,6 +671,27 @@ class DefineOutline : public Tweak { return {}; } + // Helper function to skip over a matching pair of tokens (e.g., parentheses + // or braces). Returns an iterator to the matching closing token, or the end + // iterator if no matching pair is found. + template <typename Iterator> + Iterator skipTokenPair(Iterator Begin, Iterator End, tok::TokenKind StartKind, + tok::TokenKind EndKind) { + int Count = 0; + for (auto It = Begin; It != End; ++It) { + if (It->kind() == StartKind) { + ++Count; + } else if (It->kind() == EndKind) { + if (--Count == 0) + return It; + if (Count < 0) + // We encountered a closing token without a matching opening token. + return End; + } + } + return End; + } + // We don't know the actual start or end of the definition, only the position // of the name. Therefore, we heuristically try to locate the last token // before or in this function, respectively. Adapt as required by user code. @@ -718,34 +739,41 @@ class DefineOutline : public Tweak { InsertBefore(); } else { // Skip over one top-level pair of parentheses (for the parameter list) - // and one pair of curly braces (for the code block). + // and one pair of curly braces (for the code block), or `= default`. // If that fails, insert before the function instead. auto Tokens = syntax::tokenize(syntax::FileRange(SM.getMainFileID(), *StartOffset, Buffer.getBuffer().size()), SM, AST->getLangOpts()); - bool SkippedParams = false; - int OpenParens = 0; - int OpenBraces = 0; std::optional<syntax::Token> Tok; - for (const auto &T : Tokens) { - tok::TokenKind StartKind = SkippedParams ? tok::l_brace : tok::l_paren; - tok::TokenKind EndKind = SkippedParams ? tok::r_brace : tok::r_paren; - int &Count = SkippedParams ? OpenBraces : OpenParens; - if (T.kind() == StartKind) { - ++Count; - } else if (T.kind() == EndKind) { - if (--Count == 0) { - if (SkippedParams) { - Tok = T; - break; + + // Skip parameter list (parentheses) + auto ClosingParen = skipTokenPair(Tokens.begin(), Tokens.end(), + tok::l_paren, tok::r_paren); + if (ClosingParen != Tokens.end()) { + // After the closing paren, check for `= default` + auto AfterParams = std::next(ClosingParen); + if (AfterParams != Tokens.end() && AfterParams->kind() == tok::equal) { + auto NextIt = std::next(AfterParams); + if (NextIt != Tokens.end() && NextIt->kind() == tok::kw_default) { + // Find the semicolon after `default`. + auto SemiIt = std::next(NextIt); + if (SemiIt != Tokens.end() && SemiIt->kind() == tok::semi) { + Tok = *SemiIt; } - SkippedParams = true; - } else if (Count < 0) { - break; + } + } + + // If not `= default`, skip function body (braces) + if (!Tok && AfterParams != Tokens.end()) { + auto ClosingBrace = skipTokenPair(AfterParams, Tokens.end(), + tok::l_brace, tok::r_brace); + if (ClosingBrace != Tokens.end()) { + Tok = *ClosingBrace; } } } + if (Tok) InsertionLoc = Tok->endLocation(); else diff --git a/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp b/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp index 7689bf3181a5f..df7d251afc3e4 100644 --- a/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp +++ b/clang-tools-extra/clangd/unittests/tweaks/DefineOutlineTests.cpp @@ -950,6 +950,37 @@ inline void Foo::neighbor() {} )cpp", {}}, + // Adjacent definition with `= default` + { + R"cpp( +struct Foo { + void ignored1(); + Foo(); + void fun^c() {} + void ignored2(); +}; +)cpp", + R"cpp( +#include "a.hpp" +void Foo::ignored1() {} +Foo::Foo() = default; +void Foo::ignored2() {} +)cpp", + R"cpp( +struct Foo { + void ignored1(); + Foo(); + void func() ; + void ignored2(); +}; +)cpp", + R"cpp( +#include "a.hpp" +void Foo::ignored1() {} +Foo::Foo() = default;void Foo::func() {} + +void Foo::ignored2() {} +)cpp"}, }; for (const auto &Case : Cases) { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
