clang-tools  17.0.0git
CloexecCheck.cpp
Go to the documentation of this file.
1 //===--- CloexecCheck.cpp - clang-tidy-------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "CloexecCheck.h"
10 #include "../utils/ASTUtils.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
13 #include "clang/Lex/Lexer.h"
14 
15 using namespace clang::ast_matchers;
16 
17 namespace clang::tidy::android {
18 
19 namespace {
20 // Helper function to form the correct string mode for Type3.
21 // Build the replace text. If it's string constant, add <Mode> directly in the
22 // end of the string. Else, add <Mode>.
23 std::string buildFixMsgForStringFlag(const Expr *Arg, const SourceManager &SM,
24  const LangOptions &LangOpts, char Mode) {
25  if (Arg->getBeginLoc().isMacroID())
26  return (Lexer::getSourceText(
27  CharSourceRange::getTokenRange(Arg->getSourceRange()), SM,
28  LangOpts) +
29  " \"" + Twine(Mode) + "\"")
30  .str();
31 
32  StringRef SR = cast<StringLiteral>(Arg->IgnoreParenCasts())->getString();
33  return ("\"" + SR + Twine(Mode) + "\"").str();
34 }
35 } // namespace
36 
37 const char *CloexecCheck::FuncDeclBindingStr = "funcDecl";
38 
39 const char *CloexecCheck::FuncBindingStr ="func";
40 
41 void CloexecCheck::registerMatchersImpl(
42  MatchFinder *Finder, internal::Matcher<FunctionDecl> Function) {
43  // We assume all the checked APIs are C functions.
44  Finder->addMatcher(
45  callExpr(
46  callee(functionDecl(isExternC(), Function).bind(FuncDeclBindingStr)))
47  .bind(FuncBindingStr),
48  this);
49 }
50 
51 void CloexecCheck::insertMacroFlag(const MatchFinder::MatchResult &Result,
52  StringRef MacroFlag, int ArgPos) {
53  const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>(FuncBindingStr);
54  const auto *FlagArg = MatchedCall->getArg(ArgPos);
55  const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>(FuncDeclBindingStr);
56  SourceManager &SM = *Result.SourceManager;
57 
58  if (utils::exprHasBitFlagWithSpelling(FlagArg->IgnoreParenCasts(), SM,
59  Result.Context->getLangOpts(),
60  MacroFlag))
61  return;
62 
63  SourceLocation EndLoc =
64  Lexer::getLocForEndOfToken(SM.getFileLoc(FlagArg->getEndLoc()), 0, SM,
65  Result.Context->getLangOpts());
66 
67  diag(EndLoc, "%0 should use %1 where possible")
68  << FD << MacroFlag
69  << FixItHint::CreateInsertion(EndLoc, (Twine(" | ") + MacroFlag).str());
70 }
71 
72 void CloexecCheck::replaceFunc(const MatchFinder::MatchResult &Result,
73  StringRef WarningMsg, StringRef FixMsg) {
74  const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>(FuncBindingStr);
75  diag(MatchedCall->getBeginLoc(), WarningMsg)
76  << FixItHint::CreateReplacement(MatchedCall->getSourceRange(), FixMsg);
77 }
78 
79 void CloexecCheck::insertStringFlag(
80  const ast_matchers::MatchFinder::MatchResult &Result, const char Mode,
81  const int ArgPos) {
82  const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>(FuncBindingStr);
83  const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>(FuncDeclBindingStr);
84  const auto *ModeArg = MatchedCall->getArg(ArgPos);
85 
86  // Check if the <Mode> may be in the mode string.
87  const auto *ModeStr = dyn_cast<StringLiteral>(ModeArg->IgnoreParenCasts());
88  if (!ModeStr || ModeStr->getString().contains(Mode))
89  return;
90 
91  std::string ReplacementText = buildFixMsgForStringFlag(
92  ModeArg, *Result.SourceManager, Result.Context->getLangOpts(), Mode);
93 
94  diag(ModeArg->getBeginLoc(), "use %0 mode '%1' to set O_CLOEXEC")
95  << FD << std::string(1, Mode)
96  << FixItHint::CreateReplacement(ModeArg->getSourceRange(),
97  ReplacementText);
98 }
99 
100 StringRef CloexecCheck::getSpellingArg(const MatchFinder::MatchResult &Result,
101  int N) const {
102  const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>(FuncBindingStr);
103  const SourceManager &SM = *Result.SourceManager;
104  return Lexer::getSourceText(
105  CharSourceRange::getTokenRange(MatchedCall->getArg(N)->getSourceRange()),
106  SM, Result.Context->getLangOpts());
107 }
108 
109 } // namespace clang::tidy::android
clang::tidy::cppcoreguidelines::getSourceText
static std::string getSourceText(const CXXDestructorDecl &Destructor)
Definition: VirtualClassDestructorCheck.cpp:115
clang::tidy::android
Definition: AndroidTidyModule.cpp:31
CloexecCheck.h
clang::ast_matchers
Definition: AbseilMatcher.h:13
clang::tidy::utils::exprHasBitFlagWithSpelling
bool exprHasBitFlagWithSpelling(const Expr *Flags, const SourceManager &SM, const LangOptions &LangOpts, StringRef FlagName)
Checks whether a macro flag is present in the given argument.
Definition: ASTUtils.cpp:38
LangOpts
const LangOptions * LangOpts
Definition: ExtractFunction.cpp:374