Author: Owen Pan Date: 2024-02-20T21:51:51-08:00 New Revision: 04fbc461e0fd1c6f2b014761e9c03ca80d17b33b
URL: https://github.com/llvm/llvm-project/commit/04fbc461e0fd1c6f2b014761e9c03ca80d17b33b DIFF: https://github.com/llvm/llvm-project/commit/04fbc461e0fd1c6f2b014761e9c03ca80d17b33b.diff LOG: [clang-format] Fix RemoveSemicolon for empty functions (#82278) Fixes #79833. Added: Modified: clang/lib/Format/Format.cpp clang/unittests/Format/FormatTest.cpp Removed: ################################################################################ diff --git a/clang/lib/Format/Format.cpp b/clang/lib/Format/Format.cpp index 2c815128b1a59d..10ab406a15c6e1 100644 --- a/clang/lib/Format/Format.cpp +++ b/clang/lib/Format/Format.cpp @@ -2261,27 +2261,36 @@ class SemiRemover : public TokenAnalyzer { FormatTokenLexer &Tokens) override { AffectedRangeMgr.computeAffectedLines(AnnotatedLines); tooling::Replacements Result; - removeSemi(AnnotatedLines, Result); + removeSemi(Annotator, AnnotatedLines, Result); return {Result, 0}; } private: - void removeSemi(SmallVectorImpl<AnnotatedLine *> &Lines, + void removeSemi(TokenAnnotator &Annotator, + SmallVectorImpl<AnnotatedLine *> &Lines, tooling::Replacements &Result) { + auto PrecededByFunctionRBrace = [](const FormatToken &Tok) { + const auto *Prev = Tok.Previous; + if (!Prev || Prev->isNot(tok::r_brace)) + return false; + const auto *LBrace = Prev->MatchingParen; + return LBrace && LBrace->is(TT_FunctionLBrace); + }; const auto &SourceMgr = Env.getSourceManager(); const auto End = Lines.end(); for (auto I = Lines.begin(); I != End; ++I) { const auto Line = *I; - removeSemi(Line->Children, Result); + removeSemi(Annotator, Line->Children, Result); if (!Line->Affected) continue; + Annotator.calculateFormattingInformation(*Line); const auto NextLine = I + 1 == End ? nullptr : I[1]; for (auto Token = Line->First; Token && !Token->Finalized; Token = Token->Next) { - if (!Token->Optional) - continue; - if (Token->isNot(tok::semi)) + if (Token->isNot(tok::semi) || + (!Token->Optional && !PrecededByFunctionRBrace(*Token))) { continue; + } auto Next = Token->Next; assert(Next || Token == Line->Last); if (!Next && NextLine) @@ -3677,7 +3686,7 @@ reformat(const FormatStyle &Style, StringRef Code, FormatStyle S = Expanded; S.RemoveSemicolon = true; Passes.emplace_back([&, S = std::move(S)](const Environment &Env) { - return SemiRemover(Env, S).process(/*SkipAnnotation=*/true); + return SemiRemover(Env, S).process(); }); } diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index 24f62af8ddcb87..8282e75bd847f4 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -26720,13 +26720,20 @@ TEST_F(FormatTest, RemoveSemicolon) { verifyIncompleteFormat("class C final [[deprecated(l]] {});", Style); - // These tests are here to show a problem that may not be easily - // solved, our implementation to remove semicolons is only as good - // as our FunctionLBrace detection and this fails for empty braces - // because we can't distringuish this from a bracelist. - // We will enable when that is resolved. -#if 0 verifyFormat("void main() {}", "void main() {};", Style); + + verifyFormat("struct Foo {\n" + " Foo() {}\n" + " ~Foo() {}\n" + "};", + "struct Foo {\n" + " Foo() {};\n" + " ~Foo() {};\n" + "};", + Style); + +// We can't (and probably shouldn't) support the following. +#if 0 verifyFormat("void foo() {} //\n" "int bar;", "void foo() {}; //\n" _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits