54 cxxRecordDecl(hasName(
"::std::basic_ostream"),
57 classTemplateSpecializationDecl(
58 hasTemplateArgument(0, refersToType(isChar()))));
59 auto IsDeclRefExprFromAllowedTypes = declRefExpr(to(varDecl(
61 auto IsExplicitCastExprFromAllowedTypes = explicitCastExpr(hasDestinationType(
65 hasOverloadedOperatorName(
"<<"),
66 hasLHS(hasType(hasUnqualifiedDesugaredType(
67 recordType(hasDeclaration(cxxRecordDecl(
68 anyOf(BasicOstream, isDerivedFrom(BasicOstream)))))))),
69 hasRHS(expr(hasType(hasUnqualifiedDesugaredType(isNumericChar())),
70 unless(ignoringParenImpCasts(
71 anyOf(IsDeclRefExprFromAllowedTypes,
72 IsExplicitCastExprFromAllowedTypes))))))
78 const MatchFinder::MatchResult &Result) {
79 const auto *Call = Result.Nodes.getNodeAs<CXXOperatorCallExpr>(
"x");
80 const Expr *Value = Call->getArg(1);
81 const SourceRange SourceRange = Value->getSourceRange();
83 DiagnosticBuilder Builder =
84 diag(Call->getOperatorLoc(),
85 "%0 passed to 'operator<<' outputs as character instead of integer. "
86 "cast to 'unsigned int' to print numeric value or cast to 'char' to "
88 << Value->getType() << SourceRange;
90 QualType T = Value->getType();
91 const Type *UnqualifiedDesugaredType = T->getUnqualifiedDesugaredType();
93 llvm::StringRef CastType = CastTypeName.value_or(
94 UnqualifiedDesugaredType->isSpecificBuiltinType(BuiltinType::SChar)
98 Builder << FixItHint::CreateReplacement(
99 SourceRange, (
"static_cast<" + CastType +
">(" +
100 tooling::fixit::getText(*Value, *Result.Context) +
")")
Every ClangTidyCheck reports errors through a DiagnosticsEngine provided by this context.