Index: clang-tools-extra/clang-tidy/utils/Aliasing.cpp =================================================================== --- clang-tools-extra/clang-tidy/utils/Aliasing.cpp +++ clang-tools-extra/clang-tidy/utils/Aliasing.cpp @@ -8,6 +8,7 @@ #include "Aliasing.h" +#include "clang/Analysis/AnyCall.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" @@ -50,6 +51,10 @@ } else if (const auto *LE = dyn_cast(S)) { // Treat lambda capture by reference as a form of taking a reference. return capturesByRef(LE->getLambdaClass(), Var); + } else if (Optional Call = AnyCall::forExpr(S)) { + return llvm::any_of(Call->arguments(), [Var](const Expr *ArgE) { + return isAccessForVar(ArgE, Var); + }); } return false; Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-infinite-loop.cpp @@ -551,3 +551,28 @@ do { } while (false && CondVar); } + +int &hidden_reference(int &x) { + return x; +} + +void test_hidden_reference() { + int x = 0; + int &y = hidden_reference(x); + for (; x < 10; ++y) { + // No warning. The loop is finite because 'y' is a reference to 'x'. + } +} + +struct HiddenReference { + int &y; + HiddenReference(int &x) : y(x) {} +}; + +void test_HiddenReference() { + int x = 0; + int &y = HiddenReference(x).y; + for (; x < 10; ++y) { + // No warning. The loop is finite because 'y' is a reference to 'x'. + } +} Index: clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp =================================================================== --- clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp +++ clang-tools-extra/test/clang-tidy/checkers/bugprone-redundant-branch-condition.cpp @@ -967,12 +967,29 @@ } if (tryToExtinguish(onFire) && onFire) { if (tryToExtinguishByVal(onFire) && onFire) { - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition] + // NO-MESSAGE: technically tryToExtinguish() may launch + // a background thread to extinguish the fire while tryToExtinguishByVal() + // may be waiting for that thread to finish. scream(); } } } +bool &hidden_reference(bool &flag) { + return flag; +} + +void test_hidden_reference() { + bool onFire = isBurning(); + bool onFireRef = hidden_reference(onFire); + if (onFire) { + onFireRef = false; + if (onFire) { + // NO-MESSAGE: fire was extinguished by the above assignment + } + } +} + void negative_reassigned() { bool onFire = isBurning(); if (onFire) { @@ -992,11 +1009,9 @@ bool onFire = isBurning(); if (onFire) { if (onFire) { - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition] - // CHECK-FIXES: {{^\ *$}} + // FIXME: This should warn. scream(); } - // CHECK-FIXES: {{^\ *$}} tryToExtinguish(onFire); } } @@ -1006,11 +1021,9 @@ if (onFire) { if (someOtherCondition()) { if (onFire) { - // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition] - // CHECK-FIXES: {{^\ *$}} + // FIXME: This should warn. scream(); } - // CHECK-FIXES: {{^\ *$}} } tryToExtinguish(onFire); } @@ -1021,11 +1034,9 @@ if (onFire) { if (someOtherCondition()) { if (onFire) { - // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition] - // CHECK-FIXES: {{^\ *$}} + // FIXME: This should warn. scream(); } - // CHECK-FIXES: {{^\ *$}} tryToExtinguish(onFire); } } @@ -1035,8 +1046,7 @@ bool onFire = isBurning(); if (onFire) { if (onFire) { - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: redundant condition 'onFire' [bugprone-redundant-branch-condition] - // CHECK-FIXES: {{^\ *$}} + // FIXME: This should warn. tryToExtinguish(onFire); scream(); }