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