blob: 4dfe3951d93dc7eba8dc0599cd4bac39944b64d0 [file] [log] [blame]
Yan Wang600a6132017-06-29 19:13:29 +00001//===--- CloexecOpenCheck.cpp - clang-tidy---------------------------------===//
Yan Wang36206202017-06-23 21:37:29 +00002//
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
Yan Wang600a6132017-06-29 19:13:29 +000010#include "CloexecOpenCheck.h"
Yan Wang36206202017-06-23 21:37:29 +000011#include "clang/AST/ASTContext.h"
12#include "clang/ASTMatchers/ASTMatchFinder.h"
13#include "clang/Lex/Lexer.h"
14
15using namespace clang::ast_matchers;
16
17namespace clang {
18namespace tidy {
19namespace android {
20
21namespace {
22static constexpr const char *O_CLOEXEC = "O_CLOEXEC";
23
Yan Wang600a6132017-06-29 19:13:29 +000024bool hasCloseOnExecFlag(const Expr *Flags, const SourceManager &SM,
Yan Wang36206202017-06-23 21:37:29 +000025 const LangOptions &LangOpts) {
26 // If the Flag is an integer constant, check it.
27 if (isa<IntegerLiteral>(Flags)) {
Yan Wang600a6132017-06-29 19:13:29 +000028 if (!SM.isMacroBodyExpansion(Flags->getLocStart()) &&
29 !SM.isMacroArgExpansion(Flags->getLocStart()))
Yan Wang36206202017-06-23 21:37:29 +000030 return false;
31
32 // Get the Marco name.
33 auto MacroName = Lexer::getSourceText(
34 CharSourceRange::getTokenRange(Flags->getSourceRange()), SM, LangOpts);
35
36 return MacroName == O_CLOEXEC;
37 }
38 // If it's a binary OR operation.
39 if (const auto *BO = dyn_cast<BinaryOperator>(Flags))
40 if (BO->getOpcode() == clang::BinaryOperatorKind::BO_Or)
Yan Wang600a6132017-06-29 19:13:29 +000041 return hasCloseOnExecFlag(BO->getLHS()->IgnoreParenCasts(), SM,
Yan Wang36206202017-06-23 21:37:29 +000042 LangOpts) ||
Yan Wang600a6132017-06-29 19:13:29 +000043 hasCloseOnExecFlag(BO->getRHS()->IgnoreParenCasts(), SM, LangOpts);
Yan Wang36206202017-06-23 21:37:29 +000044
45 // Otherwise, assume it has the flag.
46 return true;
47}
48} // namespace
49
Yan Wang600a6132017-06-29 19:13:29 +000050void CloexecOpenCheck::registerMatchers(MatchFinder *Finder) {
Yan Wang36206202017-06-23 21:37:29 +000051 auto CharPointerType = hasType(pointerType(pointee(isAnyCharacter())));
52
53 Finder->addMatcher(
54 callExpr(callee(functionDecl(isExternC(), returns(isInteger()),
55 hasAnyName("open", "open64"),
56 hasParameter(0, CharPointerType),
57 hasParameter(1, hasType(isInteger())))
58 .bind("funcDecl")))
59 .bind("openFn"),
60 this);
61 Finder->addMatcher(
62 callExpr(callee(functionDecl(isExternC(), returns(isInteger()),
63 hasName("openat"),
64 hasParameter(0, hasType(isInteger())),
65 hasParameter(1, CharPointerType),
66 hasParameter(2, hasType(isInteger())))
67 .bind("funcDecl")))
68 .bind("openatFn"),
69 this);
70}
71
Yan Wang600a6132017-06-29 19:13:29 +000072void CloexecOpenCheck::check(const MatchFinder::MatchResult &Result) {
Yan Wang36206202017-06-23 21:37:29 +000073 const Expr *FlagArg = nullptr;
74 if (const auto *OpenFnCall = Result.Nodes.getNodeAs<CallExpr>("openFn"))
75 FlagArg = OpenFnCall->getArg(1);
76 else if (const auto *OpenFnCall =
77 Result.Nodes.getNodeAs<CallExpr>("openatFn"))
78 FlagArg = OpenFnCall->getArg(2);
79 assert(FlagArg);
80
81 const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("funcDecl");
82
83 // Check the required flag.
84 SourceManager &SM = *Result.SourceManager;
Yan Wang600a6132017-06-29 19:13:29 +000085 if (hasCloseOnExecFlag(FlagArg->IgnoreParenCasts(), SM,
Yan Wang36206202017-06-23 21:37:29 +000086 Result.Context->getLangOpts()))
87 return;
88
Yan Wang600a6132017-06-29 19:13:29 +000089 SourceLocation EndLoc =
90 Lexer::getLocForEndOfToken(SM.getFileLoc(FlagArg->getLocEnd()), 0, SM,
91 Result.Context->getLangOpts());
Yan Wang36206202017-06-23 21:37:29 +000092
93 diag(EndLoc, "%0 should use %1 where possible")
94 << FD << O_CLOEXEC
95 << FixItHint::CreateInsertion(EndLoc, (Twine(" | ") + O_CLOEXEC).str());
96}
97
98} // namespace android
99} // namespace tidy
100} // namespace clang