This is a new clang-tidy checker that warns when there is side effects in a 
macro argument that is repeated in the macro expansion.

I am running tests. Right now it has been tested on 7678 files in 180 projects. 
And there has been in total 7 warnings. As far as I see all these 7 warnings 
are real bugs.

Interestingly I get a couple of warnings for standard functions that are 
implemented as macros. As far as I see my headers are not standard-compliant:

format.c:774:28: warning: Side effects in macro argument is repeated in macro 
expansion [misc-macro-repeated-side-effects]
                tblt->instr[0] = toupper(*p++);
                                         ^
/usr/include/ctype.h:229:11: note: 'toupper' macro defined here
#  define toupper(c)    __tobody (c, toupper, *__ctype_toupper_loc (), (c))
          ^

tunnel.c:73:25: warning: Side effects in macro argument is repeated in macro 
expansion [misc-macro-repeated-side-effects]
      char *q = strchr (++p, '"');
                        ^
/usr/include/x86_64-linux-gnu/bits/string2.h:395:11: note: 'strchr' macro 
defined here
#  define strchr(s, c) \
  (__extension__ (__builtin_constant_p (c) && !__builtin_constant_p (s)       \
                  && (c) == '\0'                                              \
                  ? (char *) __rawmemchr (s, c)                               \
                  : __builtin_strchr (s, c)))

...

http://reviews.llvm.org/D9496

Files:
  clang-tidy/misc/CMakeLists.txt
  clang-tidy/misc/MacroRepeatedSideEffectsCheck.cpp
  clang-tidy/misc/MacroRepeatedSideEffectsCheck.h
  clang-tidy/misc/MiscTidyModule.cpp
  test/clang-tidy/misc-repeated-side-effects-in-macro.c

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: test/clang-tidy/misc-repeated-side-effects-in-macro.c
===================================================================
--- test/clang-tidy/misc-repeated-side-effects-in-macro.c
+++ test/clang-tidy/misc-repeated-side-effects-in-macro.c
@@ -0,0 +1,32 @@
+// RUN: $(dirname %s)/check_clang_tidy.sh %s misc-macro-repeated-side-effects %t
+// REQUIRES: shell
+
+#define MIN(A,B)  (((A)<(B)) ? (A) : (B))
+
+void plusplus1() {
+  int j = 0;
+  int i = 0;
+  int min = MIN(i++, j);
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: side effects in macro argument is repeated in macro expansion [misc-macro-repeated-side-effects]
+}
+
+void plusplus2() {
+  int j = 0;
+  int i = 0;
+  int min = MIN(++i, j);
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: side effects in macro argument is repeated in macro expansion [misc-macro-repeated-side-effects]
+}
+
+void minusminus1() {
+  int j = 0;
+  int i = 0;
+  int min = MIN(i--, j);
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: side effects in macro argument is repeated in macro expansion [misc-macro-repeated-side-effects]
+}
+
+void minusminus2() {
+  int j = 0;
+  int i = 0;
+  int min = MIN(--i, j);
+  // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: side effects in macro argument is repeated in macro expansion [misc-macro-repeated-side-effects]
+}
Index: clang-tidy/misc/MacroRepeatedSideEffectsCheck.cpp
===================================================================
--- clang-tidy/misc/MacroRepeatedSideEffectsCheck.cpp
+++ clang-tidy/misc/MacroRepeatedSideEffectsCheck.cpp
@@ -0,0 +1,100 @@
+//===--- MacroRepeatedSideEffectsCheck.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 "MacroRepeatedSideEffectsCheck.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/PPCallbacks.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Lex/MacroArgs.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+namespace {
+class MacroRepeatedPPCallbacks : public PPCallbacks {
+public:
+  MacroRepeatedPPCallbacks(ClangTidyCheck &Check, SourceManager &SM,
+                           Preprocessor &PP)
+      : Check(Check), SM(SM), PP(PP) {}
+
+  void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,
+                    SourceRange Range, const MacroArgs *Args) override;
+
+private:
+  ClangTidyCheck &Check;
+  SourceManager &SM;
+  Preprocessor &PP;
+};
+} // namespace
+
+void MacroRepeatedPPCallbacks::MacroExpands(const Token &MacroNameTok,
+                                            const MacroDefinition &MD,
+                                            SourceRange Range,
+                                            const MacroArgs *Args) {
+  clang::SourceLocation Loc = Range.getBegin();
+  // Ignore macro argument expansions.
+  if (!Loc.isFileID())
+    return;
+
+  const clang::MacroInfo *MI = MD.getMacroInfo();
+
+  typedef clang::MacroInfo::tokens_iterator TokIter;
+  typedef clang::MacroInfo::arg_iterator ArgIter;
+  for (ArgIter AI = MI->arg_begin(), AE = MI->arg_end(); AI != AE; ++AI) {
+    const clang::Token *ResultArgToks =
+        Args->getUnexpArgument(MI->getArgumentNum((*AI)));
+    int CountInMacro = 0;
+    for (TokIter TI = MI->tokens_begin(), TE = MI->tokens_end(); TI != TE;
+         ++TI) {
+      clang::IdentifierInfo *TII = TI->getIdentifierInfo();
+      int ArgNo = (TII ? MI->getArgumentNum(TII) : -1);
+      if (ArgNo == -1) {
+        // This isn't an argument, continue.
+        continue;
+      }
+      const clang::Token *Res = Args->getUnexpArgument(ArgNo);
+      if (ResultArgToks == Res)
+        CountInMacro++;
+    }
+
+    if (CountInMacro < 2)
+      continue;
+
+    // If the arg token didn't expand into anything, ignore it.
+    if (ResultArgToks->is(clang::tok::eof))
+      continue;
+    unsigned NumToks = clang::MacroArgs::getArgLength(ResultArgToks);
+
+    // Check for sideeffects in the argument expansions.
+    for (unsigned ArgumentIndex = 0; ArgumentIndex < NumToks; ++ArgumentIndex) {
+      const clang::Token &AT = ResultArgToks[ArgumentIndex];
+
+      if (AT.is(clang::tok::plusplus) || AT.is(clang::tok::minusminus)) {
+        Check.diag(
+            ResultArgToks->getLocation(),
+            "side effects in macro argument is repeated in macro expansion");
+        Check.diag(MI->getDefinitionLoc(), "%0 macro defined here",
+                   DiagnosticIDs::Note)
+            << MacroNameTok.getIdentifierInfo();
+      }
+    }
+  }
+}
+
+void MacroRepeatedSideEffectsCheck::registerPPCallbacks(
+    CompilerInstance &Compiler) {
+  Compiler.getPreprocessor().addPPCallbacks(
+      ::llvm::make_unique<MacroRepeatedPPCallbacks>(
+          *this, Compiler.getSourceManager(), Compiler.getPreprocessor()));
+}
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
Index: clang-tidy/misc/MacroRepeatedSideEffectsCheck.h
===================================================================
--- clang-tidy/misc/MacroRepeatedSideEffectsCheck.h
+++ clang-tidy/misc/MacroRepeatedSideEffectsCheck.h
@@ -0,0 +1,32 @@
+//===--- MacroRepeatedSideEffectsCheck.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_MACRO_REPEATED_SIDE_EFFECTS_CHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MACRO_REPEATED_SIDE_EFFECTS_CHECK_H
+
+#include "../ClangTidy.h"
+
+namespace clang {
+namespace tidy {
+namespace misc {
+
+/// \brief Checks for repeated side effects in macros.
+///
+class MacroRepeatedSideEffectsCheck : public ClangTidyCheck {
+public:
+  MacroRepeatedSideEffectsCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerPPCallbacks(CompilerInstance &Compiler) override;
+};
+
+} // namespace misc
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_MACRO_REPEATED_SIDE_EFFECTS_CHECK_H
Index: clang-tidy/misc/MiscTidyModule.cpp
===================================================================
--- clang-tidy/misc/MiscTidyModule.cpp
+++ clang-tidy/misc/MiscTidyModule.cpp
@@ -16,6 +16,7 @@
 #include "BoolPointerImplicitConversionCheck.h"
 #include "InaccurateEraseCheck.h"
 #include "InefficientAlgorithmCheck.h"
+#include "MacroRepeatedSideEffectsCheck.h"
 #include "StaticAssertCheck.h"
 #include "SwappedArgumentsCheck.h"
 #include "UndelegatedConstructor.h"
@@ -41,6 +42,8 @@
         "misc-inaccurate-erase");
     CheckFactories.registerCheck<InefficientAlgorithmCheck>(
         "misc-inefficient-algorithm");
+    CheckFactories.registerCheck<MacroRepeatedSideEffectsCheck>(
+        "misc-macro-repeated-side-effects");
     CheckFactories.registerCheck<StaticAssertCheck>(
         "misc-static-assert");
     CheckFactories.registerCheck<SwappedArgumentsCheck>(
Index: clang-tidy/misc/CMakeLists.txt
===================================================================
--- clang-tidy/misc/CMakeLists.txt
+++ clang-tidy/misc/CMakeLists.txt
@@ -7,6 +7,7 @@
   BoolPointerImplicitConversionCheck.cpp
   InaccurateEraseCheck.cpp
   InefficientAlgorithmCheck.cpp
+  MacroRepeatedSideEffectsCheck.cpp
   MiscTidyModule.cpp
   StaticAssertCheck.cpp
   SwappedArgumentsCheck.cpp
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to