blob: 92cb4fa6224e6091537947a3e764f58f8e1da382 [file] [log] [blame]
// Copyright 2017 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef TOOLS_FIDL_FIDLC_INCLUDE_FIDL_REPORTER_H_
#define TOOLS_FIDL_FIDLC_INCLUDE_FIDL_REPORTER_H_
#include <algorithm>
#include <cassert>
#include <optional>
#include <sstream>
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include "diagnostics.h"
#include "source_span.h"
#include "token.h"
#include "utils.h"
namespace fidl {
using utils::identity_t;
class Reporter {
public:
Reporter() = default;
Reporter(const Reporter&) = delete;
Reporter(Reporter&&) = default;
class Counts {
public:
explicit Counts(const Reporter* reporter)
: reporter_(reporter), num_errors_(reporter->errors().size()) {}
bool NoNewErrors() const { return NumNewErrors() == 0; }
size_t NumNewErrors() const { return reporter_->errors().size() - num_errors_; }
private:
const Reporter* reporter_;
const size_t num_errors_;
};
template <typename... Args>
bool Fail(const ErrorDef<Args...>& def, SourceSpan span, const identity_t<Args>&... args) {
Report(Diagnostic::MakeError(def, span, args...));
return false;
}
template <typename... Args>
void Warn(const WarningDef<Args...>& def, SourceSpan span, const identity_t<Args>&... args) {
Report(Diagnostic::MakeWarning(def, span, args...));
}
// Reports an error or warning.
void Report(std::unique_ptr<Diagnostic> diag);
// Combines errors and warnings and sorts by (file, span).
std::vector<Diagnostic*> Diagnostics() const;
// Prints a report based on Diagnostics() in text format, with ANSI color
// escape codes if enable_color is true.
void PrintReports(bool enable_color) const;
// Prints a report based on Diagnostics() in JSON format.
void PrintReportsJson() const;
// Creates a checkpoint. This lets you detect how many new errors
// have been added since the checkpoint.
Counts Checkpoint() const { return Counts(this); }
const std::vector<std::unique_ptr<Diagnostic>>& errors() const { return errors_; }
const std::vector<std::unique_ptr<Diagnostic>>& warnings() const { return warnings_; }
void set_warnings_as_errors(bool value) { warnings_as_errors_ = value; }
// Formats a diagnostic message for the command line, displaying the filename,
// line, column, diagnostic kind, and the full line where the span occurs,
// with the span indicated by an ASCII "squiggle" below it. Optionally adds
// color via ANSI escape codes.
static std::string Format(std::string_view qualifier, SourceSpan span, std::string_view message,
bool color);
private:
void AddError(std::unique_ptr<Diagnostic> error);
void AddWarning(std::unique_ptr<Diagnostic> warning);
bool warnings_as_errors_ = false;
// The reporter collects error and warnings separately so that we can easily
// keep track of the current number of errors during compilation. The number
// of errors is used to determine whether the parser is in an `Ok` state.
std::vector<std::unique_ptr<Diagnostic>> errors_;
std::vector<std::unique_ptr<Diagnostic>> warnings_;
};
// ReporterMixin enables classes to call certain Reporter methods unqualified.
// It is meant to be used with private or protected inheritance. For example:
//
// class Foo : private ReporterMixin {
// Foo(Reporter* r) : ReporterMixin(r) {}
// void DoSomething() {
// if (/* ... */) Fail(...); // instead of reporter_->Fail(...);
// }
// };
//
// Note: All ReporterMixin methods must be const, otherwise classes using the
// mixin would not be able to call them in const contexts.
class ReporterMixin {
public:
explicit ReporterMixin(Reporter* reporter) : reporter_(reporter) {}
Reporter* reporter() const { return reporter_; }
void Report(std::unique_ptr<Diagnostic> diag) const { reporter_->Report(std::move(diag)); }
template <typename... Args>
bool Fail(const ErrorDef<Args...>& def, SourceSpan span, const identity_t<Args>&... args) const {
return reporter_->Fail(def, span, args...);
}
template <typename... Args>
void Warn(const WarningDef<Args...>& def, SourceSpan span,
const identity_t<Args>&... args) const {
reporter_->Warn(def, span, args...);
}
private:
Reporter* reporter_;
};
} // namespace fidl
#endif // TOOLS_FIDL_FIDLC_INCLUDE_FIDL_REPORTER_H_