Coverage Report

Created: 2022-07-16 07:03

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/tools/clang-repl/ClangRepl.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- tools/clang-repl/ClangRepl.cpp - clang-repl - the Clang REPL -----===//
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-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
//  This file implements a REPL tool on top of clang.
10
//
11
//===----------------------------------------------------------------------===//
12
13
#include "clang/Basic/Diagnostic.h"
14
#include "clang/Frontend/CompilerInstance.h"
15
#include "clang/Frontend/FrontendDiagnostic.h"
16
#include "clang/Interpreter/Interpreter.h"
17
18
#include "llvm/ExecutionEngine/Orc/LLJIT.h"
19
#include "llvm/LineEditor/LineEditor.h"
20
#include "llvm/Support/CommandLine.h"
21
#include "llvm/Support/ManagedStatic.h" // llvm_shutdown
22
#include "llvm/Support/Signals.h"
23
#include "llvm/Support/TargetSelect.h" // llvm::Initialize*
24
25
static llvm::cl::list<std::string>
26
    ClangArgs("Xcc",
27
              llvm::cl::desc("Argument to pass to the CompilerInvocation"),
28
              llvm::cl::CommaSeparated);
29
static llvm::cl::opt<bool> OptHostSupportsJit("host-supports-jit",
30
                                              llvm::cl::Hidden);
31
static llvm::cl::list<std::string> OptInputs(llvm::cl::Positional,
32
                                             llvm::cl::desc("[code to run]"));
33
34
static void LLVMErrorHandler(void *UserData, const char *Message,
35
0
                             bool GenCrashDiag) {
36
0
  auto &Diags = *static_cast<clang::DiagnosticsEngine *>(UserData);
37
38
0
  Diags.Report(clang::diag::err_fe_error_backend) << Message;
39
40
  // Run the interrupt handlers to make sure any special cleanups get done, in
41
  // particular that we remove files registered with RemoveFileOnSignal.
42
0
  llvm::sys::RunInterruptHandlers();
43
44
  // We cannot recover from llvm errors.  When reporting a fatal error, exit
45
  // with status 70 to generate crash diagnostics.  For BSD systems this is
46
  // defined as an internal software error. Otherwise, exit with status 1.
47
48
0
  exit(GenCrashDiag ? 70 : 1);
49
0
}
50
51
// If we are running with -verify a reported has to be returned as unsuccess.
52
// This is relevant especially for the test suite.
53
9
static int checkDiagErrors(const clang::CompilerInstance *CI) {
54
9
  unsigned Errs = CI->getDiagnostics().getClient()->getNumErrors();
55
9
  if (CI->getDiagnosticOpts().VerifyDiagnostics) {
56
    // If there was an error that came from the verifier we must return 1 as
57
    // an exit code for the process. This will make the test fail as expected.
58
0
    clang::DiagnosticConsumer *Client = CI->getDiagnostics().getClient();
59
0
    Client->EndSourceFile();
60
0
    Errs = Client->getNumErrors();
61
62
    // The interpreter expects BeginSourceFile/EndSourceFiles to be balanced.
63
0
    Client->BeginSourceFile(CI->getLangOpts(), &CI->getPreprocessor());
64
0
  }
65
9
  return Errs ? EXIT_FAILURE : EXIT_SUCCESS;
66
9
}
67
68
llvm::ExitOnError ExitOnErr;
69
16
int main(int argc, const char **argv) {
70
16
  ExitOnErr.setBanner("clang-repl: ");
71
16
  llvm::cl::ParseCommandLineOptions(argc, argv);
72
73
16
  std::vector<const char *> ClangArgv(ClangArgs.size());
74
16
  std::transform(ClangArgs.begin(), ClangArgs.end(), ClangArgv.begin(),
75
16
                 [](const std::string &s) -> const char * 
{ return s.data(); }7
);
76
16
  llvm::InitializeNativeTarget();
77
16
  llvm::InitializeNativeTargetAsmPrinter();
78
79
16
  if (OptHostSupportsJit) {
80
7
    auto J = llvm::orc::LLJITBuilder().create();
81
7
    if (J)
82
7
      llvm::outs() << "true\n";
83
0
    else {
84
0
      llvm::consumeError(J.takeError());
85
0
      llvm::outs() << "false\n";
86
0
    }
87
7
    return 0;
88
7
  }
89
90
  // FIXME: Investigate if we could use runToolOnCodeWithArgs from tooling. It
91
  // can replace the boilerplate code for creation of the compiler instance.
92
9
  auto CI = ExitOnErr(clang::IncrementalCompilerBuilder::create(ClangArgv));
93
94
  // Set an error handler, so that any LLVM backend diagnostics go through our
95
  // error handler.
96
9
  llvm::install_fatal_error_handler(LLVMErrorHandler,
97
9
                                    static_cast<void *>(&CI->getDiagnostics()));
98
99
  // Load any requested plugins.
100
9
  CI->LoadRequestedPlugins();
101
102
9
  auto Interp = ExitOnErr(clang::Interpreter::create(std::move(CI)));
103
15
  for (const std::string &input : OptInputs) {
104
15
    if (auto Err = Interp->ParseAndExecute(input))
105
2
      llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: ");
106
15
  }
107
108
9
  if (OptInputs.empty()) {
109
4
    llvm::LineEditor LE("clang-repl");
110
    // FIXME: Add LE.setListCompleter
111
81
    while (llvm::Optional<std::string> Line = LE.readLine()) {
112
81
      if (*Line == R"(%quit)")
113
4
        break;
114
77
      if (*Line == R"(%undo)") {
115
3
        if (auto Err = Interp->Undo())
116
0
          llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: ");
117
3
        continue;
118
3
      }
119
120
74
      if (auto Err = Interp->ParseAndExecute(*Line))
121
0
        llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), "error: ");
122
74
    }
123
4
  }
124
125
  // Our error handler depends on the Diagnostics object, which we're
126
  // potentially about to delete. Uninstall the handler now so that any
127
  // later errors use the default handling behavior instead.
128
9
  llvm::remove_fatal_error_handler();
129
130
9
  llvm::llvm_shutdown();
131
132
9
  return checkDiagErrors(Interp->getCompilerInstance());
133
16
}