diff --git a/clang-tools-extra/clang-tidy/performance/AvoidEndlCheck.cpp b/clang-tools-extra/clang-tidy/performance/AvoidEndlCheck.cpp new file mode 100644 index 0000000000000..8ecaa41754fb2 --- /dev/null +++ b/clang-tools-extra/clang-tidy/performance/AvoidEndlCheck.cpp @@ -0,0 +1,84 @@ +//===--- AvoidEndlCheck.cpp - clang-tidy ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "AvoidEndlCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Expr.h" +#include "clang/AST/ExprCXX.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "clang/Lex/Lexer.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::performance { + +void AvoidEndlCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + callExpr( + unless(isExpansionInSystemHeader()), + anyOf(cxxOperatorCallExpr( + hasOverloadedOperatorName("<<"), + hasRHS(declRefExpr(to(namedDecl(hasName("::std::endl")))) + .bind("expr"))), + callExpr(argumentCountIs(1), + callee(functionDecl(hasName("::std::endl")))) + .bind("expr"))), + this); +} + +void AvoidEndlCheck::check(const MatchFinder::MatchResult &Result) { + const auto *Expression = Result.Nodes.getNodeAs("expr"); + assert(Expression); + assert(isa(Expression) || isa(Expression)); + + // FIXME: It would be great if we could transform + // 'std::cout << "Hi" << std::endl;' into + // 'std::cout << "Hi\n"'; + + if (llvm::isa(Expression)) { + // Handle the more common streaming '... << std::endl' case + const CharSourceRange TokenRange = + CharSourceRange::getTokenRange(Expression->getSourceRange()); + const StringRef SourceText = Lexer::getSourceText( + TokenRange, *Result.SourceManager, Result.Context->getLangOpts()); + + auto Diag = diag(Expression->getBeginLoc(), + "do not use '%0' with streams; use '\\n' instead") + << SourceText; + + Diag << FixItHint::CreateReplacement(TokenRange, "'\\n'"); + } else { + // Handle the less common function call 'std::endl(...)' case + const auto *CallExpression = llvm::cast(Expression); + assert(CallExpression->getNumArgs() == 1); + + const StringRef SourceText = Lexer::getSourceText( + CharSourceRange::getTokenRange( + CallExpression->getCallee()->getSourceRange()), + *Result.SourceManager, Result.Context->getLangOpts()); + + const CharSourceRange ArgTokenRange = CharSourceRange::getTokenRange( + CallExpression->getArg(0)->getSourceRange()); + const StringRef ArgSourceText = Lexer::getSourceText( + ArgTokenRange, *Result.SourceManager, Result.Context->getLangOpts()); + + const std::string ReplacementString = + std::string(ArgSourceText) + " << '\\n'"; + + diag(CallExpression->getBeginLoc(), + "do not use '%0' with streams; use '\\n' instead") + << SourceText + << FixItHint::CreateReplacement( + CharSourceRange::getTokenRange(CallExpression->getSourceRange()), + ReplacementString); + } +} + +} // namespace clang::tidy::performance diff --git a/clang-tools-extra/clang-tidy/performance/AvoidEndlCheck.h b/clang-tools-extra/clang-tidy/performance/AvoidEndlCheck.h new file mode 100644 index 0000000000000..db75fbcf4e89f --- /dev/null +++ b/clang-tools-extra/clang-tidy/performance/AvoidEndlCheck.h @@ -0,0 +1,40 @@ +//===--- AvoidEndlCheck.h - clang-tidy --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_AVOIDENDLCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_AVOIDENDLCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::performance { + +/// ClangTidyCheck Checks to flag for uses of 'std::endl' on streams and +/// suggests using the newline character '"\n"' instead. +/// +/// For the user-facing documentation see: +/// https://clang.llvm.org/extra/clang-tidy/checks/performance/avoid-endl.html +class AvoidEndlCheck : public ClangTidyCheck { +public: + AvoidEndlCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } + + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + + std::optional getCheckTraversalKind() const override { + return TK_IgnoreUnlessSpelledInSource; + } +}; + +} // namespace clang::tidy::performance + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_AVOIDENDLCHECK_H diff --git a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt index 3153646416927..f6676bcf4be43 100644 --- a/clang-tools-extra/clang-tidy/performance/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/performance/CMakeLists.txt @@ -4,6 +4,7 @@ set(LLVM_LINK_COMPONENTS ) add_clang_library(clangTidyPerformanceModule + AvoidEndlCheck.cpp FasterStringFindCheck.cpp ForRangeCopyCheck.cpp ImplicitConversionInLoopCheck.cpp diff --git a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp index 30a195f76b4ec..b5151a1cc8939 100644 --- a/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp @@ -9,6 +9,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "AvoidEndlCheck.h" #include "FasterStringFindCheck.h" #include "ForRangeCopyCheck.h" #include "ImplicitConversionInLoopCheck.h" @@ -31,6 +32,7 @@ namespace performance { class PerformanceModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck("performance-avoid-endl"); CheckFactories.registerCheck( "performance-faster-string-find"); CheckFactories.registerCheck( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 55c3416235952..49f880c971a34 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -150,6 +150,11 @@ New checks Converts standard library type traits of the form ``traits<...>::type`` and ``traits<...>::value`` into ``traits_t<...>`` and ``traits_v<...>`` respectively. +- New :doc:`performance-avoid-endl + ` check. + + Finds uses of ``std::endl`` on streams and replaces them with ``'\n'``. + - New :doc:`readability-avoid-unconditional-preprocessor-if ` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index be0d32e65a7f6..3ddd257e70de6 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -314,6 +314,7 @@ Clang-Tidy Checks `objc-super-self `_, "Yes" `openmp-exception-escape `_, `openmp-use-default-none `_, + `performance-avoid-endl `_, "Yes" `performance-faster-string-find `_, "Yes" `performance-for-range-copy `_, "Yes" `performance-implicit-conversion-in-loop `_, diff --git a/clang-tools-extra/docs/clang-tidy/checks/performance/avoid-endl.rst b/clang-tools-extra/docs/clang-tidy/checks/performance/avoid-endl.rst new file mode 100644 index 0000000000000..d02bd6312a76b --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/performance/avoid-endl.rst @@ -0,0 +1,56 @@ +.. title:: clang-tidy - performance-avoid-endl + +performance-avoid-endl +============================ + +Checks for uses of ``std::endl`` on streams and suggests using the newline +character ``'\n'`` instead. + +Rationale: +Using ``std::endl`` on streams can be less efficient than using the newline +character ``'\n'`` because ``std::endl`` performs two operations: it writes a +newline character to the output stream and then flushes the stream buffer. +Writing a single newline character using ``'\n'`` does not trigger a flush, +which can improve performance. In addition, flushing the stream buffer can +cause additional overhead when working with streams that are buffered. + +Example: + +Consider the following code: + +.. code-block:: c++ + #include + + int main() { + std::cout << "Hello" << std::endl; + } + +Which gets transformed into: + +.. code-block:: c++ + #include + + int main() { + std::cout << "Hello" << '\n'; + } + +This code writes a single newline character to the ``std::cout`` stream without +flushing the stream buffer. + +Additionally, it is important to note that the standard C++ streams (like +``std::cerr``, ``std::wcerr``, ``std::clog`` and ``std::wclog``) +always flush after a write operation, unless ``std::ios_base::sync_with_stdio`` +is set to ``false``. regardless of whether ``std::endl`` or ``'\n'`` is used. +Therefore, using ``'\n'`` with these streams will not +result in any performance gain, but it is still recommended to use +``'\n'`` for consistency and readability. + +If you do need to flush the stream buffer, you can use ``std::flush`` +explicitly like this: + +.. code-block:: c++ + #include + + int main() { + std::cout << "Hello\n" << std::flush; + } diff --git a/clang-tools-extra/test/clang-tidy/checkers/performance/avoid-endl.cpp b/clang-tools-extra/test/clang-tidy/checkers/performance/avoid-endl.cpp new file mode 100644 index 0000000000000..462b88773d231 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/performance/avoid-endl.cpp @@ -0,0 +1,227 @@ +// RUN: %check_clang_tidy %s performance-avoid-endl %t + +namespace std { + template + class basic_ostream { + public: + template + basic_ostream& operator<<(T); + basic_ostream& operator<<(basic_ostream& (*)(basic_ostream&)); + }; + + template + class basic_iostream : public basic_ostream {}; + + using ostream = basic_ostream; + using wostream = basic_ostream; + + using iostream = basic_iostream; + using wiostream = basic_iostream; + + ostream cout; + wostream wcout; + + ostream cerr; + wostream wcerr; + + ostream clog; + wostream wclog; + + template + basic_ostream& endl(basic_ostream&); +} // namespace std + +void good() { + std::cout << "Hello" << '\n'; + std::cout << "World\n"; + + std::wcout << "Hello" << '\n'; + std::wcout << "World\n"; + + std::cerr << "Hello" << '\n'; + std::cerr << "World\n"; + + std::wcerr << "Hello" << '\n'; + std::wcerr << "World\n"; + + std::clog << "Hello" << '\n'; + std::clog << "World\n"; + + std::wclog << "Hello" << '\n'; + std::wclog << "World\n"; +} + +void bad() { + std::cout << "World" << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::cout << "World" << '\n'; + std::wcout << "World" << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::wcout << "World" << '\n'; + std::cerr << "World" << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::cerr << "World" << '\n'; + std::wcerr << "World" << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::wcerr << "World" << '\n'; + std::clog << "World" << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::clog << "World" << '\n'; + std::wclog << "World" << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::wclog << "World" << '\n'; +} + +void bad_single_argument() { + std::cout << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::cout << '\n'; + std::wcout << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::wcout << '\n'; + std::cerr << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::cerr << '\n'; + std::wcerr << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::wcerr << '\n'; + std::clog << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::clog << '\n'; + std::wclog << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::wclog << '\n'; +} + +void bad_multiple() { + std::cout << "Hello" << std::endl << "World" << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-MESSAGES: :[[@LINE-2]]:51: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::cout << "Hello" << '\n' << "World" << '\n'; + std::wcout << "Hello" << std::endl << "World" << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-MESSAGES: :[[@LINE-2]]:52: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::wcout << "Hello" << '\n' << "World" << '\n'; + std::cerr << "Hello" << std::endl << "World" << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-MESSAGES: :[[@LINE-2]]:51: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::cerr << "Hello" << '\n' << "World" << '\n'; + std::wcerr << "Hello" << std::endl << "World" << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-MESSAGES: :[[@LINE-2]]:52: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::wcerr << "Hello" << '\n' << "World" << '\n'; + std::clog << "Hello" << std::endl << "World" << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-MESSAGES: :[[@LINE-2]]:51: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::clog << "Hello" << '\n' << "World" << '\n'; + std::wclog << "Hello" << std::endl << "World" << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-MESSAGES: :[[@LINE-2]]:52: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::wclog << "Hello" << '\n' << "World" << '\n'; +} + +void bad_function_call() { + std::endl(std::cout); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::cout << '\n'; + std::endl(std::cout << "Hi"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::cout << "Hi" << '\n'; + std::endl(std::wcout); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::wcout << '\n'; + std::endl(std::wcout << "Hi"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::wcout << "Hi" << '\n'; + std::endl(std::cerr); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::cerr << '\n'; + std::endl(std::cerr << "Hi"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::cerr << "Hi" << '\n'; + std::endl(std::wcerr); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::wcerr << '\n'; + std::endl(std::wcerr << "Hi"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::wcerr << "Hi" << '\n'; + std::endl(std::clog); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::clog << '\n'; + std::endl(std::clog << "Hi"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::clog << "Hi" << '\n'; + std::endl(std::wclog); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::wclog << '\n'; + std::endl(std::wclog << "Hi"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: std::wclog << "Hi" << '\n'; +} + +void bad_user_stream() { + std::iostream my_iostream; + std::wiostream my_wiostream; + std::ostream my_ostream; + std::wostream my_wostream; + + my_iostream << "Hi" << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: my_iostream << "Hi" << '\n'; + my_wiostream << "Hi" << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: my_wiostream << "Hi" << '\n'; + my_ostream << "Hi" << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: my_ostream << "Hi" << '\n'; + my_wostream << "Hi" << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: my_wostream << "Hi" << '\n'; + + std::endl(my_iostream); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: my_iostream << '\n'; + std::endl(my_wiostream); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: my_wiostream << '\n'; + std::endl(my_ostream); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: my_ostream << '\n'; + std::endl(my_wostream); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: my_wostream << '\n'; +} + +using namespace std; +void bad_using_namespace_std() { + cout << "Hello" << endl; + // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: cout << "Hello" << '\n'; + endl(cout); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: cout << '\n'; +} + +namespace my_prefix = std; +void bad_using_user_namespace() { + my_prefix::cout << "Hello" << my_prefix::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: do not use 'my_prefix::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: my_prefix::cout << "Hello" << '\n'; + my_prefix::endl(my_prefix::cout); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: do not use 'my_prefix::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: my_prefix::cout << '\n'; +} + +struct CustomLogger { + template + std::ostream& operator<<(T); + std::ostream& operator<<(std::ostream& (*)(std::ostream&)); +}; + +void bad_custom_stream() { + CustomLogger logger; + + logger << std::endl; + // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl] + // CHECK-FIXES: logger << '\n'; +}