Skip to content

Commit

Permalink
[clang-tidy] Fix false-positive in readability-container-size-empty
Browse files Browse the repository at this point in the history
Ignoring std::array type when matching 'std:array == std::array()'.
In such case we shouldn't propose to use empty().

Fixes: #48286

Differential Revision: https://reviews.llvm.org/D144217
  • Loading branch information
PiotrZSL committed Feb 25, 2023
1 parent 6935dab commit e08cc52
Show file tree
Hide file tree
Showing 5 changed files with 139 additions and 43 deletions.
Expand Up @@ -8,6 +8,7 @@
#include "ContainerSizeEmptyCheck.h"
#include "../utils/ASTUtils.h"
#include "../utils/Matchers.h"
#include "../utils/OptionsUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchers.h"
#include "clang/Lex/Lexer.h"
Expand All @@ -17,6 +18,7 @@ using namespace clang::ast_matchers;

namespace clang {
namespace ast_matchers {

AST_POLYMORPHIC_MATCHER_P2(hasAnyArgumentWithParam,
AST_POLYMORPHIC_SUPPORTED_TYPES(CallExpr,
CXXConstructExpr),
Expand Down Expand Up @@ -83,20 +85,30 @@ AST_MATCHER(Expr, usedInBooleanContext) {
});
return Result;
}

AST_MATCHER(CXXConstructExpr, isDefaultConstruction) {
return Node.getConstructor()->isDefaultConstructor();
}

AST_MATCHER(QualType, isIntegralType) {
return Node->isIntegralType(Finder->getASTContext());
}

} // namespace ast_matchers
namespace tidy::readability {

using utils::isBinaryOrTernary;

ContainerSizeEmptyCheck::ContainerSizeEmptyCheck(StringRef Name,
ClangTidyContext *Context)
: ClangTidyCheck(Name, Context) {}
: ClangTidyCheck(Name, Context),
ExcludedComparisonTypes(utils::options::parseStringList(
Options.get("ExcludedComparisonTypes", "::std::array"))) {}

void ContainerSizeEmptyCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
Options.store(Opts, "ExcludedComparisonTypes",
utils::options::serializeStringList(ExcludedComparisonTypes));
}

void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
const auto ValidContainerRecord = cxxRecordDecl(isSameOrDerivedFrom(
Expand Down Expand Up @@ -164,12 +176,26 @@ void ContainerSizeEmptyCheck::registerMatchers(MatchFinder *Finder) {
hasUnaryOperand(
expr(hasType(pointsTo(ValidContainer))).bind("Pointee"))),
expr(hasType(ValidContainer)).bind("STLObject"));

const auto ExcludedComparisonTypesMatcher = qualType(anyOf(
hasDeclaration(
cxxRecordDecl(matchers::matchesAnyListedName(ExcludedComparisonTypes))
.bind("excluded")),
hasCanonicalType(hasDeclaration(
cxxRecordDecl(matchers::matchesAnyListedName(ExcludedComparisonTypes))
.bind("excluded")))));
const auto SameExcludedComparisonTypesMatcher =
qualType(anyOf(hasDeclaration(cxxRecordDecl(equalsBoundNode("excluded"))),
hasCanonicalType(hasDeclaration(
cxxRecordDecl(equalsBoundNode("excluded"))))));

Finder->addMatcher(
binaryOperation(hasAnyOperatorName("==", "!="),
hasOperands(WrongComparend,
STLArg),
unless(hasAncestor(cxxMethodDecl(
ofClass(equalsBoundNode("container"))))))
binaryOperation(
hasAnyOperatorName("==", "!="), hasOperands(WrongComparend, STLArg),
unless(allOf(hasLHS(hasType(ExcludedComparisonTypesMatcher)),
hasRHS(hasType(SameExcludedComparisonTypesMatcher)))),
unless(hasAncestor(
cxxMethodDecl(ofClass(equalsBoundNode("container"))))))
.bind("BinCmp"),
this);
}
Expand Down
Expand Up @@ -10,6 +10,7 @@
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_CONTAINERSIZEEMPTYCHECK_H

#include "../ClangTidyCheck.h"
#include <vector>

namespace clang::tidy::readability {

Expand All @@ -31,9 +32,13 @@ class ContainerSizeEmptyCheck : public ClangTidyCheck {
}
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 {
return TK_IgnoreUnlessSpelledInSource;
}

private:
std::vector<llvm::StringRef> ExcludedComparisonTypes;
};

} // namespace clang::tidy::readability
Expand Down
5 changes: 5 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Expand Up @@ -173,6 +173,11 @@ Changes in existing checks
:doc:`readability-identifier-naming
<clang-tidy/checks/readability/identifier-naming>` check.

- Fixed a false positive in :doc:`readability-container-size-empty
<clang-tidy/checks/readability/container-size-empty>` check when comparing
``std::array`` objects to default constructed ones. The behavior for this and
other relevant classes can now be configured with a new option.

Removed checks
^^^^^^^^^^^^^^

Expand Down
Expand Up @@ -24,3 +24,11 @@ matching following signatures:
bool empty() const;

`size_type` can be any kind of integer type.

.. option:: ExcludedComparisonTypes

A semicolon-separated list of class names for which the check will ignore
comparisons of objects with default-constructed objects of the same type.
If a class is listed here, the check will not suggest using ``empty()``
instead of such comparisons for objects of that class.
Default value is: `::std::array`.

0 comments on commit e08cc52

Please sign in to comment.