CloexecCheck.cpp 4.3 KB

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