brintos

brintos / llvm-project-archived public Read only

0
0
Text · 4.0 KiB · 1f666d2 Raw
117 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 "LambdaFunctionNameCheck.h"10#include "clang/AST/ASTContext.h"11#include "clang/AST/DeclCXX.h"12#include "clang/ASTMatchers/ASTMatchFinder.h"13#include "clang/ASTMatchers/ASTMatchers.h"14#include "clang/Frontend/CompilerInstance.h"15#include "clang/Lex/MacroInfo.h"16#include "clang/Lex/Preprocessor.h"17 18using namespace clang::ast_matchers;19 20namespace clang::tidy::bugprone {21 22namespace {23 24static constexpr bool DefaultIgnoreMacros = false;25 26// Keep track of macro expansions that contain both __FILE__ and __LINE__. If27// such a macro also uses __func__ or __FUNCTION__, we don't want to issue a28// warning because __FILE__ and __LINE__ may be useful even if __func__ or29// __FUNCTION__ is not, especially if the macro could be used in the context of30// either a function body or a lambda body.31class MacroExpansionsWithFileAndLine : public PPCallbacks {32public:33  explicit MacroExpansionsWithFileAndLine(34      LambdaFunctionNameCheck::SourceRangeSet *SME)35      : SuppressMacroExpansions(SME) {}36 37  void MacroExpands(const Token &MacroNameTok, const MacroDefinition &MD,38                    SourceRange Range, const MacroArgs *Args) override {39    bool HasFile = false;40    bool HasLine = false;41    for (const Token &T : MD.getMacroInfo()->tokens()) {42      if (T.is(tok::identifier)) {43        const StringRef IdentName = T.getIdentifierInfo()->getName();44        if (IdentName == "__FILE__") {45          HasFile = true;46        } else if (IdentName == "__LINE__") {47          HasLine = true;48        }49      }50    }51    if (HasFile && HasLine) {52      SuppressMacroExpansions->insert(Range);53    }54  }55 56private:57  LambdaFunctionNameCheck::SourceRangeSet *SuppressMacroExpansions;58};59 60AST_MATCHER(CXXMethodDecl, isInLambda) { return Node.getParent()->isLambda(); }61 62} // namespace63 64LambdaFunctionNameCheck::LambdaFunctionNameCheck(StringRef Name,65                                                 ClangTidyContext *Context)66    : ClangTidyCheck(Name, Context),67      IgnoreMacros(Options.get("IgnoreMacros", DefaultIgnoreMacros)) {}68 69void LambdaFunctionNameCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {70  Options.store(Opts, "IgnoreMacros", IgnoreMacros);71}72 73void LambdaFunctionNameCheck::registerMatchers(MatchFinder *Finder) {74  Finder->addMatcher(75      cxxMethodDecl(isInLambda(),76                    hasBody(forEachDescendant(77                        predefinedExpr(hasAncestor(cxxMethodDecl().bind("fn")))78                            .bind("E"))),79                    equalsBoundNode("fn")),80      this);81}82 83void LambdaFunctionNameCheck::registerPPCallbacks(84    const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) {85  PP->addPPCallbacks(std::make_unique<MacroExpansionsWithFileAndLine>(86      &SuppressMacroExpansions));87}88 89void LambdaFunctionNameCheck::check(const MatchFinder::MatchResult &Result) {90  const auto *E = Result.Nodes.getNodeAs<PredefinedExpr>("E");91  if (E->getIdentKind() != PredefinedIdentKind::Func &&92      E->getIdentKind() != PredefinedIdentKind::Function) {93    // We don't care about other PredefinedExprs.94    return;95  }96  if (E->getLocation().isMacroID()) {97    if (IgnoreMacros)98      return;99 100    auto ER =101        Result.SourceManager->getImmediateExpansionRange(E->getLocation());102    if (SuppressMacroExpansions.find(ER.getAsRange()) !=103        SuppressMacroExpansions.end()) {104      // This is a macro expansion for which we should not warn.105      return;106    }107  }108 109  diag(E->getLocation(),110       "inside a lambda, '%0' expands to the name of the function call "111       "operator; consider capturing the name of the enclosing function "112       "explicitly")113      << PredefinedExpr::getIdentKindName(E->getIdentKind());114}115 116} // namespace clang::tidy::bugprone117