Hi alexfh,

This patch fixes possible false negatives when macro contains ?:.

I tested this improvemed checker on 1398 open source projects, but did not see 
any new warnings.. At least that means that it did not cause any new false 
positives even though it does fix the false negatives that are shown in the 
testing.

Question: Is it a good idea to use std::stack or would some other container be 
better in clang-tidy?

http://reviews.llvm.org/D10653

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

EMAIL PREFERENCES
  http://reviews.llvm.org/settings/panel/emailpreferences/
Index: clang-tidy/misc/MacroRepeatedSideEffectsCheck.cpp
===================================================================
--- clang-tidy/misc/MacroRepeatedSideEffectsCheck.cpp
+++ clang-tidy/misc/MacroRepeatedSideEffectsCheck.cpp
@@ -51,10 +51,10 @@
   // making the macro too complex.
   if (std::find_if(
           MI->tokens().begin(), MI->tokens().end(), [](const Token &T) {
-            return T.isOneOf(tok::question, tok::kw_if, tok::kw_else,
-                             tok::kw_switch, tok::kw_case, tok::kw_break,
-                             tok::kw_while, tok::kw_do, tok::kw_for,
-                             tok::kw_continue, tok::kw_goto, tok::kw_return);
+            return T.isOneOf(tok::kw_if, tok::kw_else, tok::kw_switch,
+                             tok::kw_case, tok::kw_break, tok::kw_while,
+                             tok::kw_do, tok::kw_for, tok::kw_continue,
+                             tok::kw_goto, tok::kw_return);
           }) != MI->tokens().end())
     return;
 
@@ -77,10 +77,30 @@
 
 unsigned MacroRepeatedPPCallbacks::CountArgumentExpansions(
     const MacroInfo *MI, const IdentifierInfo *Arg) const {
-  unsigned CountInMacro = 0;
+  // Current argument count. When moving forward to a different control-flow
+  // path this can decrease.
+  unsigned Current = 0;
+  // Max argument count.
+  unsigned Max = 0;
   bool SkipParen = false;
   int SkipParenCount = 0;
+  bool FoundBuiltin = false;
+  std::stack<unsigned> CountAtQuestion;
   for (const auto &T : MI->tokens()) {
+    // Handling of ? and :.
+    if (T.is(tok::question)) {
+      // Result from __builtin might be known, maybe only the true or false
+      // expression should be analysed.
+      if (FoundBuiltin)
+        return Max;
+      CountAtQuestion.push(Current);
+    } else if (T.is(tok::colon)) {
+      if (CountAtQuestion.empty())
+        return 0;
+      Current = CountAtQuestion.top();
+      CountAtQuestion.pop();
+    }
+
     // If current token is a parenthesis, skip it.
     if (SkipParen) {
       if (T.is(tok::l_paren))
@@ -100,6 +120,7 @@
     // If a builtin is found within the macro definition, skip next
     // parenthesis.
     if (TII->getBuiltinID() != 0) {
+      FoundBuiltin = true;
       SkipParen = true;
       continue;
     }
@@ -114,10 +135,13 @@
     }
 
     // Count argument.
-    if (TII == Arg)
-      CountInMacro++;
+    if (TII == Arg) {
+      Current++;
+      if (Current > Max)
+        Max = Current;
+    }
   }
-  return CountInMacro;
+  return Max;
 }
 
 bool MacroRepeatedPPCallbacks::HasSideEffects(
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
@@ -22,6 +22,21 @@
 }
 
 
+#define MIN(A,B)     ((A) < (B) ? (A) : (B))                        // single ?:
+#define LIMIT(X,A,B) ((X) < (A) ? (A) : ((X) > (B) ? (B) : (X)))    // two ?:
+void question(int x) {
+  MIN(x++, 12);
+  // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: side effects in the 1st macro argument 'A'
+  MIN(34, x++);
+  // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: side effects in the 2nd macro argument 'B'
+  LIMIT(x++, 0, 100);
+  // CHECK-MESSAGES: :[[@LINE-1]]:9: warning: side effects in the 1st macro argument 'X'
+  LIMIT(20, x++, 100);
+  // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: side effects in the 2nd macro argument 'A'
+  LIMIT(20, 0, x++);
+  // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: side effects in the 3rd macro argument 'B'
+}
+
 // False positive: Repeated side effects is intentional.
 // It is hard to know when it's done by intention so right now we warn.
 #define UNROLL(A)    {A A}
@@ -74,11 +89,9 @@
 }
 
 // Bail out for conditionals.
-#define condA(x,y)  ((x)>(y)?(x):(y))
 #define condB(x,y)  if(x) {x=y;} else {x=y + 1;}
-void conditionals(int ret, int a, int b)
+void conditionals(int a, int b)
 {
-  ret += condA(a++, b++);
   condB(a, b++);
 }
 
_______________________________________________
cfe-commits mailing list
cfe-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to