https://github.com/5chmidti created https://github.com/llvm/llvm-project/pull/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. >From 9b5bf4e1d53b3a55f9290199aeccb02c20a1e2cc Mon Sep 17 00:00:00 2001 From: Julian Schmidt <git.julian.schm...@gmail.com> Date: Fri, 26 Apr 2024 22:49:38 +0200 Subject: [PATCH] [clang-tidy] fix false-positives for templates in `bugprone-return-const-ref-from-parameter` 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. --- .../ReturnConstRefFromParameterCheck.cpp | 10 +- .../return-const-ref-from-parameter.cpp | 114 ++++++++++++++++++ 2 files changed, 121 insertions(+), 3 deletions(-) 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..205d93606993e1 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 @@ -4,6 +4,15 @@ 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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits