blob: b89e7fed99aaceb3cb1f865e7791b1cd38307f5f [file] [log] [blame]
// Part of the Crubit project, under the Apache License v2.0 with LLVM
// Exceptions. See /LICENSE for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#ifndef THIRD_PARTY_CRUBIT_RS_BINDINGS_FROM_CC_RECORDING_DIAGNOSTIC_CONSUMER_H_
#define THIRD_PARTY_CRUBIT_RS_BINDINGS_FROM_CC_RECORDING_DIAGNOSTIC_CONSUMER_H_
#include <functional>
#include <memory>
#include <string>
#include <vector>
#include "absl/strings/string_view.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/LLVM.h"
#include "clang/Basic/SourceLocation.h"
#include "llvm/ADT/SmallString.h"
namespace crubit {
class RecordingDiagnosticConsumer final : public clang::DiagnosticConsumer {
public:
void HandleDiagnostic(clang::DiagnosticsEngine::Level diagnostic_level,
const clang::Diagnostic& info) override;
void clear() override;
struct Diagnostic {
unsigned diagnostic_id;
clang::DiagnosticsEngine::Level diagnostic_level;
clang::PresumedLoc source_location;
// The size of 64 is chosen based on just a few diagnostics; adjust as
// needed.
llvm::SmallString<64> diagnostic;
std::string FormattedDiagnostics() const;
};
const std::vector<Diagnostic>& GetDiagnostics() const {
return diagnostics_;
};
std::string ConcatenatedDiagnostics(absl::string_view prefix = "") const;
private:
std::vector<Diagnostic> diagnostics_;
};
/// A function that records the diagnostics emitted by `diagnostic_engine` while
/// running the `callback`, by swapping `diagonostic_engine`'s original
/// diagnostic client with a newly-created `RecordingDiagnosticConsumer` before
/// invoking the callback and restoring the original diagnostic consumer when
/// done.
/// Why? `clang::Sema` methods may fail (e.g., `IsCompleteType`) and the
/// emitted (fatal) diagnostic is sent to the original diagnostic consumer,
/// which causes `clang::tooling::runToolOnCodeWithArgs` to return an error
/// status, which then causes Crubit to exit with failure. In some cases,
/// it's OK for these methods to fail (e.g., to find out if a template
/// specialization can be instantiated and should thus be imported), so it
/// would be helpful to temporarily avoid sending the diagnostics for these
/// fallable attempts to the original diagnostic consumer, and this is where
/// this 'trap' becomes useful.
RecordingDiagnosticConsumer RecordDiagnostics(
clang::DiagnosticsEngine& diagnostic_engine,
std::function<void(void)> callback);
} // namespace crubit
#endif // THIRD_PARTY_CRUBIT_RS_BINDINGS_FROM_CC_RECORDING_DIAGNOSTIC_CONSUMER_H_