[clang-tidy] Add bugprone-optional-value-conversion check
Detects potentially unintentional and redundant conversions where a value is extracted from an optional-like type and then used to create a new instance of the same optional-like type. Reviewed By: xgupta Differential Revision: https://reviews.llvm.org/D147357
This commit is contained in:
@@ -44,6 +44,7 @@
|
||||
#include "NoEscapeCheck.h"
|
||||
#include "NonZeroEnumToBoolConversionCheck.h"
|
||||
#include "NotNullTerminatedResultCheck.h"
|
||||
#include "OptionalValueConversionCheck.h"
|
||||
#include "ParentVirtualCallCheck.h"
|
||||
#include "PosixReturnCheck.h"
|
||||
#include "RedundantBranchConditionCheck.h"
|
||||
@@ -150,6 +151,8 @@ public:
|
||||
"bugprone-multiple-new-in-one-expression");
|
||||
CheckFactories.registerCheck<MultipleStatementMacroCheck>(
|
||||
"bugprone-multiple-statement-macro");
|
||||
CheckFactories.registerCheck<OptionalValueConversionCheck>(
|
||||
"bugprone-optional-value-conversion");
|
||||
CheckFactories.registerCheck<RedundantBranchConditionCheck>(
|
||||
"bugprone-redundant-branch-condition");
|
||||
CheckFactories.registerCheck<cppcoreguidelines::NarrowingConversionsCheck>(
|
||||
|
||||
@@ -40,6 +40,7 @@ add_clang_library(clangTidyBugproneModule
|
||||
NoEscapeCheck.cpp
|
||||
NonZeroEnumToBoolConversionCheck.cpp
|
||||
NotNullTerminatedResultCheck.cpp
|
||||
OptionalValueConversionCheck.cpp
|
||||
ParentVirtualCallCheck.cpp
|
||||
PosixReturnCheck.cpp
|
||||
RedundantBranchConditionCheck.cpp
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
//===--- OptionalValueConversionCheck.cpp - clang-tidy --------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "OptionalValueConversionCheck.h"
|
||||
#include "../utils/LexerUtils.h"
|
||||
#include "../utils/Matchers.h"
|
||||
#include "../utils/OptionsUtils.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
|
||||
using namespace clang::ast_matchers;
|
||||
|
||||
namespace clang::tidy::bugprone {
|
||||
|
||||
namespace {
|
||||
|
||||
AST_MATCHER_P(QualType, hasCleanType, ast_matchers::internal::Matcher<QualType>,
|
||||
InnerMatcher) {
|
||||
return InnerMatcher.matches(
|
||||
Node.getNonReferenceType().getUnqualifiedType().getCanonicalType(),
|
||||
Finder, Builder);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
OptionalValueConversionCheck::OptionalValueConversionCheck(
|
||||
StringRef Name, ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context),
|
||||
OptionalTypes(utils::options::parseStringList(
|
||||
Options.get("OptionalTypes",
|
||||
"::std::optional;::absl::optional;::boost::optional"))),
|
||||
ValueMethods(utils::options::parseStringList(
|
||||
Options.get("ValueMethods", "::value$;::get$"))) {}
|
||||
|
||||
std::optional<TraversalKind>
|
||||
OptionalValueConversionCheck::getCheckTraversalKind() const {
|
||||
return TK_AsIs;
|
||||
}
|
||||
|
||||
void OptionalValueConversionCheck::registerMatchers(MatchFinder *Finder) {
|
||||
auto ConstructTypeMatcher =
|
||||
qualType(hasCleanType(qualType().bind("optional-type")));
|
||||
|
||||
auto CallTypeMatcher =
|
||||
qualType(hasCleanType(equalsBoundNode("optional-type")));
|
||||
|
||||
auto OptionalDereferenceMatcher = callExpr(
|
||||
anyOf(
|
||||
cxxOperatorCallExpr(hasOverloadedOperatorName("*"),
|
||||
hasUnaryOperand(hasType(CallTypeMatcher)))
|
||||
.bind("op-call"),
|
||||
cxxMemberCallExpr(thisPointerType(CallTypeMatcher),
|
||||
callee(cxxMethodDecl(anyOf(
|
||||
hasOverloadedOperatorName("*"),
|
||||
matchers::matchesAnyListedName(ValueMethods)))))
|
||||
.bind("member-call")),
|
||||
hasType(qualType().bind("value-type")));
|
||||
|
||||
auto StdMoveCallMatcher =
|
||||
callExpr(argumentCountIs(1), callee(functionDecl(hasName("::std::move"))),
|
||||
hasArgument(0, ignoringImpCasts(OptionalDereferenceMatcher)));
|
||||
Finder->addMatcher(
|
||||
cxxConstructExpr(
|
||||
argumentCountIs(1U),
|
||||
hasDeclaration(cxxConstructorDecl(
|
||||
ofClass(matchers::matchesAnyListedName(OptionalTypes)))),
|
||||
hasType(ConstructTypeMatcher),
|
||||
hasArgument(0U, ignoringImpCasts(anyOf(OptionalDereferenceMatcher,
|
||||
StdMoveCallMatcher))))
|
||||
.bind("expr"),
|
||||
this);
|
||||
}
|
||||
|
||||
void OptionalValueConversionCheck::storeOptions(
|
||||
ClangTidyOptions::OptionMap &Opts) {
|
||||
Options.store(Opts, "OptionalTypes",
|
||||
utils::options::serializeStringList(OptionalTypes));
|
||||
Options.store(Opts, "ValueMethods",
|
||||
utils::options::serializeStringList(ValueMethods));
|
||||
}
|
||||
|
||||
void OptionalValueConversionCheck::check(
|
||||
const MatchFinder::MatchResult &Result) {
|
||||
const auto *MatchedExpr = Result.Nodes.getNodeAs<Expr>("expr");
|
||||
const auto *OptionalType = Result.Nodes.getNodeAs<QualType>("optional-type");
|
||||
const auto *ValueType = Result.Nodes.getNodeAs<QualType>("value-type");
|
||||
|
||||
diag(MatchedExpr->getExprLoc(),
|
||||
"conversion from %0 into %1 and back into %0, remove potentially "
|
||||
"error-prone optional dereference")
|
||||
<< *OptionalType << ValueType->getUnqualifiedType();
|
||||
|
||||
if (const auto *OperatorExpr =
|
||||
Result.Nodes.getNodeAs<CXXOperatorCallExpr>("op-call")) {
|
||||
diag(OperatorExpr->getExprLoc(), "remove '*' to silence this warning",
|
||||
DiagnosticIDs::Note)
|
||||
<< FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
|
||||
OperatorExpr->getBeginLoc(), OperatorExpr->getExprLoc()));
|
||||
return;
|
||||
}
|
||||
if (const auto *CallExpr =
|
||||
Result.Nodes.getNodeAs<CXXMemberCallExpr>("member-call")) {
|
||||
const SourceLocation Begin =
|
||||
utils::lexer::getPreviousToken(CallExpr->getExprLoc(),
|
||||
*Result.SourceManager, getLangOpts())
|
||||
.getLocation();
|
||||
auto Diag =
|
||||
diag(CallExpr->getExprLoc(),
|
||||
"remove call to %0 to silence this warning", DiagnosticIDs::Note);
|
||||
Diag << CallExpr->getMethodDecl()
|
||||
<< FixItHint::CreateRemoval(
|
||||
CharSourceRange::getTokenRange(Begin, CallExpr->getEndLoc()));
|
||||
if (const auto *Member =
|
||||
llvm::dyn_cast<MemberExpr>(CallExpr->getCallee()->IgnoreImplicit());
|
||||
Member && Member->isArrow())
|
||||
Diag << FixItHint::CreateInsertion(CallExpr->getBeginLoc(), "*");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace clang::tidy::bugprone
|
||||
@@ -0,0 +1,38 @@
|
||||
//===--- OptionalValueConversionCheck.h - clang-tidy ------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_OPTIONALVALUECONVERSIONCHECK_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_OPTIONALVALUECONVERSIONCHECK_H
|
||||
|
||||
#include "../ClangTidyCheck.h"
|
||||
#include <vector>
|
||||
|
||||
namespace clang::tidy::bugprone {
|
||||
|
||||
/// Detects potentially unintentional and redundant conversions where a value is
|
||||
/// extracted from an optional-like type and then used to create a new instance
|
||||
/// of the same optional-like type.
|
||||
///
|
||||
/// For the user-facing documentation see:
|
||||
/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/optional-value-conversion.html
|
||||
class OptionalValueConversionCheck : public ClangTidyCheck {
|
||||
public:
|
||||
OptionalValueConversionCheck(StringRef Name, ClangTidyContext *Context);
|
||||
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
|
||||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
|
||||
void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
|
||||
std::optional<TraversalKind> getCheckTraversalKind() const override;
|
||||
|
||||
private:
|
||||
std::vector<StringRef> OptionalTypes;
|
||||
std::vector<StringRef> ValueMethods;
|
||||
};
|
||||
|
||||
} // namespace clang::tidy::bugprone
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_OPTIONALVALUECONVERSIONCHECK_H
|
||||
@@ -129,6 +129,13 @@ New checks
|
||||
Detects implicit conversions between pointers of different levels of
|
||||
indirection.
|
||||
|
||||
- New :doc:`bugprone-optional-value-conversion
|
||||
<clang-tidy/checks/bugprone/optional-value-conversion>` check.
|
||||
|
||||
Detects potentially unintentional and redundant conversions where a value is
|
||||
extracted from an optional-like type and then used to create a new instance
|
||||
of the same optional-like type.
|
||||
|
||||
- New :doc:`modernize-use-constraints
|
||||
<clang-tidy/checks/modernize/use-constraints>` check.
|
||||
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
.. title:: clang-tidy - bugprone-optional-value-conversion
|
||||
|
||||
bugprone-optional-value-conversion
|
||||
==================================
|
||||
|
||||
Detects potentially unintentional and redundant conversions where a value is
|
||||
extracted from an optional-like type and then used to create a new instance of
|
||||
the same optional-like type.
|
||||
|
||||
These conversions might be the result of developer oversight, leftovers from
|
||||
code refactoring, or other situations that could lead to unintended exceptions
|
||||
or cases where the resulting optional is always initialized, which might be
|
||||
unexpected behavior.
|
||||
|
||||
To illustrate, consider the following problematic code snippet:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#include <optional>
|
||||
|
||||
void print(std::optional<int>);
|
||||
|
||||
int main()
|
||||
{
|
||||
std::optional<int> opt;
|
||||
// ...
|
||||
|
||||
// Unintentional conversion from std::optional<int> to int and back to
|
||||
// std::optional<int>:
|
||||
print(opt.value());
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
A better approach would be to directly pass ``opt`` to the ``print`` function
|
||||
without extracting its value:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
#include <optional>
|
||||
|
||||
void print(std::optional<int>);
|
||||
|
||||
int main()
|
||||
{
|
||||
std::optional<int> opt;
|
||||
// ...
|
||||
|
||||
// Proposed code: Directly pass the std::optional<int> to the print
|
||||
// function.
|
||||
print(opt);
|
||||
|
||||
// ...
|
||||
}
|
||||
|
||||
By passing ``opt`` directly to the print function, unnecessary conversions are
|
||||
avoided, and potential unintended behavior or exceptions are minimized.
|
||||
|
||||
Value extraction using ``operator *`` is matched by default.
|
||||
The support for non-standard optional types such as ``boost::optional`` or
|
||||
``absl::optional`` may be limited.
|
||||
|
||||
Options:
|
||||
--------
|
||||
|
||||
.. option:: OptionalTypes
|
||||
|
||||
Semicolon-separated list of (fully qualified) optional type names or regular
|
||||
expressions that match the optional types.
|
||||
Default value is `::std::optional;::absl::optional;::boost::optional`.
|
||||
|
||||
.. option:: ValueMethods
|
||||
|
||||
Semicolon-separated list of (fully qualified) method names or regular
|
||||
expressions that match the methods.
|
||||
Default value is `::value$;::get$`.
|
||||
@@ -110,6 +110,7 @@ Clang-Tidy Checks
|
||||
`bugprone-no-escape <bugprone/no-escape.html>`_,
|
||||
`bugprone-non-zero-enum-to-bool-conversion <bugprone/non-zero-enum-to-bool-conversion.html>`_,
|
||||
`bugprone-not-null-terminated-result <bugprone/not-null-terminated-result.html>`_, "Yes"
|
||||
`bugprone-optional-value-conversion <bugprone/optional-value-conversion.html>`_, "Yes"
|
||||
`bugprone-parent-virtual-call <bugprone/parent-virtual-call.html>`_, "Yes"
|
||||
`bugprone-posix-return <bugprone/posix-return.html>`_, "Yes"
|
||||
`bugprone-redundant-branch-condition <bugprone/redundant-branch-condition.html>`_, "Yes"
|
||||
|
||||
@@ -0,0 +1,213 @@
|
||||
// RUN: %check_clang_tidy -std=c++17-or-later %s bugprone-optional-value-conversion %t -- --fix-notes
|
||||
// RUN: %check_clang_tidy -check-suffix=CUSTOM -std=c++17-or-later %s bugprone-optional-value-conversion %t -- \
|
||||
// RUN: -config="{CheckOptions: [{key: 'bugprone-optional-value-conversion.OptionalTypes', value: 'CustomOptional'}, \
|
||||
// RUN: {key: 'bugprone-optional-value-conversion.ValueMethods', value: '::Read$;::Ooo$'}]}" --fix-notes
|
||||
|
||||
namespace std {
|
||||
template<typename T>
|
||||
struct optional
|
||||
{
|
||||
constexpr optional() noexcept;
|
||||
constexpr optional(T&&) noexcept;
|
||||
constexpr optional(const T&) noexcept;
|
||||
template<typename U>
|
||||
constexpr optional(U&&) noexcept;
|
||||
const T& operator*() const;
|
||||
T* operator->();
|
||||
const T* operator->() const;
|
||||
T& operator*();
|
||||
const T& value() const;
|
||||
T& value();
|
||||
const T& get() const;
|
||||
T& get();
|
||||
T value_or(T) const;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
T&& move(T &x) {
|
||||
return static_cast<T&&>(x);
|
||||
}
|
||||
}
|
||||
|
||||
namespace boost {
|
||||
template<typename T>
|
||||
struct optional {
|
||||
constexpr optional() noexcept;
|
||||
constexpr optional(const T&) noexcept;
|
||||
const T& operator*() const;
|
||||
const T& get() const;
|
||||
};
|
||||
}
|
||||
|
||||
namespace absl {
|
||||
template<typename T>
|
||||
struct optional {
|
||||
constexpr optional() noexcept;
|
||||
constexpr optional(const T&) noexcept;
|
||||
const T& operator*() const;
|
||||
const T& value() const;
|
||||
};
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct CustomOptional {
|
||||
CustomOptional();
|
||||
CustomOptional(const T&);
|
||||
const T& Read() const;
|
||||
T& operator*();
|
||||
T& Ooo();
|
||||
};
|
||||
|
||||
void takeOptionalValue(std::optional<int>);
|
||||
void takeOptionalRef(const std::optional<int>&);
|
||||
void takeOptionalRRef(std::optional<int>&&);
|
||||
void takeOtherOptional(std::optional<long>);
|
||||
void takeBOptionalValue(boost::optional<int>);
|
||||
void takeAOptionalValue(absl::optional<int>);
|
||||
|
||||
void incorrect(std::optional<int> param)
|
||||
{
|
||||
std::optional<int>* ptr = ¶m;
|
||||
takeOptionalValue(**ptr);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalValue(*ptr);
|
||||
takeOptionalValue(*param);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalValue(param);
|
||||
takeOptionalValue(param.value());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalValue(param);
|
||||
takeOptionalValue(ptr->value());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalValue(*ptr);
|
||||
takeOptionalValue(param.operator*());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalValue(param);
|
||||
takeOptionalValue(ptr->operator*());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalValue(*ptr);
|
||||
takeOptionalRef(*param);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalRef(param);
|
||||
takeOptionalRef(param.value());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalRef(param);
|
||||
takeOptionalRef(ptr->value());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalRef(*ptr);
|
||||
takeOptionalRef(param.operator*());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalRef(param);
|
||||
takeOptionalRef(ptr->operator*());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalRef(*ptr);
|
||||
std::optional<int> p = *param;
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:26: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: std::optional<int> p = param;
|
||||
|
||||
takeOptionalValue(std::move(**ptr));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalValue(std::move(*ptr));
|
||||
takeOptionalValue(std::move(*param));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalValue(std::move(param));
|
||||
takeOptionalValue(std::move(param.value()));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalValue(std::move(param));
|
||||
takeOptionalValue(std::move(ptr->value()));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalValue(std::move(*ptr));
|
||||
takeOptionalValue(std::move(param.operator*()));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalValue(std::move(param));
|
||||
takeOptionalRef(std::move(*param));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalRef(std::move(param));
|
||||
takeOptionalRef(std::move(param.value()));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalRef(std::move(param));
|
||||
takeOptionalRef(std::move(ptr->value()));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalRef(std::move(*ptr));
|
||||
takeOptionalRef(std::move(param.operator*()));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:19: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalRef(std::move(param));
|
||||
takeOptionalRRef(std::move(*param));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalRRef(std::move(param));
|
||||
takeOptionalRRef(std::move(param.value()));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalRRef(std::move(param));
|
||||
takeOptionalRRef(std::move(ptr->value()));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalRRef(std::move(*ptr));
|
||||
takeOptionalRRef(std::move(param.operator*()));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalRRef(std::move(param));
|
||||
takeOptionalRRef(std::move(ptr->operator*()));
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalRRef(std::move(*ptr));
|
||||
std::optional<int> p2 = std::move(*param);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:27: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: std::optional<int> p2 = std::move(param);
|
||||
|
||||
std::optional<std::optional<int>> opt;
|
||||
takeOptionalValue(opt->value());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalValue(*opt);
|
||||
takeOptionalValue(opt->operator*());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:21: warning: conversion from 'std::optional<int>' into 'int' and back into 'std::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeOptionalValue(*opt);
|
||||
|
||||
boost::optional<int> bopt;
|
||||
takeBOptionalValue(*bopt);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: conversion from 'boost::optional<int>' into 'int' and back into 'boost::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeBOptionalValue(bopt);
|
||||
takeBOptionalValue(bopt.get());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: conversion from 'boost::optional<int>' into 'int' and back into 'boost::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeBOptionalValue(bopt);
|
||||
|
||||
absl::optional<int> aopt;
|
||||
takeAOptionalValue(*aopt);
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: conversion from 'absl::optional<int>' into 'int' and back into 'absl::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeAOptionalValue(aopt);
|
||||
takeAOptionalValue(aopt.value());
|
||||
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: conversion from 'absl::optional<int>' into 'int' and back into 'absl::optional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES: takeAOptionalValue(aopt);
|
||||
}
|
||||
|
||||
void takeCustom(const CustomOptional<int>&);
|
||||
|
||||
void testCustom(CustomOptional<int> param) {
|
||||
takeCustom(*param);
|
||||
// CHECK-MESSAGES-CUSTOM: :[[@LINE-1]]:14: warning: conversion from 'CustomOptional<int>' into 'int' and back into 'CustomOptional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES-CUSTOM: takeCustom(param);
|
||||
takeCustom(param.Read());
|
||||
// CHECK-MESSAGES-CUSTOM: :[[@LINE-1]]:14: warning: conversion from 'CustomOptional<int>' into 'int' and back into 'CustomOptional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES-CUSTOM: takeCustom(param);
|
||||
takeCustom(param.Ooo());
|
||||
// CHECK-MESSAGES-CUSTOM: :[[@LINE-1]]:14: warning: conversion from 'CustomOptional<int>' into 'int' and back into 'CustomOptional<int>', remove potentially error-prone optional dereference [bugprone-optional-value-conversion]
|
||||
// CHECK-FIXES-CUSTOM: takeCustom(param);
|
||||
}
|
||||
|
||||
void correct(std::optional<int> param)
|
||||
{
|
||||
takeOtherOptional(*param);
|
||||
takeOtherOptional(param.value());
|
||||
takeOtherOptional(param.value_or(5U));
|
||||
takeOtherOptional(param.operator*());
|
||||
|
||||
std::optional<long> p = *param;
|
||||
takeOptionalValue(param.value_or(5U));
|
||||
takeOptionalRef(param.value_or(5U));
|
||||
|
||||
std::optional<int>* ptr = ¶m;
|
||||
takeOtherOptional(**ptr);
|
||||
takeOtherOptional(ptr->value());
|
||||
takeOtherOptional(ptr->value_or(5U));
|
||||
takeOtherOptional(ptr->operator*());
|
||||
|
||||
std::optional<long>* p2 = &p;
|
||||
takeOptionalValue(p2->value_or(5U));
|
||||
takeOptionalRef(p2->value_or(5U));
|
||||
}
|
||||
Reference in New Issue
Block a user