From 0e4ba47ca827f96319ff9c5f2f9f7ee5c607f6ea Mon Sep 17 00:00:00 2001 From: Congcong Cai Date: Wed, 12 Mar 2025 06:12:09 +0800 Subject: [PATCH] [clang-tidy] support to detect conversion in `make_optional` for `bugprone-optional-value-conversion` (#130417) Add support for std::make_optional. Fixes #119554 --- .../bugprone/OptionalValueConversionCheck.cpp | 25 ++++++++++++++++--- clang-tools-extra/docs/ReleaseNotes.rst | 4 +++ ...al-value-conversion-construct-from-std.cpp | 13 ++++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp index 33e823ac0749..cda9288c0531 100644 --- a/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/OptionalValueConversionCheck.cpp @@ -12,6 +12,7 @@ #include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/ASTMatchers/ASTMatchers.h" #include using namespace clang::ast_matchers; @@ -31,6 +32,7 @@ constexpr std::array MakeSmartPtrList{ "::std::make_unique", "::std::make_shared", }; +constexpr StringRef MakeOptional = "::std::make_optional"; } // namespace @@ -83,9 +85,26 @@ void OptionalValueConversionCheck::registerMatchers(MatchFinder *Finder) { // known template methods in std callExpr( argumentCountIs(1), - callee(functionDecl( - matchers::matchesAnyListedName(MakeSmartPtrList), - hasTemplateArgument(0, refersToType(BindOptionalType)))), + anyOf( + // match std::make_unique std::make_shared + callee(functionDecl( + matchers::matchesAnyListedName(MakeSmartPtrList), + hasTemplateArgument( + 0, refersToType(BindOptionalType)))), + // match first std::make_optional by limit argument count + // (1) and template count (1). + // 1. template< class T > constexpr + // std::optional> make_optional(T&& value); + // 2. template< class T, class... Args > constexpr + // std::optional make_optional(Args&&... args); + callee(functionDecl(templateArgumentCountIs(1), + hasName(MakeOptional), + returns(BindOptionalType)))), + hasArgument(0, OptionalDerefMatcher)), + callExpr( + + argumentCountIs(1), + hasArgument(0, OptionalDerefMatcher))), unless(anyOf(hasAncestor(typeLoc()), hasAncestor(expr(matchers::hasUnevaluatedContext()))))) diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 8f8e6e3c0165..110f949741c3 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -112,6 +112,10 @@ New check aliases Changes in existing checks ^^^^^^^^^^^^^^^^^^^^^^^^^^ +- Improved :doc:`bugprone-optional-value-conversion + ` check to detect + conversion in argument of ``std::make_optional``. + - Improved :doc:`bugprone-string-constructor ` check to find suspicious calls of ``std::string`` constructor with char pointer, start position and diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/optional-value-conversion-construct-from-std.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/optional-value-conversion-construct-from-std.cpp index 768ab1ce014c..305fd6890710 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/optional-value-conversion-construct-from-std.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/optional-value-conversion-construct-from-std.cpp @@ -27,9 +27,19 @@ class unique_ptr {}; template class shared_ptr {}; +template +class initializer_list {}; + template unique_ptr make_unique(Args &&...args); template shared_ptr make_shared(Args &&...args); +template +constexpr std::optional<__decay(T)> make_optional(T &&value); +template +constexpr std::optional make_optional(Args &&...args); +template +constexpr std::optional make_optional(std::initializer_list il, Args &&...args); + } // namespace std struct A { @@ -45,9 +55,12 @@ void invalid() { // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: conversion from 'std::optional' into 'int' and back into 'std::optional', remove potentially error-prone optional dereference [bugprone-optional-value-conversion] std::make_shared>(opt.value()); // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: conversion from 'std::optional' into 'int' and back into 'std::optional', remove potentially error-prone optional dereference [bugprone-optional-value-conversion] + std::make_optional(opt.value()); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: conversion from 'std::optional' into 'int' and back into 'std::optional', remove potentially error-prone optional dereference [bugprone-optional-value-conversion] } void valid() { std::make_unique(opt.value()); std::make_shared(opt.value()); + std::make_optional(opt.value()); }