brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.3 KiB · a2de7a2 Raw
169 lines · cpp
1//===---- ClangQuery.cpp - clang-query tool -------------------------------===//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// This tool is for interactive exploration of the Clang AST using AST matchers.10// It currently allows the user to enter a matcher at an interactive prompt and11// view the resulting bindings as diagnostics, AST pretty prints or AST dumps.12// Example session:13//14// $ cat foo.c15// void foo(void) {}16// $ clang-query foo.c --17// clang-query> match functionDecl()18//19// Match #1:20//21// foo.c:1:1: note: "root" binds here22// void foo(void) {}23// ^~~~~~~~~~~~~~~~~24// 1 match.25//26//===----------------------------------------------------------------------===//27 28#include "Query.h"29#include "QueryParser.h"30#include "QuerySession.h"31#include "clang/Frontend/ASTUnit.h"32#include "clang/Tooling/CommonOptionsParser.h"33#include "clang/Tooling/Tooling.h"34#include "llvm/LineEditor/LineEditor.h"35#include "llvm/Support/CommandLine.h"36#include "llvm/Support/Error.h"37#include "llvm/Support/MemoryBuffer.h"38#include "llvm/Support/Signals.h"39#include "llvm/Support/WithColor.h"40#include <optional>41#include <string>42 43using namespace clang;44using namespace clang::ast_matchers;45using namespace clang::ast_matchers::dynamic;46using namespace clang::query;47using namespace clang::tooling;48using namespace llvm;49 50static cl::extrahelp CommonHelp(CommonOptionsParser::HelpMessage);51static cl::OptionCategory ClangQueryCategory("clang-query options");52 53static cl::opt<bool>54    UseColor("use-color",55             cl::desc(56                 R"(Use colors in detailed AST output. If not set, colors57will be used if the terminal connected to58standard output supports colors.)"),59             cl::init(false), cl::cat(ClangQueryCategory));60 61static cl::list<std::string> Commands("c", cl::desc("Specify command to run"),62                                      cl::value_desc("command"),63                                      cl::cat(ClangQueryCategory));64 65static cl::list<std::string> CommandFiles("f",66                                          cl::desc("Read commands from file"),67                                          cl::value_desc("file"),68                                          cl::cat(ClangQueryCategory));69 70static cl::opt<std::string> PreloadFile(71    "preload",72    cl::desc("Preload commands from file and start interactive mode"),73    cl::value_desc("file"), cl::cat(ClangQueryCategory));74 75bool runCommandsInFile(const char *ExeName, std::string const &FileName,76                       QuerySession &QS) {77  FileQuery Query(FileName, ExeName);78  return !Query.run(llvm::errs(), QS);79}80 81int main(int argc, const char **argv) {82  llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);83 84  llvm::Expected<CommonOptionsParser> OptionsParser =85      CommonOptionsParser::create(argc, argv, ClangQueryCategory,86                                  llvm::cl::OneOrMore);87 88  if (!OptionsParser) {89    llvm::WithColor::error() << llvm::toString(OptionsParser.takeError());90    return 1;91  }92 93  if (!Commands.empty() && !CommandFiles.empty()) {94    llvm::errs() << argv[0] << ": cannot specify both -c and -f\n";95    return 1;96  }97 98  if ((!Commands.empty() || !CommandFiles.empty()) && !PreloadFile.empty()) {99    llvm::errs() << argv[0]100                 << ": cannot specify both -c or -f with --preload\n";101    return 1;102  }103 104  ClangTool Tool(OptionsParser->getCompilations(),105                 OptionsParser->getSourcePathList());106 107  if (UseColor.getNumOccurrences() > 0) {108    ArgumentsAdjuster colorAdjustor = [](const CommandLineArguments &Args, StringRef /*unused*/) {109      CommandLineArguments AdjustedArgs = Args;110      if (UseColor)111        AdjustedArgs.push_back("-fdiagnostics-color");112      else113        AdjustedArgs.push_back("-fno-diagnostics-color");114      return AdjustedArgs;115    };116    Tool.appendArgumentsAdjuster(colorAdjustor);117  }118 119  std::vector<std::unique_ptr<ASTUnit>> ASTs;120  int ASTStatus = 0;121  switch (Tool.buildASTs(ASTs)) {122  case 0:123    break;124  case 1: // Building ASTs failed.125    return 1;126  case 2:127    ASTStatus |= 1;128    llvm::errs() << "Failed to build AST for some of the files, "129                 << "results may be incomplete."130                 << "\n";131    break;132  default:133    llvm_unreachable("Unexpected status returned");134  }135 136  QuerySession QS(ASTs);137 138  if (!Commands.empty()) {139    for (auto &Command : Commands) {140      QueryRef Q = QueryParser::parse(Command, QS);141      if (!Q->run(llvm::outs(), QS))142        return 1;143    }144  } else if (!CommandFiles.empty()) {145    for (auto &CommandFile : CommandFiles) {146      if (runCommandsInFile(argv[0], CommandFile, QS))147        return 1;148    }149  } else {150    if (!PreloadFile.empty()) {151      if (runCommandsInFile(argv[0], PreloadFile, QS))152        return 1;153    }154    LineEditor LE("clang-query");155    LE.setListCompleter([&QS](StringRef Line, size_t Pos) {156      return QueryParser::complete(Line, Pos, QS);157    });158    while (std::optional<std::string> Line = LE.readLine()) {159      QueryRef Q = QueryParser::parse(*Line, QS);160      Q->run(llvm::outs(), QS);161      llvm::outs().flush();162      if (QS.Terminate)163        break;164    }165  }166 167  return ASTStatus;168}169