11 #include "clang/AST/ASTContext.h"
12 #include "clang/Lex/Lexer.h"
13 #include "clang/Tooling/FixIt.h"
14 #include "llvm/ADT/SmallPtrSet.h"
16 using namespace clang::ast_matchers;
22 void SwappedArgumentsCheck::registerMatchers(MatchFinder *
Finder) {
23 Finder->addMatcher(callExpr().bind(
"call"),
this);
30 if (
auto *Cast = dyn_cast<CastExpr>(E))
31 if (Cast->getCastKind() == CK_LValueToRValue ||
32 Cast->getCastKind() == CK_NoOp)
41 return Cast->getCastKind() == CK_UserDefinedConversion ||
42 Cast->getCastKind() == CK_FloatingToBoolean ||
43 Cast->getCastKind() == CK_FloatingToIntegral ||
44 Cast->getCastKind() == CK_IntegralToBoolean ||
45 Cast->getCastKind() == CK_IntegralToFloating ||
46 Cast->getCastKind() == CK_MemberPointerToBoolean ||
47 Cast->getCastKind() == CK_PointerToBoolean;
50 void SwappedArgumentsCheck::check(
const MatchFinder::MatchResult &
Result) {
51 const ASTContext &Ctx = *Result.Context;
52 const auto *Call = Result.Nodes.getStmtAs<CallExpr>(
"call");
54 llvm::SmallPtrSet<const Expr *, 4> UsedArgs;
55 for (
unsigned I = 1, E = Call->getNumArgs(); I < E; ++I) {
56 const Expr *LHS = Call->getArg(I - 1);
57 const Expr *RHS = Call->getArg(I);
61 if (UsedArgs.count(RHS))
81 if (LHS->getType() == RHS->getType() ||
82 LHS->getType() != RHSFrom->getType() ||
83 RHS->getType() != LHSFrom->getType())
87 diag(Call->getLocStart(),
"argument with implicit conversion from %0 "
88 "to %1 followed by argument converted from "
89 "%2 to %3, potentially swapped arguments.")
90 << LHS->getType() << LHSFrom->getType() << RHS->getType()
92 << tooling::fixit::createReplacement(*LHS, *RHS, Ctx)
93 << tooling::fixit::createReplacement(*RHS, *LHS, Ctx);
96 UsedArgs.insert(RHSCast);
static const Expr * ignoreNoOpCasts(const Expr *E)
Look through lvalue to rvalue and nop casts.
std::unique_ptr< ast_matchers::MatchFinder > Finder
static bool isImplicitCastCandidate(const CastExpr *Cast)
Restrict the warning to implicit casts that are most likely accidental.