[clang-tools-extra] 9aad38b - [clang-tidy] fix false-positives for templates in `bugprone-return-const-ref-from-parameter` (#90273)
via cfe-commits
cfe-commits at lists.llvm.org
Sun May 5 08:51:37 PDT 2024
Author: Julian Schmidt
Date: 2024-05-05T17:51:33+02:00
New Revision: 9aad38b61586cab8b125c3f522789267f9b749a9
URL: https://github.com/llvm/llvm-project/commit/9aad38b61586cab8b125c3f522789267f9b749a9
DIFF: https://github.com/llvm/llvm-project/commit/9aad38b61586cab8b125c3f522789267f9b749a9.diff
LOG: [clang-tidy] fix false-positives for templates in `bugprone-return-const-ref-from-parameter` (#90273)
In the AST for function templates, the return will be a DeclRefExpr,
even if the return type differs from that of the returned variable.
Protect against false-positives by constraining the canonical return
type to be that of the parameter.
Also streams the source range of the returned expression into the
diagnostic.
Added:
Modified:
clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp
clang-tools-extra/test/clang-tidy/checkers/bugprone/return-const-ref-from-parameter.cpp
Removed:
################################################################################
diff --git a/clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp
index 8ae37d4f774d23..b3f7dd6d1c86f8 100644
--- a/clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/ReturnConstRefFromParameterCheck.cpp
@@ -17,8 +17,11 @@ namespace clang::tidy::bugprone {
void ReturnConstRefFromParameterCheck::registerMatchers(MatchFinder *Finder) {
Finder->addMatcher(
- returnStmt(hasReturnValue(declRefExpr(to(parmVarDecl(hasType(
- hasCanonicalType(matchers::isReferenceToConst())))))))
+ returnStmt(
+ hasReturnValue(declRefExpr(to(parmVarDecl(hasType(hasCanonicalType(
+ qualType(matchers::isReferenceToConst()).bind("type"))))))),
+ hasAncestor(functionDecl(hasReturnTypeLoc(
+ loc(qualType(hasCanonicalType(equalsBoundNode("type"))))))))
.bind("ret"),
this);
}
@@ -28,7 +31,8 @@ void ReturnConstRefFromParameterCheck::check(
const auto *R = Result.Nodes.getNodeAs<ReturnStmt>("ret");
diag(R->getRetValue()->getBeginLoc(),
"returning a constant reference parameter may cause a use-after-free "
- "when the parameter is constructed from a temporary");
+ "when the parameter is constructed from a temporary")
+ << R->getRetValue()->getSourceRange();
}
} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/return-const-ref-from-parameter.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/return-const-ref-from-parameter.cpp
index a83a019ec7437d..ca41bdf74a1073 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/return-const-ref-from-parameter.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/return-const-ref-from-parameter.cpp
@@ -1,9 +1,18 @@
-// RUN: %check_clang_tidy %s bugprone-return-const-ref-from-parameter %t
+// RUN: %check_clang_tidy %s bugprone-return-const-ref-from-parameter %t -- -- -fno-delayed-template-parsing
using T = int;
using TConst = int const;
using TConstRef = int const&;
+template <typename T>
+struct Wrapper { Wrapper(T); };
+
+template <typename T>
+struct Identity { using type = T; };
+
+template <typename T>
+struct ConstRef { using type = const T&; };
+
namespace invalid {
int const &f1(int const &a) { return a; }
@@ -18,8 +27,59 @@ int const &f3(TConstRef a) { return a; }
int const &f4(TConst &a) { return a; }
// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: returning a constant reference parameter
+template <typename T>
+const T& tf1(const T &a) { return a; }
+// CHECK-MESSAGES: :[[@LINE-1]]:35: warning: returning a constant reference parameter
+
+template <typename T>
+const T& itf1(const T &a) { return a; }
+// CHECK-MESSAGES: :[[@LINE-1]]:36: warning: returning a constant reference parameter
+
+template <typename T>
+typename ConstRef<T>::type itf2(const T &a) { return a; }
+// CHECK-MESSAGES: :[[@LINE-1]]:54: warning: returning a constant reference parameter
+
+template <typename T>
+typename ConstRef<T>::type itf3(typename ConstRef<T>::type a) { return a; }
+// CHECK-MESSAGES: :[[@LINE-1]]:72: warning: returning a constant reference parameter
+
+template <typename T>
+const T& itf4(typename ConstRef<T>::type a) { return a; }
+// CHECK-MESSAGES: :[[@LINE-1]]:54: warning: returning a constant reference parameter
+
+void instantiate(const int ¶m, const float ¶mf, int &mut_param, float &mut_paramf) {
+ itf1(0);
+ itf1(param);
+ itf1(paramf);
+ itf2(0);
+ itf2(param);
+ itf2(paramf);
+ itf3<int>(0);
+ itf3<int>(param);
+ itf3<float>(paramf);
+ itf4<int>(0);
+ itf4<int>(param);
+ itf4<float>(paramf);
+}
+
+struct C {
+ const C& foo(const C&c) { return c; }
+// CHECK-MESSAGES: :[[@LINE-1]]:38: warning: returning a constant reference parameter
+};
+
} // namespace invalid
+namespace false_negative_because_dependent_and_not_instantiated {
+template <typename T>
+typename ConstRef<T>::type tf2(const T &a) { return a; }
+
+template <typename T>
+typename ConstRef<T>::type tf3(typename ConstRef<T>::type a) { return a; }
+
+template <typename T>
+const T& tf4(typename ConstRef<T>::type a) { return a; }
+} // false_negative_because_dependent_and_not_instantiated
+
namespace valid {
int const &f1(int &a) { return a; }
@@ -28,4 +88,58 @@ int const &f2(int &&a) { return a; }
int f1(int const &a) { return a; }
+template <typename T>
+T tf1(T a) { return a; }
+
+template <typename T>
+T tf2(const T a) { return a; }
+
+template <typename T>
+T tf3(const T &a) { return a; }
+
+template <typename T>
+Identity<T>::type tf4(const T &a) { return a; }
+
+template <typename T>
+T itf1(T a) { return a; }
+
+template <typename T>
+T itf2(const T a) { return a; }
+
+template <typename T>
+T itf3(const T &a) { return a; }
+
+template <typename T>
+Wrapper<T> itf4(const T& a) { return a; }
+
+template <typename T>
+const T& itf5(T& a) { return a; }
+
+template <typename T>
+T itf6(T& a) { return a; }
+
+void instantiate(const int ¶m, const float ¶mf, int &mut_param, float &mut_paramf) {
+ itf1(0);
+ itf1(param);
+ itf1(paramf);
+ itf2(0);
+ itf2(param);
+ itf2(paramf);
+ itf3(0);
+ itf3(param);
+ itf3(paramf);
+ itf2(0);
+ itf2(param);
+ itf2(paramf);
+ itf3(0);
+ itf3(param);
+ itf3(paramf);
+ itf4(param);
+ itf4(paramf);
+ itf5(mut_param);
+ itf5(mut_paramf);
+ itf6(mut_param);
+ itf6(mut_paramf);
+}
+
} // namespace valid
More information about the cfe-commits
mailing list