brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.3 KiB · ff86fc5 Raw
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