================ @@ -0,0 +1,221 @@ +//===----------------------------------------------------------------------===// +// +// 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 "MissingEndComparisonCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" +#include "clang/Tooling/FixIt.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::bugprone { + +namespace { + +constexpr llvm::StringRef IteratorAlgorithms[] = { + "::std::find", "::std::find_if", + "::std::find_if_not", "::std::search", + "::std::search_n", "::std::find_end", + "::std::find_first_of", "::std::lower_bound", + "::std::upper_bound", "::std::partition_point", + "::std::min_element", "::std::max_element", + "::std::adjacent_find", "::std::is_sorted_until"}; + +constexpr llvm::StringRef RangeAlgorithms[] = { + "::std::ranges::find", "::std::ranges::find_if", + "::std::ranges::find_if_not", "::std::ranges::lower_bound", + "::std::ranges::upper_bound", "::std::ranges::min_element", + "::std::ranges::max_element", "::std::ranges::find_first_of", + "::std::ranges::adjacent_find", "::std::ranges::is_sorted_until"}; + +AST_MATCHER(DeclStmt, isConditionVariableStatement) { + return !match( + declStmt(hasAncestor(stmt(anyOf( + ifStmt(hasConditionVariableStatement(equalsNode(&Node))), + whileStmt(hasConditionVariableStatement(equalsNode(&Node))), + forStmt(hasConditionVariableStatement(equalsNode(&Node))))))), + Node, Finder->getASTContext()) + .empty(); +} + +} // namespace + +void MissingEndComparisonCheck::registerMatchers(MatchFinder *Finder) { + const auto StdAlgoCall = callExpr( + callee(functionDecl(hasAnyName(IteratorAlgorithms), isInStdNamespace()))); + + const auto RangesCall = cxxOperatorCallExpr( + hasOverloadedOperatorName("()"), + hasArgument(0, declRefExpr(to( + varDecl(hasAnyName(RangeAlgorithms)).bind("cpo"))))); + + const auto AnyAlgoCall = + getLangOpts().CPlusPlus20 + ? expr(anyOf(StdAlgoCall, RangesCall)).bind("algoCall") + : expr(StdAlgoCall).bind("algoCall"); + + // Captures implicit pointer-to-bool casts and operator bool() calls. + const auto IsBoolUsage = anyOf( + implicitCastExpr(hasCastKind(CK_PointerToBoolean), + hasSourceExpression(ignoringParenImpCasts(AnyAlgoCall))), + cxxMemberCallExpr(callee(cxxConversionDecl(returns(booleanType()))), + on(ignoringParenImpCasts(AnyAlgoCall)))); + + // Captures variable usage: `auto it = std::find(...); if (it)` + // FIXME: This only handles variables initialized directly by the algorithm. + // We may need to introduce more accurate dataflow analysis in the future. + const auto VarWithAlgoInit = + varDecl(hasInitializer(ignoringParenImpCasts(AnyAlgoCall))) + .bind("initVar"); + + const auto IsVariableBoolUsage = + anyOf(implicitCastExpr(hasCastKind(CK_PointerToBoolean), + hasSourceExpression(ignoringParenImpCasts( + declRefExpr(to(VarWithAlgoInit))))), + cxxMemberCallExpr( + callee(cxxConversionDecl(returns(booleanType()))), + on(ignoringParenImpCasts(declRefExpr(to(VarWithAlgoInit)))))); + + Finder->addMatcher( + expr(anyOf(IsBoolUsage, IsVariableBoolUsage)).bind("boolOp"), this); +} + +void MissingEndComparisonCheck::check(const MatchFinder::MatchResult &Result) { + const auto *Call = Result.Nodes.getNodeAs<CallExpr>("algoCall"); + const auto *BoolOp = Result.Nodes.getNodeAs<Expr>("boolOp"); + const auto *CPO = Result.Nodes.getNodeAs<VarDecl>("cpo"); ---------------- vbvictor wrote:
What does "cpo" mean? https://github.com/llvm/llvm-project/pull/182543 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
