AMS21 updated this revision to Diff 514366.
AMS21 added a comment.

Handle the function calling case


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/AvoidEndlCheck.cpp
  clang-tools-extra/clang-tidy/performance/AvoidEndlCheck.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.rst
  clang-tools-extra/test/clang-tidy/checkers/performance/avoid-endl.cpp

Index: clang-tools-extra/test/clang-tidy/checkers/performance/avoid-endl.cpp
===================================================================
--- /dev/null
+++ 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 <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>&);
+} // 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 <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]
+  // CHECK-FIXES: logger << '\n';
+}
Index: clang-tools-extra/docs/clang-tidy/checks/performance/avoid-endl.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/performance/avoid-endl.rst
@@ -0,0 +1,54 @@
+.. 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 <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
@@ -314,6 +314,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 <performance/avoid-endl.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
@@ -150,6 +150,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
+  <clang-tidy/checks/performance/avoid-endl>` 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 "AvoidEndlCheck.h"
 #include "FasterStringFindCheck.h"
 #include "ForRangeCopyCheck.h"
 #include "ImplicitConversionInLoopCheck.h"
@@ -31,6 +32,7 @@
 class PerformanceModule : public ClangTidyModule {
 public:
   void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override {
+    CheckFactories.registerCheck<AvoidEndlCheck>("performance-avoid-endl");
     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
+  AvoidEndlCheck.cpp
   FasterStringFindCheck.cpp
   ForRangeCopyCheck.cpp
   ImplicitConversionInLoopCheck.cpp
Index: clang-tools-extra/clang-tidy/performance/AvoidEndlCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/performance/AvoidEndlCheck.h
@@ -0,0 +1,35 @@
+//===--- 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 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.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;
+};
+
+} // namespace clang::tidy::performance
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_AVOIDENDLCHECK_H
Index: clang-tools-extra/clang-tidy/performance/AvoidEndlCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/performance/AvoidEndlCheck.cpp
@@ -0,0 +1,92 @@
+//===--- 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(
+      cxxOperatorCallExpr(
+          unless(isExpansionInSystemHeader()), hasOverloadedOperatorName("<<"),
+          hasRHS(ignoringImplicit(
+              declRefExpr(to(namedDecl(hasName("endl")).bind("decl")))
+                  .bind("expr")))),
+      this);
+  Finder->addMatcher(callExpr(unless(isExpansionInSystemHeader()),
+                              callee(functionDecl(hasName("endl"))),
+                              argumentCountIs(1))
+                         .bind("expr"),
+                     this);
+}
+
+void AvoidEndlCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Expression = Result.Nodes.getNodeAs<Expr>("expr");
+  assert(Expression);
+  assert(isa<DeclRefExpr>(Expression) || isa<CallExpr>(Expression));
+
+  // FIXME: It would be great if we could transform
+  // 'std::cout << "Hi" << std::endl;' into
+  // 'std::cout << "Hi\n"';
+
+  if (llvm::isa<DeclRefExpr>(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());
+
+    const std::string Message =
+        "do not use '" + std::string(SourceText.data(), SourceText.size()) +
+        "' with streams; use '\\n' instead";
+
+    auto Diag = diag(Expression->getBeginLoc(), Message);
+
+    Diag << FixItHint::CreateReplacement(TokenRange, "'\\n'");
+  } else {
+    // Handle the less common function call 'std::endl(...)' case
+    const auto *CallExpression = llvm::cast<CallExpr>(Expression);
+    assert(CallExpression->getNumArgs() == 1);
+
+    const CharSourceRange CalleeTokenRange = CharSourceRange::getTokenRange(
+        CallExpression->getCallee()->getSourceRange());
+    const StringRef SourceText = Lexer::getSourceText(
+        CalleeTokenRange, *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(CallExpression->getBeginLoc(), Message);
+
+    const SourceRange ArgSourceRange =
+        CallExpression->getArg(0)->getSourceRange();
+    const CharSourceRange ArgTokenRange =
+        CharSourceRange::getTokenRange(ArgSourceRange);
+    const StringRef ArgSourceText = Lexer::getSourceText(
+        ArgTokenRange, *Result.SourceManager, Result.Context->getLangOpts());
+
+    const std::string ReplacementString =
+        std::string(ArgSourceText) + " << '\\n'";
+
+    Diag << FixItHint::CreateReplacement(
+        CharSourceRange::getTokenRange(CallExpression->getSourceRange()),
+        ReplacementString);
+  }
+}
+
+} // 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