clang-tools  15.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 {
18 namespace tidy {
19 namespace android {
20 
21 namespace {
22 // Helper function to form the correct string mode for Type3.
23 // Build the replace text. If it's string constant, add <Mode> directly in the
24 // end of the string. Else, add <Mode>.
25 std::string buildFixMsgForStringFlag(const Expr *Arg, const SourceManager &SM,
26  const LangOptions &LangOpts, char Mode) {
27  if (Arg->getBeginLoc().isMacroID())
28  return (Lexer::getSourceText(
29  CharSourceRange::getTokenRange(Arg->getSourceRange()), SM,
30  LangOpts) +
31  " \"" + Twine(Mode) + "\"")
32  .str();
33 
34  StringRef SR = cast<StringLiteral>(Arg->IgnoreParenCasts())->getString();
35  return ("\"" + SR + Twine(Mode) + "\"").str();
36 }
37 } // namespace
38 
39 const char *CloexecCheck::FuncDeclBindingStr = "funcDecl";
40 
41 const char *CloexecCheck::FuncBindingStr ="func";
42 
43 void CloexecCheck::registerMatchersImpl(
44  MatchFinder *Finder, internal::Matcher<FunctionDecl> Function) {
45  // We assume all the checked APIs are C functions.
46  Finder->addMatcher(
47  callExpr(
48  callee(functionDecl(isExternC(), Function).bind(FuncDeclBindingStr)))
49  .bind(FuncBindingStr),
50  this);
51 }
52 
53 void CloexecCheck::insertMacroFlag(const MatchFinder::MatchResult &Result,
54  StringRef MacroFlag, int ArgPos) {
55  const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>(FuncBindingStr);
56  const auto *FlagArg = MatchedCall->getArg(ArgPos);
57  const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>(FuncDeclBindingStr);
58  SourceManager &SM = *Result.SourceManager;
59 
60  if (utils::exprHasBitFlagWithSpelling(FlagArg->IgnoreParenCasts(), SM,
61  Result.Context->getLangOpts(),
62  MacroFlag))
63  return;
64 
65  SourceLocation EndLoc =
66  Lexer::getLocForEndOfToken(SM.getFileLoc(FlagArg->getEndLoc()), 0, SM,
67  Result.Context->getLangOpts());
68 
69  diag(EndLoc, "%0 should use %1 where possible")
70  << FD << MacroFlag
71  << FixItHint::CreateInsertion(EndLoc, (Twine(" | ") + MacroFlag).str());
72 }
73 
74 void CloexecCheck::replaceFunc(const MatchFinder::MatchResult &Result,
75  StringRef WarningMsg, StringRef FixMsg) {
76  const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>(FuncBindingStr);
77  diag(MatchedCall->getBeginLoc(), WarningMsg)
78  << FixItHint::CreateReplacement(MatchedCall->getSourceRange(), FixMsg);
79 }
80 
81 void CloexecCheck::insertStringFlag(
82  const ast_matchers::MatchFinder::MatchResult &Result, const char Mode,
83  const int ArgPos) {
84  const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>(FuncBindingStr);
85  const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>(FuncDeclBindingStr);
86  const auto *ModeArg = MatchedCall->getArg(ArgPos);
87 
88  // Check if the <Mode> may be in the mode string.
89  const auto *ModeStr = dyn_cast<StringLiteral>(ModeArg->IgnoreParenCasts());
90  if (!ModeStr || ModeStr->getString().contains(Mode))
91  return;
92 
93  std::string ReplacementText = buildFixMsgForStringFlag(
94  ModeArg, *Result.SourceManager, Result.Context->getLangOpts(), Mode);
95 
96  diag(ModeArg->getBeginLoc(), "use %0 mode '%1' to set O_CLOEXEC")
97  << FD << std::string(1, Mode)
98  << FixItHint::CreateReplacement(ModeArg->getSourceRange(),
99  ReplacementText);
100 }
101 
102 StringRef CloexecCheck::getSpellingArg(const MatchFinder::MatchResult &Result,
103  int N) const {
104  const auto *MatchedCall = Result.Nodes.getNodeAs<CallExpr>(FuncBindingStr);
105  const SourceManager &SM = *Result.SourceManager;
106  return Lexer::getSourceText(
107  CharSourceRange::getTokenRange(MatchedCall->getArg(N)->getSourceRange()),
108  SM, Result.Context->getLangOpts());
109 }
110 
111 } // namespace android
112 } // namespace tidy
113 } // namespace clang
clang::tidy::cppcoreguidelines::getSourceText
static std::string getSourceText(const CXXDestructorDecl &Destructor)
Definition: VirtualClassDestructorCheck.cpp:115
CloexecCheck.h
clang::ast_matchers
Definition: AbseilMatcher.h:14
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:40
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
LangOpts
const LangOptions * LangOpts
Definition: ExtractFunction.cpp:366