blob: 102f27f609216ff2eddad66e93b29d87a1aa4dd0 [file] [log] [blame]
// Copyright 2017-2021 The Verible Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef VERIBLE_COMMON_ANALYSIS_VIOLATION_HANDLER_H_
#define VERIBLE_COMMON_ANALYSIS_VIOLATION_HANDLER_H_
#include <functional>
#include <map>
#include <ostream>
#include <set>
#include "absl/strings/string_view.h"
#include "common/analysis/lint_rule_status.h"
namespace verible {
// Interface for implementing violation handlers.
//
// The linting process produces a list of violations found in source code. Those
// violations are then sorted and passed to `HandleViolations()` method of an
// instance passed to LintOneFile().
class ViolationHandler {
public:
virtual ~ViolationHandler() = default;
// This method is called with a list of sorted violations found in file
// located at `path`. It can be called multiple times with statuses generated
// from different files. `base` contains source code from the file.
virtual void HandleViolations(
const std::set<verible::LintViolationWithStatus>& violations,
absl::string_view base, absl::string_view path) = 0;
};
// ViolationHandler that prints all violations in a form of user-friendly
// messages.
class ViolationPrinter : public ViolationHandler {
public:
explicit ViolationPrinter(std::ostream* stream)
: stream_(stream), formatter_(nullptr) {}
void HandleViolations(
const std::set<verible::LintViolationWithStatus>& violations,
absl::string_view base, absl::string_view path) override;
protected:
std::ostream* const stream_;
verible::LintStatusFormatter* formatter_;
};
// ViolationHandler that prints all violations in a format required by
// --waiver_files flag
class ViolationWaiverPrinter : public ViolationHandler {
public:
explicit ViolationWaiverPrinter(std::ostream* message_stream_,
std::ostream* waiver_stream_)
: message_stream_(message_stream_),
waiver_stream_(waiver_stream_),
formatter_(nullptr) {}
void HandleViolations(
const std::set<verible::LintViolationWithStatus>& violations,
absl::string_view base, absl::string_view path) override;
protected:
std::ostream* const message_stream_;
std::ostream* const waiver_stream_;
verible::LintStatusFormatter* formatter_;
};
// ViolationHandler that prints all violations and gives an option to fix those
// that have autofixes available.
//
// By default, when violation has an autofix available, ViolationFixer asks an
// user what to do. The answers can be provided by AnswerChooser callback passed
// to the constructor as the answer_chooser parameter. The callback is called
// once for each fixable violation with a current violation object and a
// violated rule name as arguments, and must return one of the values from
// AnswerChoice enum.
//
// When the constructor's patch_stream parameter is not null, the fixes are
// written to specified stream in unified diff format. Otherwise the fixes are
// applied directly to the source file.
//
// The HandleLintRuleStatuses method can be called multiple times with statuses
// generated from different files. The state of answers like "apply all for
// rule" or "apply all" is kept between the calls.
class ViolationFixer : public verible::ViolationHandler {
public:
enum class AnswerChoice {
kUnknown,
kApply, // apply fix
kReject, // reject fix
kApplyAllForRule, // apply this and all remaining fixes for violations
// of this rule
kRejectAllForRule, // reject this and all remaining fixes for violations
// of this rule
kApplyAll, // apply this and all remaining fixes
kRejectAll, // reject this and all remaining fixes
kPrintFix, // show fix
kPrintAppliedFixes, // show fixes applied so far
};
struct Answer {
AnswerChoice choice;
// If there are multiple alternatives for fixes available, this is
// the one chosen. By default the first one.
size_t alternative = 0;
};
using AnswerChooser =
std::function<Answer(const verible::LintViolation&, absl::string_view)>;
// Violation fixer with user-chosen answer chooser.
ViolationFixer(std::ostream* message_stream, std::ostream* patch_stream,
const AnswerChooser& answer_chooser)
: ViolationFixer(message_stream, patch_stream, answer_chooser, false) {}
// Violation fixer with interactive answer choice.
ViolationFixer(std::ostream* message_stream, std::ostream* patch_stream)
: ViolationFixer(message_stream, patch_stream, InteractiveAnswerChooser,
true) {}
void HandleViolations(
const std::set<verible::LintViolationWithStatus>& violations,
absl::string_view base, absl::string_view path) final;
private:
ViolationFixer(std::ostream* message_stream, std::ostream* patch_stream,
const AnswerChooser& answer_chooser, bool is_interactive)
: message_stream_(message_stream),
patch_stream_(patch_stream),
answer_chooser_(answer_chooser),
is_interactive_(is_interactive),
ultimate_answer_({AnswerChoice::kUnknown, 0}) {}
void HandleViolation(const verible::LintViolation& violation,
absl::string_view base, absl::string_view path,
absl::string_view url, absl::string_view rule_name,
const verible::LintStatusFormatter& formatter,
verible::AutoFix* fix);
static Answer InteractiveAnswerChooser(
const verible::LintViolation& violation, absl::string_view rule_name);
void CommitFixes(absl::string_view source_content,
absl::string_view source_path,
const verible::AutoFix& fix) const;
std::ostream* const message_stream_;
std::ostream* const patch_stream_;
const AnswerChooser answer_chooser_;
const bool is_interactive_;
Answer ultimate_answer_;
std::map<absl::string_view, Answer> rule_answers_;
};
} // namespace verible
#endif // VERIBLE_COMMON_ANALYSIS_VIOLATION_HANDLER_H_