[clang-tools-extra] r304570 - [clang-tidy] check for __func__/__FUNCTION__ in lambdas

Alexander Kornienko via cfe-commits cfe-commits at lists.llvm.org
Fri Jun 2 10:36:33 PDT 2017


Author: alexfh
Date: Fri Jun  2 12:36:32 2017
New Revision: 304570

URL: http://llvm.org/viewvc/llvm-project?rev=304570&view=rev
Log:
[clang-tidy] check for __func__/__FUNCTION__ in lambdas

Add a clang-tidy check for using func__/FUNCTION__ inside lambdas. This
evaluates to the string operator(), which is almost never useful and almost
certainly not what the author intended.

Patch by Bryce Liu!

Differential Revision: https://reviews.llvm.org/D33497

Added:
    clang-tools-extra/trunk/clang-tidy/misc/LambdaFunctionNameCheck.cpp
    clang-tools-extra/trunk/clang-tidy/misc/LambdaFunctionNameCheck.h
    clang-tools-extra/trunk/docs/clang-tidy/checks/misc-lambda-function-name.rst
    clang-tools-extra/trunk/test/clang-tidy/misc-lambda-function-name.cpp
Modified:
    clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
    clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp
    clang-tools-extra/trunk/docs/ReleaseNotes.rst
    clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst

Modified: clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt?rev=304570&r1=304569&r2=304570&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-tidy/misc/CMakeLists.txt Fri Jun  2 12:36:32 2017
@@ -4,6 +4,7 @@ add_clang_library(clangTidyMiscModule
   ArgumentCommentCheck.cpp
   AssertSideEffectCheck.cpp
   ForwardingReferenceOverloadCheck.cpp
+  LambdaFunctionNameCheck.cpp
   MisplacedConstCheck.cpp
   UnconventionalAssignOperatorCheck.cpp
   BoolPointerImplicitConversionCheck.cpp

Added: clang-tools-extra/trunk/clang-tidy/misc/LambdaFunctionNameCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/LambdaFunctionNameCheck.cpp?rev=304570&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/LambdaFunctionNameCheck.cpp (added)
+++ clang-tools-extra/trunk/clang-tidy/misc/LambdaFunctionNameCheck.cpp Fri Jun  2 12:36:32 2017
@@ -0,0 +1,99 @@
+//===--- LambdaFunctionNameCheck.cpp - clang-tidy--------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "LambdaFunctionNameCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/MacroInfo.h"
+#include "clang/Lex/Preprocessor.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+namespace {
+
+// Keep track of macro expansions that contain both __FILE__ and __LINE__. If
+// such a macro also uses __func__ or __FUNCTION__, we don't want to issue a
+// warning because __FILE__ and __LINE__ may be useful even if __func__ or
+// __FUNCTION__ is not, especially if the macro could be used in the context of
+// either a function body or a lambda body.
+class MacroExpansionsWithFileAndLine : public PPCallbacks {
+public:
+  explicit MacroExpansionsWithFileAndLine(
+      LambdaFunctionNameCheck::SourceRangeSet *SME)
+      : SuppressMacroExpansions(SME) {}
+
+  void MacroExpands(const Token &MacroNameTok,
+                    const MacroDefinition &MD, SourceRange Range,
+                    const MacroArgs *Args) override {
+    bool has_file = false;
+    bool has_line = false;
+    for (const auto& T : MD.getMacroInfo()->tokens()) {
+      if (T.is(tok::identifier)) {
+        StringRef IdentName = T.getIdentifierInfo()->getName();
+        if (IdentName == "__FILE__") {
+          has_file = true;
+        } else if (IdentName == "__LINE__") {
+          has_line = true;
+        }
+      }
+    }
+    if (has_file && has_line) {
+      SuppressMacroExpansions->insert(Range);
+    }
+  }
+
+private:
+  LambdaFunctionNameCheck::SourceRangeSet* SuppressMacroExpansions;
+};
+
+} // namespace
+
+void LambdaFunctionNameCheck::registerMatchers(MatchFinder *Finder) {
+  // Match on PredefinedExprs inside a lambda.
+  Finder->addMatcher(predefinedExpr(hasAncestor(lambdaExpr())).bind("E"),
+                     this);
+}
+
+void LambdaFunctionNameCheck::registerPPCallbacks(CompilerInstance &Compiler) {
+  Compiler.getPreprocessor().addPPCallbacks(
+      llvm::make_unique<MacroExpansionsWithFileAndLine>(
+          &SuppressMacroExpansions));
+}
+
+void LambdaFunctionNameCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *E = Result.Nodes.getNodeAs<PredefinedExpr>("E");
+  if (E->getIdentType() != PredefinedExpr::Func &&
+      E->getIdentType() != PredefinedExpr::Function) {
+    // We don't care about other PredefinedExprs.
+    return;
+  }
+  if (E->getLocation().isMacroID()) {
+    auto ER =
+        Result.SourceManager->getImmediateExpansionRange(E->getLocation());
+    if (SuppressMacroExpansions.find(SourceRange(ER.first, ER.second)) !=
+        SuppressMacroExpansions.end()) {
+      // This is a macro expansion for which we should not warn.
+      return;
+    }
+  }
+  diag(E->getLocation(),
+       "inside a lambda, '%0' expands to the name of the function call "
+       "operator; consider capturing the name of the enclosing function "
+       "explicitly")
+      << PredefinedExpr::getIdentTypeName(E->getIdentType());
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang

Added: clang-tools-extra/trunk/clang-tidy/misc/LambdaFunctionNameCheck.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/LambdaFunctionNameCheck.h?rev=304570&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/LambdaFunctionNameCheck.h (added)
+++ clang-tools-extra/trunk/clang-tidy/misc/LambdaFunctionNameCheck.h Fri Jun  2 12:36:32 2017
@@ -0,0 +1,51 @@
+//===--- LambdaFunctionNameCheck.h - clang-tidy------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_LAMBDA_FUNCTION_NAME_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_LAMBDA_FUNCTION_NAME_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// Detect when __func__ or __FUNCTION__ is being used from within a lambda. In
+/// that context, those expressions expand to the name of the call operator
+/// (i.e., `operator()`).
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/misc-lambda-function-name.html
+class LambdaFunctionNameCheck : public ClangTidyCheck {
+public:
+  struct SourceRangeLessThan {
+    bool operator()(const SourceRange &L, const SourceRange &R) {
+      if (L.getBegin() == R.getBegin()) {
+        return L.getEnd() < R.getEnd();
+      }
+      return L.getBegin() < R.getBegin();
+    }
+  };
+  using SourceRangeSet = std::set<SourceRange, SourceRangeLessThan>;
+
+  LambdaFunctionNameCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void registerPPCallbacks(CompilerInstance &Compiler) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  SourceRangeSet SuppressMacroExpansions;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_LAMBDA_FUNCTION_NAME_H

Modified: clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp?rev=304570&r1=304569&r2=304570&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp (original)
+++ clang-tools-extra/trunk/clang-tidy/misc/MiscTidyModule.cpp Fri Jun  2 12:36:32 2017
@@ -21,6 +21,7 @@
 #include "InaccurateEraseCheck.h"
 #include "IncorrectRoundings.h"
 #include "InefficientAlgorithmCheck.h"
+#include "LambdaFunctionNameCheck.h"
 #include "MacroParenthesesCheck.h"
 #include "MacroRepeatedSideEffectsCheck.h"
 #include "MisplacedConstCheck.h"
@@ -68,6 +69,8 @@ public:
         "misc-assert-side-effect");
     CheckFactories.registerCheck<ForwardingReferenceOverloadCheck>(
         "misc-forwarding-reference-overload");
+    CheckFactories.registerCheck<LambdaFunctionNameCheck>(
+        "misc-lambda-function-name");
     CheckFactories.registerCheck<MisplacedConstCheck>("misc-misplaced-const");
     CheckFactories.registerCheck<UnconventionalAssignOperatorCheck>(
         "misc-unconventional-assign-operator");

Modified: clang-tools-extra/trunk/docs/ReleaseNotes.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/ReleaseNotes.rst?rev=304570&r1=304569&r2=304570&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/ReleaseNotes.rst (original)
+++ clang-tools-extra/trunk/docs/ReleaseNotes.rst Fri Jun  2 12:36:32 2017
@@ -77,6 +77,11 @@ Improvements to clang-tidy
 
   Finds perfect forwarding constructors that can unintentionally hide copy or move constructors.
 
+- New `misc-lambda-function-name
+	<http://clang.llvm.org/extra/clang-tidy/checks/misc-lambda-function-name.html>`_ check
+
+	Finds uses of ``__func__`` or ``__FUNCTION__`` inside lambdas.
+
 - New `modernize-replace-random-shuffle
   <http://clang.llvm.org/extra/clang-tidy/checks/modernize-replace-random-shuffle.html>`_ check
 

Modified: clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst?rev=304570&r1=304569&r2=304570&view=diff
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst (original)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/list.rst Fri Jun  2 12:36:32 2017
@@ -82,6 +82,7 @@ Clang-Tidy Checks
    misc-inaccurate-erase
    misc-incorrect-roundings
    misc-inefficient-algorithm
+   misc-lambda-function-name
    misc-macro-parentheses
    misc-macro-repeated-side-effects
    misc-misplaced-const

Added: clang-tools-extra/trunk/docs/clang-tidy/checks/misc-lambda-function-name.rst
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/docs/clang-tidy/checks/misc-lambda-function-name.rst?rev=304570&view=auto
==============================================================================
--- clang-tools-extra/trunk/docs/clang-tidy/checks/misc-lambda-function-name.rst (added)
+++ clang-tools-extra/trunk/docs/clang-tidy/checks/misc-lambda-function-name.rst Fri Jun  2 12:36:32 2017
@@ -0,0 +1,27 @@
+.. title:: clang-tidy - misc-lambda-function-name
+
+misc-lambda-function-name
+=========================
+
+Checks for attempts to get the name of a function from within a lambda
+expression. The name of a lambda is always something like ``operator()``, which
+is almost never what was intended.
+
+Example:
+
+.. code-block:: c++
+								
+  void FancyFunction() {
+    [] { printf("Called from %s\n", __func__); }();
+    [] { printf("Now called from %s\n", __FUNCTION__); }();
+  }
+
+Output::
+
+  Called from operator()
+  Now called from operator()
+
+Likely intended output::
+
+  Called from FancyFunction
+  Now called from FancyFunction

Added: clang-tools-extra/trunk/test/clang-tidy/misc-lambda-function-name.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/test/clang-tidy/misc-lambda-function-name.cpp?rev=304570&view=auto
==============================================================================
--- clang-tools-extra/trunk/test/clang-tidy/misc-lambda-function-name.cpp (added)
+++ clang-tools-extra/trunk/test/clang-tidy/misc-lambda-function-name.cpp Fri Jun  2 12:36:32 2017
@@ -0,0 +1,41 @@
+// RUN: %check_clang_tidy %s misc-lambda-function-name %t
+
+void Foo(const char* a, const char* b, int c) {}
+
+#define FUNC_MACRO Foo(__func__, "", 0)
+#define FUNCTION_MACRO Foo(__FUNCTION__, "", 0)
+#define EMBED_IN_ANOTHER_MACRO1 FUNC_MACRO
+
+void Positives() {
+  [] { __func__; }();
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: inside a lambda, '__func__' expands to the name of the function call operator; consider capturing the name of the enclosing function explicitly [misc-lambda-function-name]
+  [] { __FUNCTION__; }();
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: inside a lambda, '__FUNCTION__' expands to the name of the function call operator; consider capturing the name of the enclosing function explicitly [misc-lambda-function-name]
+  [] { FUNC_MACRO; }();
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: inside a lambda, '__func__' expands to the name of the function call operator; consider capturing the name of the enclosing function explicitly [misc-lambda-function-name]
+  [] { FUNCTION_MACRO; }();
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: inside a lambda, '__FUNCTION__' expands to the name of the function call operator; consider capturing the name of the enclosing function explicitly [misc-lambda-function-name]
+  [] { EMBED_IN_ANOTHER_MACRO1; }();
+  // CHECK-MESSAGES: :[[@LINE-1]]:8: warning: inside a lambda, '__func__' expands to the name of the function call operator; consider capturing the name of the enclosing function explicitly [misc-lambda-function-name]
+}
+
+#define FUNC_MACRO_WITH_FILE_AND_LINE Foo(__func__, __FILE__, __LINE__)
+#define FUNCTION_MACRO_WITH_FILE_AND_LINE Foo(__FUNCTION__, __FILE__, __LINE__)
+#define EMBED_IN_ANOTHER_MACRO2 FUNC_MACRO_WITH_FILE_AND_LINE
+
+void Negatives() {
+  __func__;
+  __FUNCTION__;
+
+  // __PRETTY_FUNCTION__ should not trigger a warning because its value is
+  // actually potentially useful.
+  __PRETTY_FUNCTION__;
+  [] { __PRETTY_FUNCTION__; }();
+
+  // Don't warn if __func__/__FUNCTION is used inside a macro that also uses
+  // __FILE__ and __LINE__, on the assumption that __FILE__ and __LINE__ will
+  // be useful even if __func__/__FUNCTION__ is not.
+  [] { FUNC_MACRO_WITH_FILE_AND_LINE; }();
+  [] { FUNCTION_MACRO_WITH_FILE_AND_LINE; }();
+  [] { EMBED_IN_ANOTHER_MACRO2; }();
+}




More information about the cfe-commits mailing list