brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.2 KiB · 315ce58 Raw
147 lines · cpp
1//===--- QueryCheck.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-exception6//7//===----------------------------------------------------------------------===//8 9#include "QueryCheck.h"10#include "../../clang-query/Query.h"11#include "../../clang-query/QueryParser.h"12#include "clang/ASTMatchers/ASTMatchers.h"13#include "clang/ASTMatchers/Dynamic/VariantValue.h"14#include "clang/Basic/DiagnosticIDs.h"15#include "llvm/ADT/SmallVector.h"16#include "llvm/ADT/StringRef.h"17#include <string>18 19using namespace clang::ast_matchers;20 21namespace clang::tidy::custom {22 23static void emitConfigurationDiag(ClangTidyContext *Context, StringRef Message,24                                  StringRef CheckName) {25  Context->configurationDiag("%0 in '%1'", DiagnosticIDs::Warning)26      << Message << CheckName;27}28 29static SmallVector<ast_matchers::dynamic::DynTypedMatcher>30parseQuery(const ClangTidyOptions::CustomCheckValue &V,31           ClangTidyContext *Context) {32  SmallVector<ast_matchers::dynamic::DynTypedMatcher> Matchers{};33  clang::query::QuerySession QS({});34  llvm::StringRef QueryStringRef{V.Query};35  while (!QueryStringRef.empty()) {36    const query::QueryRef Q = query::QueryParser::parse(QueryStringRef, QS);37    switch (Q->Kind) {38    case query::QK_Match: {39      const auto &MatchQuery = llvm::cast<query::MatchQuery>(*Q);40      Matchers.push_back(MatchQuery.Matcher);41      break;42    }43    case query::QK_Let: {44      const auto &LetQuery = llvm::cast<query::LetQuery>(*Q);45      LetQuery.run(llvm::errs(), QS);46      break;47    }48    case query::QK_NoOp: {49      const auto &NoOpQuery = llvm::cast<query::NoOpQuery>(*Q);50      NoOpQuery.run(llvm::errs(), QS);51      break;52    }53    case query::QK_Invalid: {54      const auto &InvalidQuery = llvm::cast<query::InvalidQuery>(*Q);55      emitConfigurationDiag(Context, InvalidQuery.ErrStr, V.Name);56      return {};57    }58    // FIXME: TODO59    case query::QK_File: {60      emitConfigurationDiag(Context, "unsupported query kind 'File'", V.Name);61      return {};62    }63    case query::QK_DisableOutputKind: {64      emitConfigurationDiag(65          Context, "unsupported query kind 'DisableOutputKind'", V.Name);66      return {};67    }68    case query::QK_EnableOutputKind: {69      emitConfigurationDiag(70          Context, "unsupported query kind 'EnableOutputKind'", V.Name);71      return {};72    }73    case query::QK_SetOutputKind: {74      emitConfigurationDiag(Context, "unsupported query kind 'SetOutputKind'",75                            V.Name);76      return {};77    }78    case query::QK_SetTraversalKind: {79      emitConfigurationDiag(80          Context, "unsupported query kind 'SetTraversalKind'", V.Name);81      return {};82    }83    case query::QK_SetBool: {84      emitConfigurationDiag(Context, "unsupported query kind 'SetBool'",85                            V.Name);86      return {};87    }88    case query::QK_Help: {89      emitConfigurationDiag(Context, "unsupported query kind 'Help'", V.Name);90      return {};91    }92    case query::QK_Quit: {93      emitConfigurationDiag(Context, "unsupported query kind 'Quit'", V.Name);94      return {};95    }96    }97    QueryStringRef = Q->RemainingContent;98  }99  return Matchers;100}101 102QueryCheck::QueryCheck(llvm::StringRef Name,103                       const ClangTidyOptions::CustomCheckValue &V,104                       ClangTidyContext *Context)105    : ClangTidyCheck(Name, Context) {106  for (const ClangTidyOptions::CustomCheckDiag &D : V.Diags) {107    auto DiagnosticIdIt =108        Diags109            .try_emplace(D.Level.value_or(DiagnosticIDs::Warning),110                         llvm::StringMap<llvm::SmallVector<std::string>>{})111            .first;112    auto DiagMessageIt =113        DiagnosticIdIt->getSecond()114            .try_emplace(D.BindName, llvm::SmallVector<std::string>{})115            .first;116    DiagMessageIt->second.emplace_back(D.Message);117  }118  Matchers = parseQuery(V, Context);119}120 121void QueryCheck::registerMatchers(MatchFinder *Finder) {122  for (const ast_matchers::dynamic::DynTypedMatcher &M : Matchers)123    Finder->addDynamicMatcher(M, this);124}125 126void QueryCheck::check(const MatchFinder::MatchResult &Result) {127  auto Emit = [this](const DiagMaps &DiagMaps, const std::string &BindName,128                     const DynTypedNode &Node, DiagnosticIDs::Level Level) {129    const DiagMaps::const_iterator DiagMapIt = DiagMaps.find(Level);130    if (DiagMapIt == DiagMaps.end())131      return;132    const BindNameMapToDiagMessage &BindNameMap = DiagMapIt->second;133    const BindNameMapToDiagMessage::const_iterator BindNameMapIt =134        BindNameMap.find(BindName);135    if (BindNameMapIt == BindNameMap.end())136      return;137    for (const std::string &Message : BindNameMapIt->second)138      diag(Node.getSourceRange().getBegin(), Message, Level);139  };140  for (const auto &[Name, Node] : Result.Nodes.getMap())141    Emit(Diags, Name, Node, DiagnosticIDs::Warning);142  // place Note last, otherwise it will not be emitted143  for (const auto &[Name, Node] : Result.Nodes.getMap())144    Emit(Diags, Name, Node, DiagnosticIDs::Note);145}146} // namespace clang::tidy::custom147