mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2025-04-17 13:51:21 +00:00
[Clang-Tidy] Empty Check
Adds a clang-tidy check for the incorrect use of `empty()` on a container when the result of the call is ignored. Authored-by: Abraham Corea Diaz <abrahamcd@google.com> Co-authored-by: Denis Nikitin <denik@google.com> Reviewed By: cjdb Differential Revision: https://reviews.llvm.org/D128372
This commit is contained in:
parent
106a99276f
commit
ec3f8feddf
@ -49,6 +49,7 @@
|
||||
#include "SizeofContainerCheck.h"
|
||||
#include "SizeofExpressionCheck.h"
|
||||
#include "SpuriouslyWakeUpFunctionsCheck.h"
|
||||
#include "StandaloneEmptyCheck.h"
|
||||
#include "StringConstructorCheck.h"
|
||||
#include "StringIntegerAssignmentCheck.h"
|
||||
#include "StringLiteralWithEmbeddedNulCheck.h"
|
||||
@ -156,6 +157,8 @@ public:
|
||||
"bugprone-sizeof-expression");
|
||||
CheckFactories.registerCheck<SpuriouslyWakeUpFunctionsCheck>(
|
||||
"bugprone-spuriously-wake-up-functions");
|
||||
CheckFactories.registerCheck<StandaloneEmptyCheck>(
|
||||
"bugprone-standalone-empty");
|
||||
CheckFactories.registerCheck<StringConstructorCheck>(
|
||||
"bugprone-string-constructor");
|
||||
CheckFactories.registerCheck<StringIntegerAssignmentCheck>(
|
||||
|
@ -45,6 +45,7 @@ add_clang_library(clangTidyBugproneModule
|
||||
SizeofContainerCheck.cpp
|
||||
SizeofExpressionCheck.cpp
|
||||
SpuriouslyWakeUpFunctionsCheck.cpp
|
||||
StandaloneEmptyCheck.cpp
|
||||
StringConstructorCheck.cpp
|
||||
StringIntegerAssignmentCheck.cpp
|
||||
StringLiteralWithEmbeddedNulCheck.cpp
|
||||
|
207
clang-tools-extra/clang-tidy/bugprone/StandaloneEmptyCheck.cpp
Normal file
207
clang-tools-extra/clang-tidy/bugprone/StandaloneEmptyCheck.cpp
Normal file
@ -0,0 +1,207 @@
|
||||
//===--- StandaloneEmptyCheck.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 "StandaloneEmptyCheck.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
#include "clang/AST/Decl.h"
|
||||
#include "clang/AST/DeclBase.h"
|
||||
#include "clang/AST/DeclCXX.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprCXX.h"
|
||||
#include "clang/AST/Stmt.h"
|
||||
#include "clang/AST/Type.h"
|
||||
#include "clang/ASTMatchers/ASTMatchFinder.h"
|
||||
#include "clang/ASTMatchers/ASTMatchers.h"
|
||||
#include "clang/Basic/Diagnostic.h"
|
||||
#include "clang/Basic/SourceLocation.h"
|
||||
#include "clang/Lex/Lexer.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/ADT/STLExtras.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/Support/Casting.h"
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
namespace bugprone {
|
||||
|
||||
using ast_matchers::BoundNodes;
|
||||
using ast_matchers::callee;
|
||||
using ast_matchers::callExpr;
|
||||
using ast_matchers::cxxMemberCallExpr;
|
||||
using ast_matchers::cxxMethodDecl;
|
||||
using ast_matchers::expr;
|
||||
using ast_matchers::functionDecl;
|
||||
using ast_matchers::hasName;
|
||||
using ast_matchers::hasParent;
|
||||
using ast_matchers::ignoringImplicit;
|
||||
using ast_matchers::ignoringParenImpCasts;
|
||||
using ast_matchers::MatchFinder;
|
||||
using ast_matchers::optionally;
|
||||
using ast_matchers::returns;
|
||||
using ast_matchers::stmt;
|
||||
using ast_matchers::stmtExpr;
|
||||
using ast_matchers::unless;
|
||||
using ast_matchers::voidType;
|
||||
|
||||
const Expr *getCondition(const BoundNodes &Nodes, const StringRef NodeId) {
|
||||
const auto *If = Nodes.getNodeAs<IfStmt>(NodeId);
|
||||
if (If != nullptr)
|
||||
return If->getCond();
|
||||
|
||||
const auto *For = Nodes.getNodeAs<ForStmt>(NodeId);
|
||||
if (For != nullptr)
|
||||
return For->getCond();
|
||||
|
||||
const auto *While = Nodes.getNodeAs<WhileStmt>(NodeId);
|
||||
if (While != nullptr)
|
||||
return While->getCond();
|
||||
|
||||
const auto *Do = Nodes.getNodeAs<DoStmt>(NodeId);
|
||||
if (Do != nullptr)
|
||||
return Do->getCond();
|
||||
|
||||
const auto *Switch = Nodes.getNodeAs<SwitchStmt>(NodeId);
|
||||
if (Switch != nullptr)
|
||||
return Switch->getCond();
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void StandaloneEmptyCheck::registerMatchers(ast_matchers::MatchFinder *Finder) {
|
||||
const auto NonMemberMatcher = expr(ignoringImplicit(ignoringParenImpCasts(
|
||||
callExpr(
|
||||
hasParent(stmt(optionally(hasParent(stmtExpr().bind("stexpr"))))
|
||||
.bind("parent")),
|
||||
callee(functionDecl(hasName("empty"), unless(returns(voidType())))))
|
||||
.bind("empty"))));
|
||||
const auto MemberMatcher =
|
||||
expr(ignoringImplicit(ignoringParenImpCasts(cxxMemberCallExpr(
|
||||
hasParent(stmt(optionally(hasParent(stmtExpr().bind("stexpr"))))
|
||||
.bind("parent")),
|
||||
callee(cxxMethodDecl(hasName("empty"),
|
||||
unless(returns(voidType()))))))))
|
||||
.bind("empty");
|
||||
|
||||
Finder->addMatcher(MemberMatcher, this);
|
||||
Finder->addMatcher(NonMemberMatcher, this);
|
||||
}
|
||||
|
||||
void StandaloneEmptyCheck::check(const MatchFinder::MatchResult &Result) {
|
||||
// Skip if the parent node is Expr.
|
||||
if (Result.Nodes.getNodeAs<Expr>("parent"))
|
||||
return;
|
||||
|
||||
const auto PParentStmtExpr = Result.Nodes.getNodeAs<Expr>("stexpr");
|
||||
const auto ParentCompStmt = Result.Nodes.getNodeAs<CompoundStmt>("parent");
|
||||
const auto *ParentCond = getCondition(Result.Nodes, "parent");
|
||||
|
||||
if (const auto *MemberCall =
|
||||
Result.Nodes.getNodeAs<CXXMemberCallExpr>("empty")) {
|
||||
// Skip if it's a condition of the parent statement.
|
||||
if (ParentCond == MemberCall->getExprStmt())
|
||||
return;
|
||||
// Skip if it's the last statement in the GNU extension
|
||||
// statement expression.
|
||||
if (PParentStmtExpr && ParentCompStmt &&
|
||||
ParentCompStmt->body_back() == MemberCall->getExprStmt())
|
||||
return;
|
||||
|
||||
SourceLocation MemberLoc = MemberCall->getBeginLoc();
|
||||
SourceLocation ReplacementLoc = MemberCall->getExprLoc();
|
||||
SourceRange ReplacementRange = SourceRange(ReplacementLoc, ReplacementLoc);
|
||||
|
||||
ASTContext &Context = MemberCall->getRecordDecl()->getASTContext();
|
||||
DeclarationName Name =
|
||||
Context.DeclarationNames.getIdentifier(&Context.Idents.get("clear"));
|
||||
|
||||
auto Candidates = MemberCall->getRecordDecl()->lookupDependentName(
|
||||
Name, [](const NamedDecl *ND) {
|
||||
return isa<CXXMethodDecl>(ND) &&
|
||||
llvm::cast<CXXMethodDecl>(ND)->getMinRequiredArguments() ==
|
||||
0 &&
|
||||
!llvm::cast<CXXMethodDecl>(ND)->isConst();
|
||||
});
|
||||
|
||||
bool HasClear = !Candidates.empty();
|
||||
if (HasClear) {
|
||||
const CXXMethodDecl *Clear = llvm::cast<CXXMethodDecl>(Candidates.at(0));
|
||||
QualType RangeType = MemberCall->getImplicitObjectArgument()->getType();
|
||||
bool QualifierIncompatible =
|
||||
(!Clear->isVolatile() && RangeType.isVolatileQualified()) ||
|
||||
RangeType.isConstQualified();
|
||||
if (!QualifierIncompatible) {
|
||||
diag(MemberLoc,
|
||||
"ignoring the result of 'empty()'; did you mean 'clear()'? ")
|
||||
<< FixItHint::CreateReplacement(ReplacementRange, "clear");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
diag(MemberLoc, "ignoring the result of 'empty()'");
|
||||
|
||||
} else if (const auto *NonMemberCall =
|
||||
Result.Nodes.getNodeAs<CallExpr>("empty")) {
|
||||
if (ParentCond == NonMemberCall->getExprStmt())
|
||||
return;
|
||||
if (PParentStmtExpr && ParentCompStmt &&
|
||||
ParentCompStmt->body_back() == NonMemberCall->getExprStmt())
|
||||
return;
|
||||
|
||||
SourceLocation NonMemberLoc = NonMemberCall->getExprLoc();
|
||||
SourceLocation NonMemberEndLoc = NonMemberCall->getEndLoc();
|
||||
|
||||
const Expr *Arg = NonMemberCall->getArg(0);
|
||||
CXXRecordDecl *ArgRecordDecl = Arg->getType()->getAsCXXRecordDecl();
|
||||
if (ArgRecordDecl == nullptr)
|
||||
return;
|
||||
|
||||
ASTContext &Context = ArgRecordDecl->getASTContext();
|
||||
DeclarationName Name =
|
||||
Context.DeclarationNames.getIdentifier(&Context.Idents.get("clear"));
|
||||
|
||||
auto Candidates =
|
||||
ArgRecordDecl->lookupDependentName(Name, [](const NamedDecl *ND) {
|
||||
return isa<CXXMethodDecl>(ND) &&
|
||||
llvm::cast<CXXMethodDecl>(ND)->getMinRequiredArguments() ==
|
||||
0 &&
|
||||
!llvm::cast<CXXMethodDecl>(ND)->isConst();
|
||||
});
|
||||
|
||||
bool HasClear = !Candidates.empty();
|
||||
|
||||
if (HasClear) {
|
||||
const CXXMethodDecl *Clear = llvm::cast<CXXMethodDecl>(Candidates.at(0));
|
||||
bool QualifierIncompatible =
|
||||
(!Clear->isVolatile() && Arg->getType().isVolatileQualified()) ||
|
||||
Arg->getType().isConstQualified();
|
||||
if (!QualifierIncompatible) {
|
||||
std::string ReplacementText =
|
||||
std::string(Lexer::getSourceText(
|
||||
CharSourceRange::getTokenRange(Arg->getSourceRange()),
|
||||
*Result.SourceManager, getLangOpts())) +
|
||||
".clear()";
|
||||
SourceRange ReplacementRange =
|
||||
SourceRange(NonMemberLoc, NonMemberEndLoc);
|
||||
diag(NonMemberLoc,
|
||||
"ignoring the result of '%0'; did you mean 'clear()'?")
|
||||
<< llvm::dyn_cast<NamedDecl>(NonMemberCall->getCalleeDecl())
|
||||
->getQualifiedNameAsString()
|
||||
<< FixItHint::CreateReplacement(ReplacementRange, ReplacementText);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
diag(NonMemberLoc, "ignoring the result of '%0'")
|
||||
<< llvm::dyn_cast<NamedDecl>(NonMemberCall->getCalleeDecl())
|
||||
->getQualifiedNameAsString();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace bugprone
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
38
clang-tools-extra/clang-tidy/bugprone/StandaloneEmptyCheck.h
Normal file
38
clang-tools-extra/clang-tidy/bugprone/StandaloneEmptyCheck.h
Normal file
@ -0,0 +1,38 @@
|
||||
//===--- StandaloneEmptyCheck.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_STANDALONEEMPTYCHECK_H
|
||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STANDALONEEMPTYCHECK_H
|
||||
|
||||
#include "../ClangTidyCheck.h"
|
||||
|
||||
namespace clang {
|
||||
namespace tidy {
|
||||
namespace bugprone {
|
||||
|
||||
/// Checks for ignored calls to `empty()` on a range and suggests `clear()`
|
||||
/// as an alternative if it is an existing member function.
|
||||
///
|
||||
/// For the user-facing documentation see:
|
||||
/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/standalone-empty.html
|
||||
class StandaloneEmptyCheck : public ClangTidyCheck {
|
||||
public:
|
||||
StandaloneEmptyCheck(StringRef Name, ClangTidyContext *Context)
|
||||
: ClangTidyCheck(Name, Context) {}
|
||||
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
|
||||
return LangOpts.CPlusPlus;
|
||||
}
|
||||
void registerMatchers(ast_matchers::MatchFinder *Finder) override;
|
||||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
|
||||
};
|
||||
|
||||
} // namespace bugprone
|
||||
} // namespace tidy
|
||||
} // namespace clang
|
||||
|
||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_STANDALONEEMPTYCHECK_H
|
@ -121,6 +121,11 @@ New checks
|
||||
Warns when using ``static`` function or variables at global scope, and suggests
|
||||
moving them into an anonymous namespace.
|
||||
|
||||
- New :doc:`bugprone-standalone-empty <clang-tidy/checks/bugprone/standalone-empty>` check.
|
||||
|
||||
Warns when `empty()` is used on a range and the result is ignored. Suggests `clear()`
|
||||
if it is an existing member function.
|
||||
|
||||
New check aliases
|
||||
^^^^^^^^^^^^^^^^^
|
||||
|
||||
|
@ -0,0 +1,31 @@
|
||||
.. title:: clang-tidy - bugprone-standalone-empty
|
||||
|
||||
bugprone-standalone-empty
|
||||
=========================
|
||||
|
||||
Warns when `empty()` is used on a range and the result is ignored. Suggests
|
||||
`clear()` if it is an existing member function.
|
||||
|
||||
The ``empty()`` method on several common ranges returns a Boolean indicating
|
||||
whether or not the range is empty, but is often mistakenly interpreted as
|
||||
a way to clear the contents of a range. Some ranges offer a ``clear()``
|
||||
method for this purpose. This check warns when a call to empty returns a
|
||||
result that is ignored, and suggests replacing it with a call to ``clear()``
|
||||
if it is available as a member function of the range.
|
||||
|
||||
For example, the following code could be used to indicate whether a range
|
||||
is empty or not, but the result is ignored:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
std::vector<int> v;
|
||||
...
|
||||
v.empty();
|
||||
|
||||
A call to ``clear()`` would appropriately clear the contents of the range:
|
||||
|
||||
.. code-block:: c++
|
||||
|
||||
std::vector<int> v;
|
||||
...
|
||||
v.clear();
|
@ -115,6 +115,7 @@ Clang-Tidy Checks
|
||||
`bugprone-sizeof-container <bugprone/sizeof-container.html>`_,
|
||||
`bugprone-sizeof-expression <bugprone/sizeof-expression.html>`_,
|
||||
`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions.html>`_,
|
||||
`bugprone-standalone-empty <bugprone/standalone-empty.html>`_, "Yes"
|
||||
`bugprone-string-constructor <bugprone/string-constructor.html>`_, "Yes"
|
||||
`bugprone-string-integer-assignment <bugprone/string-integer-assignment.html>`_, "Yes"
|
||||
`bugprone-string-literal-with-embedded-nul <bugprone/string-literal-with-embedded-nul.html>`_,
|
||||
|
@ -0,0 +1,578 @@
|
||||
// RUN: %check_clang_tidy %s bugprone-standalone-empty %t
|
||||
|
||||
namespace std {
|
||||
template <typename T>
|
||||
struct vector {
|
||||
bool empty();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct vector_with_clear {
|
||||
bool empty();
|
||||
void clear();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct vector_with_void_empty {
|
||||
void empty();
|
||||
void clear();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct vector_with_int_empty {
|
||||
int empty();
|
||||
void clear();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct vector_with_clear_args {
|
||||
bool empty();
|
||||
void clear(int i);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct vector_with_clear_variable {
|
||||
bool empty();
|
||||
int clear;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
bool empty(T &&);
|
||||
|
||||
} // namespace std
|
||||
|
||||
namespace absl {
|
||||
struct string {
|
||||
bool empty();
|
||||
};
|
||||
|
||||
struct string_with_clear {
|
||||
bool empty();
|
||||
void clear();
|
||||
};
|
||||
|
||||
struct string_with_void_empty {
|
||||
void empty();
|
||||
void clear();
|
||||
};
|
||||
|
||||
struct string_with_int_empty {
|
||||
int empty();
|
||||
void clear();
|
||||
};
|
||||
|
||||
struct string_with_clear_args {
|
||||
bool empty();
|
||||
void clear(int i);
|
||||
};
|
||||
|
||||
struct string_with_clear_variable {
|
||||
bool empty();
|
||||
int clear;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
bool empty(T &&);
|
||||
} // namespace absl
|
||||
|
||||
namespace test {
|
||||
template <class T>
|
||||
void empty(T &&);
|
||||
} // namespace test
|
||||
|
||||
namespace base {
|
||||
template <typename T>
|
||||
struct base_vector {
|
||||
void clear();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct base_vector_clear_with_args {
|
||||
void clear(int i);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct base_vector_clear_variable {
|
||||
int clear;
|
||||
};
|
||||
|
||||
struct base_vector_non_dependent {
|
||||
void clear();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct vector : base_vector<T> {
|
||||
bool empty();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct vector_clear_with_args : base_vector_clear_with_args<T> {
|
||||
bool empty();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct vector_clear_variable : base_vector_clear_variable<T> {
|
||||
bool empty();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct vector_non_dependent : base_vector_non_dependent {
|
||||
bool empty();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
bool empty(T &&);
|
||||
|
||||
} // namespace base
|
||||
|
||||
namespace qualifiers {
|
||||
template <typename T>
|
||||
struct vector_with_const_clear {
|
||||
bool empty() const;
|
||||
void clear() const;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct vector_with_const_empty {
|
||||
bool empty() const;
|
||||
void clear();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct vector_with_volatile_clear {
|
||||
bool empty() volatile;
|
||||
void clear() volatile;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct vector_with_volatile_empty {
|
||||
bool empty() volatile;
|
||||
void clear();
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
bool empty(T &&);
|
||||
} // namespace qualifiers
|
||||
|
||||
|
||||
void test_member_empty() {
|
||||
{
|
||||
std::vector<int> v;
|
||||
v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
std::vector_with_void_empty<int> v;
|
||||
v.empty();
|
||||
// no-warning
|
||||
}
|
||||
|
||||
{
|
||||
std::vector_with_clear<int> v;
|
||||
v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} v.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector_with_int_empty<int> v;
|
||||
v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} v.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector_with_clear_args<int> v;
|
||||
v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
std::vector_with_clear_variable<int> v;
|
||||
v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
absl::string s;
|
||||
s.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
absl::string_with_void_empty s;
|
||||
s.empty();
|
||||
// no-warning
|
||||
}
|
||||
|
||||
{
|
||||
absl::string_with_clear s;
|
||||
s.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} s.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
absl::string_with_int_empty s;
|
||||
s.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} s.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
absl::string_with_clear_args s;
|
||||
s.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
absl::string_with_clear_variable s;
|
||||
s.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
}
|
||||
}
|
||||
|
||||
void test_qualified_empty() {
|
||||
{
|
||||
absl::string_with_clear v;
|
||||
std::empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'std::empty'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} v.clear();{{$}}
|
||||
|
||||
absl::empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'absl::empty'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} v.clear();{{$}}
|
||||
|
||||
test::empty(v);
|
||||
// no-warning
|
||||
}
|
||||
|
||||
{
|
||||
absl::string s;
|
||||
std::empty(s);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'std::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
std::empty(0);
|
||||
// no-warning
|
||||
absl::empty(nullptr);
|
||||
// no-warning
|
||||
}
|
||||
}
|
||||
|
||||
void test_unqualified_empty() {
|
||||
{
|
||||
std::vector<int> v;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'std::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
std::vector_with_void_empty<int> v;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'std::empty'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} v.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector_with_clear<int> v;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'std::empty'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} v.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector_with_int_empty<int> v;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'std::empty'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} v.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
std::vector_with_clear_args<int> v;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'std::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
std::vector_with_clear_variable<int> v;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'std::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
absl::string s;
|
||||
empty(s);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'absl::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
absl::string_with_void_empty s;
|
||||
empty(s);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'absl::empty'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} s.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
absl::string_with_clear s;
|
||||
empty(s);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'absl::empty'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} s.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
absl::string_with_int_empty s;
|
||||
empty(s);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'absl::empty'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} s.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
absl::string_with_clear_args s;
|
||||
empty(s);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'absl::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
absl::string_with_clear_variable s;
|
||||
empty(s);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'absl::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<int> v;
|
||||
using std::empty;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'std::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
std::vector_with_clear<int> v;
|
||||
using std::empty;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'std::empty'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} v.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
absl::string s;
|
||||
using absl::empty;
|
||||
empty(s);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'absl::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
absl::string_with_clear s;
|
||||
using absl::empty;
|
||||
empty(s);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'absl::empty'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} s.clear();{{$}}
|
||||
}
|
||||
}
|
||||
|
||||
void test_empty_method_expressions() {
|
||||
std::vector<int> v;
|
||||
bool EmptyReturn(v.empty());
|
||||
// no-warning
|
||||
|
||||
(void)v.empty();
|
||||
// no-warning
|
||||
|
||||
// Don't warn in the if condition.
|
||||
if (v.empty()) v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:18: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
|
||||
// Don't warn in the for condition.
|
||||
for(v.empty();v.empty();v.empty()) v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:7: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
// CHECK-MESSAGES: :[[#@LINE-2]]:27: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
// CHECK-MESSAGES: :[[#@LINE-3]]:38: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
|
||||
// Don't warn in the while condition.
|
||||
while(v.empty()) v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:20: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
|
||||
// Don't warn in the do-while condition.
|
||||
do v.empty(); while(v.empty());
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:6: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
|
||||
// Don't warn in the switch expression.
|
||||
switch(v.empty()) {
|
||||
// no-warning
|
||||
case true:
|
||||
v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:7: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
// Don't warn in the return expression, which is the last statement.
|
||||
bool StmtExprReturn = ({v.empty(); v.empty();});
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:27: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
void test_empty_expressions() {
|
||||
absl::string s;
|
||||
bool test(std::empty(s));
|
||||
// no-warning
|
||||
|
||||
(void)std::empty(s);
|
||||
// no-warning
|
||||
|
||||
if (std::empty(s)) std::empty(s);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:22: warning: ignoring the result of 'std::empty' [bugprone-standalone-empty]
|
||||
|
||||
for(std::empty(s);std::empty(s);std::empty(s)) std::empty(s);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:7: warning: ignoring the result of 'std::empty' [bugprone-standalone-empty]
|
||||
// CHECK-MESSAGES: :[[#@LINE-2]]:35: warning: ignoring the result of 'std::empty' [bugprone-standalone-empty]
|
||||
// CHECK-MESSAGES: :[[#@LINE-3]]:50: warning: ignoring the result of 'std::empty' [bugprone-standalone-empty]
|
||||
|
||||
while(std::empty(s)) std::empty(s);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:24: warning: ignoring the result of 'std::empty' [bugprone-standalone-empty]
|
||||
|
||||
do std::empty(s); while(std::empty(s));
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:6: warning: ignoring the result of 'std::empty' [bugprone-standalone-empty]
|
||||
|
||||
switch(std::empty(s)) {
|
||||
// no-warning
|
||||
case true:
|
||||
std::empty(s);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:7: warning: ignoring the result of 'std::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
bool StmtExprReturn = ({std::empty(s); std::empty(s);});
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:27: warning: ignoring the result of 'std::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
void test_clear_in_base_class() {
|
||||
|
||||
{
|
||||
base::vector<int> v;
|
||||
v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} v.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
base::vector_non_dependent<int> v;
|
||||
v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} v.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
base::vector_clear_with_args<int> v;
|
||||
v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
base::vector_clear_variable<int> v;
|
||||
v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
base::vector<int> v;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'base::empty'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} v.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
base::vector_non_dependent<int> v;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'base::empty'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} v.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
base::vector_clear_with_args<int> v;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'base::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
base::vector_clear_variable<int> v;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'base::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
}
|
||||
|
||||
void test_clear_with_qualifiers() {
|
||||
{
|
||||
qualifiers::vector_with_const_clear<int> v;
|
||||
v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
const qualifiers::vector_with_const_clear<int> v;
|
||||
v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
const qualifiers::vector_with_const_empty<int> v;
|
||||
v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
qualifiers::vector_with_const_clear<int> v;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'qualifiers::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
const qualifiers::vector_with_const_clear<int> v;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'qualifiers::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
const std::vector_with_clear<int> v;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'std::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
qualifiers::vector_with_volatile_clear<int> v;
|
||||
v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} v.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
volatile qualifiers::vector_with_volatile_clear<int> v;
|
||||
v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} v.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
volatile qualifiers::vector_with_volatile_empty<int> v;
|
||||
v.empty();
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'empty()' [bugprone-standalone-empty]
|
||||
}
|
||||
|
||||
{
|
||||
qualifiers::vector_with_volatile_clear<int> v;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'qualifiers::empty'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} v.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
volatile qualifiers::vector_with_volatile_clear<int> v;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'qualifiers::empty'; did you mean 'clear()'? [bugprone-standalone-empty]
|
||||
// CHECK-FIXES: {{^ }} v.clear();{{$}}
|
||||
}
|
||||
|
||||
{
|
||||
volatile std::vector_with_clear<int> v;
|
||||
empty(v);
|
||||
// CHECK-MESSAGES: :[[#@LINE-1]]:5: warning: ignoring the result of 'std::empty' [bugprone-standalone-empty]
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user