10 #include "clang/AST/ASTContext.h"
11 #include "clang/AST/Type.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
15 using namespace clang::ast_matchers;
22 static const char MODE =
'e';
26 std::string BuildReplaceText(
const Expr *Arg,
const SourceManager &
SM,
28 if (Arg->getLocStart().isMacroID())
29 return (Lexer::getSourceText(
30 CharSourceRange::getTokenRange(Arg->getSourceRange()), SM,
32 " \"" + Twine(MODE) +
"\"")
35 StringRef SR = cast<StringLiteral>(Arg->IgnoreParenCasts())->getString();
36 return (
"\"" + SR + Twine(MODE) +
"\"").str();
40 void CloexecFopenCheck::registerMatchers(MatchFinder *
Finder) {
41 auto CharPointerType = hasType(pointerType(pointee(isAnyCharacter())));
44 callExpr(callee(functionDecl(isExternC(), returns(asString(
"FILE *")),
46 hasParameter(0, CharPointerType),
47 hasParameter(1, CharPointerType))
53 void CloexecFopenCheck::check(
const MatchFinder::MatchResult &Result) {
54 const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>(
"fopenFn");
55 const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>(
"funcDecl");
56 const Expr *ModeArg = MatchedCall->getArg(1);
59 const auto *ModeStr = dyn_cast<StringLiteral>(ModeArg->IgnoreParenCasts());
60 if (!ModeStr || (ModeStr->getString().find(MODE) != StringRef::npos))
63 const std::string &ReplacementText = BuildReplaceText(
64 ModeArg, *Result.SourceManager, Result.Context->getLangOpts());
66 diag(ModeArg->getLocStart(),
"use %0 mode 'e' to set O_CLOEXEC")
68 << FixItHint::CreateReplacement(ModeArg->getSourceRange(),
std::unique_ptr< ast_matchers::MatchFinder > Finder