1 //===--- CloexecOpenCheck.cpp - clang-tidy---------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "CloexecOpenCheck.h" 11 #include "../utils/ASTUtils.h" 12 #include "clang/AST/ASTContext.h" 13 #include "clang/ASTMatchers/ASTMatchFinder.h" 14 #include "clang/Lex/Lexer.h" 15 16 using namespace clang::ast_matchers; 17 18 namespace clang { 19 namespace tidy { 20 namespace android { 21 22 static constexpr const char *O_CLOEXEC = "O_CLOEXEC"; 23 24 void CloexecOpenCheck::registerMatchers(MatchFinder *Finder) { 25 auto CharPointerType = hasType(pointerType(pointee(isAnyCharacter()))); 26 27 Finder->addMatcher( 28 callExpr(callee(functionDecl(isExternC(), returns(isInteger()), 29 hasAnyName("open", "open64"), 30 hasParameter(0, CharPointerType), 31 hasParameter(1, hasType(isInteger()))) 32 .bind("funcDecl"))) 33 .bind("openFn"), 34 this); 35 Finder->addMatcher( 36 callExpr(callee(functionDecl(isExternC(), returns(isInteger()), 37 hasName("openat"), 38 hasParameter(0, hasType(isInteger())), 39 hasParameter(1, CharPointerType), 40 hasParameter(2, hasType(isInteger()))) 41 .bind("funcDecl"))) 42 .bind("openatFn"), 43 this); 44 } 45 46 void CloexecOpenCheck::check(const MatchFinder::MatchResult &Result) { 47 const Expr *FlagArg = nullptr; 48 if (const auto *OpenFnCall = Result.Nodes.getNodeAs<CallExpr>("openFn")) 49 FlagArg = OpenFnCall->getArg(1); 50 else if (const auto *OpenFnCall = 51 Result.Nodes.getNodeAs<CallExpr>("openatFn")) 52 FlagArg = OpenFnCall->getArg(2); 53 assert(FlagArg); 54 55 const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("funcDecl"); 56 57 // Check the required flag. 58 SourceManager &SM = *Result.SourceManager; 59 if (utils::exprHasBitFlagWithSpelling(FlagArg->IgnoreParenCasts(), SM, 60 Result.Context->getLangOpts(), O_CLOEXEC)) 61 return; 62 63 SourceLocation EndLoc = 64 Lexer::getLocForEndOfToken(SM.getFileLoc(FlagArg->getLocEnd()), 0, SM, 65 Result.Context->getLangOpts()); 66 67 diag(EndLoc, "%0 should use %1 where possible") 68 << FD << O_CLOEXEC 69 << FixItHint::CreateInsertion(EndLoc, (Twine(" | ") + O_CLOEXEC).str()); 70 } 71 72 } // namespace android 73 } // namespace tidy 74 } // namespace clang 75