AMS21 updated this revision to Diff 513878.
AMS21 marked 12 inline comments as done.
AMS21 added a comment.

Implement suggested fixes


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D148318/new/

https://reviews.llvm.org/D148318

Files:
  clang-tools-extra/clang-tidy/performance/AvoidEndlEndsCheck.cpp
  clang-tools-extra/clang-tidy/performance/AvoidEndlEndsCheck.h
  clang-tools-extra/clang-tidy/performance/CMakeLists.txt
  clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
  clang-tools-extra/docs/ReleaseNotes.rst
  clang-tools-extra/docs/clang-tidy/checks/list.rst
  clang-tools-extra/docs/clang-tidy/checks/performance/avoid-endl-ends.rst
  clang-tools-extra/test/clang-tidy/checkers/performance/avoid-endl-ends.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance/avoid-endl-ends.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/test/clang-tidy/checkers/performance/avoid-endl-ends.cpp
@@ -0,0 +1,235 @@
+// RUN: %check_clang_tidy %s performance-avoid-endl-ends %t
+
+namespace std {
+  template <typename CharT>
+  class basic_ostream {
+    public:
+    template <typename T>
+    basic_ostream& operator<<(T);
+    basic_ostream& operator<<(basic_ostream<CharT>& (*)(basic_ostream<CharT>&));
+  };
+
+  template <typename CharT>
+  class basic_iostream : public basic_ostream<CharT> {};
+
+  using ostream = basic_ostream<char>;
+  using wostream = basic_ostream<wchar_t>;
+
+  using iostream = basic_iostream<char>;
+  using wiostream = basic_iostream<wchar_t>;
+
+  ostream cout;
+  wostream wcout;
+
+  ostream cerr;
+  wostream wcerr;
+
+  ostream clog;
+  wostream wclog;
+
+  template<typename CharT>
+  basic_ostream<CharT>& endl(basic_ostream<CharT>&);
+
+  template<typename CharT>
+  basic_ostream<CharT>& ends(basic_ostream<CharT>&);
+} // 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-ends]
+  // 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-ends]
+  // 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-ends]
+  // 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-ends]
+  // 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-ends]
+  // 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-ends]
+  // CHECK-FIXES: std::wclog << "World" << '\n';
+
+  std::cout << "World" << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::cout << "World" << '\n';
+  std::wcout << "World" << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::wcout << "World" << '\n';
+  std::cerr << "World" << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::cerr << "World" << '\n';
+  std::wcerr << "World" << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::wcerr << "World" << '\n';
+  std::clog << "World" << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::clog << "World" << '\n';
+  std::wclog << "World" << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // 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-ends]
+  // 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-ends]
+  // 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-ends]
+  // 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-ends]
+  // 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-ends]
+  // 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-ends]
+  // CHECK-FIXES: std::wclog << '\n';
+
+  std::cout << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::cout << '\n';
+  std::wcout << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::wcout << '\n';
+  std::cerr << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::cerr << '\n';
+  std::wcerr << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::wcerr << '\n';
+  std::clog << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::clog << '\n';
+  std::wclog << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // 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-ends]
+  // CHECK-MESSAGES: :[[@LINE-2]]:51: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // 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-ends]
+  // CHECK-MESSAGES: :[[@LINE-2]]:52: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // 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-ends]
+  // CHECK-MESSAGES: :[[@LINE-2]]:51: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // 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-ends]
+  // CHECK-MESSAGES: :[[@LINE-2]]:52: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // 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-ends]
+  // CHECK-MESSAGES: :[[@LINE-2]]:51: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // 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-ends]
+  // CHECK-MESSAGES: :[[@LINE-2]]:52: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::wclog << "Hello" << '\n' << "World" << '\n';
+
+  std::cout << "Hello" << std::ends << "World" << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-MESSAGES: :[[@LINE-2]]:51: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::cout << "Hello" << '\n' << "World" << '\n';
+  std::wcout << "Hello" << std::ends << "World" << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-MESSAGES: :[[@LINE-2]]:52: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::wcout << "Hello" << '\n' << "World" << '\n';
+  std::cerr << "Hello" << std::ends << "World" << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-MESSAGES: :[[@LINE-2]]:51: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::cerr << "Hello" << '\n' << "World" << '\n';
+  std::wcerr << "Hello" << std::ends << "World" << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-MESSAGES: :[[@LINE-2]]:52: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::wcerr << "Hello" << '\n' << "World" << '\n';
+  std::clog << "Hello" << std::ends << "World" << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-MESSAGES: :[[@LINE-2]]:51: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::clog << "Hello" << '\n' << "World" << '\n';
+  std::wclog << "Hello" << std::ends << "World" << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-MESSAGES: :[[@LINE-2]]:52: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: std::wclog << "Hello" << '\n' << "World" << '\n';
+}
+
+void bad_user_stream() {
+  std::iostream my_stream;
+
+  my_stream << "Hi" << std::endl;
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not use 'std::endl' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: my_stream << "Hi" << '\n';
+  my_stream << "Hi" << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: my_stream << "Hi" << '\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-ends]
+  // CHECK-FIXES: cout << "Hello" << '\n';
+  cout << "Hello" << ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: do not use 'ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: cout << "Hello" << '\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-ends]
+  // CHECK-FIXES: my_prefix::cout << "Hello" << '\n';
+  my_prefix::cout << "Hello" << my_prefix::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:33: warning: do not use 'my_prefix::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: my_prefix::cout << "Hello" << '\n';
+}
+
+struct CustomLogger {
+  template <typename T>
+  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-ends]
+  // CHECK-FIXES: logger << '\n';
+  logger << std::ends;
+  // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: do not use 'std::ends' with streams; use '\n' instead [performance-avoid-endl-ends]
+  // CHECK-FIXES: logger << '\n';
+}
Index: clang-tools-extra/docs/clang-tidy/checks/performance/avoid-endl-ends.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/performance/avoid-endl-ends.rst
@@ -0,0 +1,56 @@
+.. title:: clang-tidy - performance-avoid-endl-ends
+
+performance-avoid-endl-ends-ends+
+============================
+
+Checks for uses of ``std::endl`` and ``std::ends`` 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.
+For consistency and readability we also replace ``std::ends`` although it
+doesn't triggera flush like ``std::endl``.
+
+Example:
+
+Consider the following code:
+
+.. code-block:: c++
+    #include <iostream>
+
+    int main() {
+        std::cout << "Hello" << std::endl;
+    }
+
+Which gets transformed into:
+
+.. code-block:: c++
+    #include <iostream>
+
+    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 ``std::cerr`` and ``std::clog``
+streams always flush after a write operation, 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 <iostream>
+
+    int main() {
+        std::cout << "Hello\n" << std::flush;
+    }
Index: clang-tools-extra/docs/clang-tidy/checks/list.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -313,6 +313,7 @@
    `objc-super-self <objc/super-self.html>`_, "Yes"
    `openmp-exception-escape <openmp/exception-escape.html>`_,
    `openmp-use-default-none <openmp/use-default-none.html>`_,
+   `performance-avoid-endl-ends <performance/avoid-endl-ends.html>`_, "Yes"
    `performance-faster-string-find <performance/faster-string-find.html>`_, "Yes"
    `performance-for-range-copy <performance/for-range-copy.html>`_, "Yes"
    `performance-implicit-conversion-in-loop <performance/implicit-conversion-in-loop.html>`_,
Index: clang-tools-extra/docs/ReleaseNotes.rst
===================================================================
--- clang-tools-extra/docs/ReleaseNotes.rst
+++ clang-tools-extra/docs/ReleaseNotes.rst
@@ -142,6 +142,12 @@
   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-ends
+  <clang-tidy/checks/performance/avoid-endl-ends>` check.
+
+  Finds uses of ``std::endl`` and ``std::ends`` on streams and replaces them
+  with ``'\n'``.
+
 - New :doc:`readability-avoid-unconditional-preprocessor-if
   <clang-tidy/checks/readability/avoid-unconditional-preprocessor-if>` check.
 
Index: clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
+++ clang-tools-extra/clang-tidy/performance/PerformanceTidyModule.cpp
@@ -9,6 +9,7 @@
 #include "../ClangTidy.h"
 #include "../ClangTidyModule.h"
 #include "../ClangTidyModuleRegistry.h"
+#include "AvoidEndlEndsCheck.h"
 #include "FasterStringFindCheck.h"
 #include "ForRangeCopyCheck.h"
 #include "ImplicitConversionInLoopCheck.h"
@@ -31,6 +32,8 @@
 class PerformanceModule : public ClangTidyModule {
 public:
   void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+    CheckFactories.registerCheck<AvoidEndlEndsCheck>(
+        "performance-avoid-endl-ends");
     CheckFactories.registerCheck<FasterStringFindCheck>(
         "performance-faster-string-find");
     CheckFactories.registerCheck<ForRangeCopyCheck>(
Index: clang-tools-extra/clang-tidy/performance/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/performance/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/performance/CMakeLists.txt
@@ -4,6 +4,7 @@
   )
 
 add_clang_library(clangTidyPerformanceModule
+  AvoidEndlEndsCheck.cpp
   FasterStringFindCheck.cpp
   ForRangeCopyCheck.cpp
   ImplicitConversionInLoopCheck.cpp
Index: clang-tools-extra/clang-tidy/performance/AvoidEndlEndsCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/performance/AvoidEndlEndsCheck.h
@@ -0,0 +1,35 @@
+//===--- AvoidEndlEndsCheck.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_AVOIDENDLENDSCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_AVOIDENDLENDSCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::performance {
+
+/// ClangTidyCheck to flag all uses of std::endl on iostreams.
+///
+/// For the user-facing documentation see:
+/// https://clang.llvm.org/extra/clang-tidy/checks/performance/avoid-endl-ends.html
+class AvoidEndlEndsCheck : public ClangTidyCheck {
+public:
+  AvoidEndlEndsCheck(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;
+};
+
+} // namespace clang::tidy::performance
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_AVOIDENDLENDSCHECK_H
Index: clang-tools-extra/clang-tidy/performance/AvoidEndlEndsCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/performance/AvoidEndlEndsCheck.cpp
@@ -0,0 +1,55 @@
+//===--- AvoidEndlEndsCheck.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 "AvoidEndlEndsCheck.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 AvoidEndlEndsCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      cxxOperatorCallExpr(
+          unless(isExpansionInSystemHeader()), hasOverloadedOperatorName("<<"),
+          hasRHS(ignoringImplicit(
+              declRefExpr(
+                  to(namedDecl(hasAnyName("endl", "ends")).bind("decl")))
+                  .bind("expr")))),
+      this);
+}
+
+void AvoidEndlEndsCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Expression = Result.Nodes.getNodeAs<DeclRefExpr>("expr");
+  assert(Expression);
+
+  const auto TokenRange =
+      CharSourceRange::getTokenRange(Expression->getSourceRange());
+  const auto SourceText = Lexer::getSourceText(
+      TokenRange, *Result.SourceManager, Result.Context->getLangOpts());
+
+  const std::string Message =
+      "do not use '" + std::string(SourceText.data(), SourceText.size()) +
+      "' with streams; use '\\n' instead";
+
+  auto Diag = diag(Expression->getBeginLoc(), Message);
+
+  // Add a fix-it hint to replace with '\n'
+  // FIXME: It would be great if we could transform
+  // 'std::cout << "Hi" << std::endl;' into
+  // 'std::cout << "Hi\n"';
+  Diag << FixItHint::CreateReplacement(TokenRange, "'\\n'");
+}
+
+} // namespace clang::tidy::performance
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to