Index: lib/Analysis/CloneDetection.cpp =================================================================== --- lib/Analysis/CloneDetection.cpp +++ lib/Analysis/CloneDetection.cpp @@ -297,7 +297,14 @@ ConstStmtVisitor::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 ChildSignatures; 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: 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); + } +}