// Copyright (c) 2023 Bitcoin Developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include "logprintf.h" #include #include namespace { AST_MATCHER(clang::StringLiteral, unterminated) { size_t len = Node.getLength(); if (len > 0 && Node.getCodeUnit(len - 1) == '\n') { return false; } return true; } } // namespace namespace bitcoin { void LogPrintfCheck::registerMatchers(clang::ast_matchers::MatchFinder* finder) { using namespace clang::ast_matchers; /* Logprintf(..., ..., ..., ..., ..., "foo", ...) */ finder->addMatcher( callExpr( callee(functionDecl(hasName("LogPrintf_"))), hasArgument(5, stringLiteral(unterminated()).bind("logstring"))), this); /* auto walletptr = &wallet; wallet.WalletLogPrintf("foo"); wallet->WalletLogPrintf("foo"); */ finder->addMatcher( cxxMemberCallExpr( callee(cxxMethodDecl(hasName("WalletLogPrintf"))), hasArgument(0, stringLiteral(unterminated()).bind("logstring"))), this); } void LogPrintfCheck::check(const clang::ast_matchers::MatchFinder::MatchResult& Result) { if (const clang::StringLiteral* lit = Result.Nodes.getNodeAs("logstring")) { const clang::ASTContext& ctx = *Result.Context; const auto user_diag = diag(lit->getEndLoc(), "Unterminated format string used with LogPrintf"); const auto& loc = lit->getLocationOfByte(lit->getByteLength(), *Result.SourceManager, ctx.getLangOpts(), ctx.getTargetInfo()); user_diag << clang::FixItHint::CreateInsertion(loc, "\\n"); } } } // namespace bitcoin