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