teemperor created this revision.
teemperor added reviewers: v.g.vassilev, NoQ, zaks.anna.
teemperor added a subscriber: cfe-commits.

So far macro-generated code was treated by the CloneDetector as normal code. 
This caused that some macros where reported as false-positive clones because 
their generated code was detected as a clone.

This patch prevents that macro-generated code is influencing the complexity 
value of clones. This prevents that macros are reported as clones.

https://reviews.llvm.org/D23316

Files:
  lib/Analysis/CloneDetection.cpp
  test/Analysis/copypaste/macro-complexity.cpp
  test/Analysis/copypaste/macros.cpp

Index: test/Analysis/copypaste/macros.cpp
===================================================================
--- /dev/null
+++ test/Analysis/copypaste/macros.cpp
@@ -0,0 +1,38 @@
+// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+
+// Tests that macros and non-macro clones aren't mixed into the same hash
+// group. This is currently necessary as all clones in a hash group need
+// to have the same complexity value. Macros have smaller complexity values
+// and need to be in their own hash group.
+
+#define ABS(a, b) a > b ? a : b;
+
+int max(int a, int b) { // expected-warning{{Detected code clone.}}
+  return a > b ? a : b;
+}
+
+int maxClone(int a, int b) { // expected-note{{Related code clone is here.}}
+  return a > b ? a : b;
+}
+
+int maxNoClone(int a, int b) {
+  return ABS(a, b);
+}
+
+// Tests that code containing macros is still reported.
+
+void longFoo() { // expected-warning{{Detected code clone.}}
+  const unsigned size = 10;
+  int array[size];
+  for (unsigned i = 0; i < size; i++) {
+    array[i] = ABS(i, 5);
+  }
+}
+
+void longFooClone () { // expected-note{{Related code clone is here.}}
+  const unsigned size = 10;
+  int array[size];
+  for (unsigned i = 0; i < size; i++) {
+    array[i] = ABS(i, 5);
+  }
+}
Index: test/Analysis/copypaste/macro-complexity.cpp
===================================================================
--- /dev/null
+++ test/Analysis/copypaste/macro-complexity.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=20 -verify %s
+
+// Tests that only non-generated code increases the complexity of a statement.
+
+#define MACRO_FOO(a, b) a > b ? -a * a : -b * b;
+
+// The body of these two aren't complex enough to be considered clones of each
+// other.
+int fooMacro(int a, int b) {
+  return MACRO_FOO(a, b);
+}
+
+int fooMacroClone(int a, int b) {
+  return MACRO_FOO(a, b);
+}
+
+// This tests that above code would be complex enough to be reported.
+// Prevents that this tests won't accidentially pass because the code inside
+// the macro isn't complex enough.
+int foo(int a, int b) {  // expected-warning{{Detected code clone.}}
+  return a > b ? -a * a : -b * b;
+}
+
+int fooClone(int a, int b) {  // expected-note{{Related code clone is here.}}
+  return a > b ? -a * a : -b * b;
+}
Index: lib/Analysis/CloneDetection.cpp
===================================================================
--- lib/Analysis/CloneDetection.cpp
+++ lib/Analysis/CloneDetection.cpp
@@ -297,7 +297,14 @@
     ConstStmtVisitor<StmtDataCollector>::Visit##CLASS(S);                      \
   }
 
-  DEF_ADD_DATA(Stmt, { addData(S->getStmtClass()); })
+  DEF_ADD_DATA(Stmt, {
+    addData(S->getStmtClass());
+    // This ensures that macro-code and non-macro code never lands in the same
+    // hash group. This is necessary as they have different complexity values
+    // and a single group currently needs to have one common complexity value.
+    addData(S->getLocStart().isMacroID());
+    addData(S->getLocEnd().isMacroID());
+  })
   DEF_ADD_DATA(Expr, { addData(S->getType()); })
 
   //--- Builtin functionality ----------------------------------------------//
@@ -419,6 +426,16 @@
     // Collect all relevant data from S and put it into the empty signature.
     StmtDataCollector(S, Context, Signature.Data);
 
+    // If this code is generated by a macro, it won't increase the complexity
+    // level of it's containing clone. This prevents false-positives caused by
+    // complex macros. For example 'assert(false)' could be reported as a clone
+    // if the assert macro is implemented as a expression that would
+    // fulfill the standard complexity requirement for clones.
+    bool IsInMacro = S->getLocStart().isMacroID() || S->getLocEnd().isMacroID();
+    if (IsInMacro) {
+      Signature.Complexity = 0;
+    }
+
     // Storage for the signatures of the direct child statements. This is only
     // needed if the current statement is a CompoundStmt.
     std::vector<CloneDetector::CloneSignature> ChildSignatures;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to