forked from chipsalliance/verible
-
Notifications
You must be signed in to change notification settings - Fork 0
/
verilog_lint.cc
221 lines (194 loc) · 8.09 KB
/
verilog_lint.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
// Copyright 2017-2020 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.
// verilog_lint is a command-line utility to check Verilog syntax
// and style compliance for the given file.
//
// Example usage:
// verilog_lint files...
#include <fstream>
#include <iostream>
#include <memory>
#include <sstream> // IWYU pragma: keep // for ostringstream
#include <string> // for string, allocator, etc
#include <vector>
#include "absl/flags/flag.h"
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "common/analysis/violation_handler.h"
#include "common/util/enum_flags.h"
#include "common/util/file_util.h"
#include "common/util/init_command_line.h"
#include "common/util/logging.h" // for operator<<, LOG, LogMessage, etc
#include "verilog/analysis/verilog_linter.h"
#include "verilog/analysis/verilog_linter_configuration.h"
// From least to most disruptive
enum class AutofixMode {
kNo, // No Autofixes
kPatchInteractive, // Interactively choose fixes, generate patch
kPatch, // Emit a patch
kInplaceInteractive, // Interactively choose fixes, apply inplace
kInplace, // Automatically apply patch in-place.
kGenerateWaiver, // Generate waiver file for violations
};
static const verible::EnumNameMap<AutofixMode>& AutofixModeEnumStringMap() {
static const verible::EnumNameMap<AutofixMode> kAutofixModeEnumStringMap({
{"no", AutofixMode::kNo},
{"patch-interactive", AutofixMode::kPatchInteractive},
{"patch", AutofixMode::kPatch},
{"inplace-interactive", AutofixMode::kInplaceInteractive},
{"inplace", AutofixMode::kInplace},
{"generate-waiver", AutofixMode::kGenerateWaiver},
});
return kAutofixModeEnumStringMap;
}
std::ostream& operator<<(std::ostream& stream, AutofixMode mode) {
return AutofixModeEnumStringMap().Unparse(mode, stream);
}
std::string AbslUnparseFlag(const AutofixMode& mode) {
std::ostringstream stream;
AutofixModeEnumStringMap().Unparse(mode, stream);
return stream.str();
}
bool AbslParseFlag(absl::string_view text, AutofixMode* mode,
std::string* error) {
return AutofixModeEnumStringMap().Parse(text, mode, error, "--autofix value");
}
// LINT.IfChange
ABSL_FLAG(bool, check_syntax, true,
"If true, check for lexical and syntax errors, otherwise ignore.");
ABSL_FLAG(bool, parse_fatal, true,
"If true, exit nonzero if there are any syntax errors.");
ABSL_FLAG(bool, lint_fatal, true,
"If true, exit nonzero if linter finds violations.");
ABSL_FLAG(std::string, help_rules, "",
"[all|<rule-name>], print the description of one rule/all rules "
"and exit immediately.");
ABSL_FLAG(
bool, generate_markdown, false,
"If true, print the description of every rule formatted for the "
"Markdown and exit immediately. Intended for the output to be written "
"to a snippet of Markdown.");
ABSL_FLAG(bool, show_diagnostic_context, false,
"prints an additional "
"line on which the diagnostic was found,"
"followed by a line with a position marker");
ABSL_FLAG(
AutofixMode, autofix, AutofixMode::kNo,
"autofix mode; one of "
"[no|patch-interactive|patch|inplace-interactive|inplace|generate-waiver]");
ABSL_FLAG(std::string, autofix_output_file, "",
"File to write a patch with autofixes to if "
"--autofix=patch or --autofix=patch-interactive "
"or a waiver file if --autofix=generate-waiver");
// LINT.ThenChange(README.md)
using verilog::LinterConfiguration;
// LintOneFile returns 0, 1, or 2
static const int kAutofixErrorExitStatus = 3;
int main(int argc, char** argv) {
const auto usage =
absl::StrCat("usage: ", argv[0], " [options] <file> [<file>...]");
const auto args = verible::InitCommandLine(usage, &argc, &argv);
std::string help_flag = absl::GetFlag(FLAGS_help_rules);
if (!help_flag.empty()) {
verilog::GetLintRuleDescriptionsHelpFlag(&std::cout, help_flag);
return 0;
}
// In documentation generation mode, print documentation and exit immediately.
bool generate_markdown_flag = absl::GetFlag(FLAGS_generate_markdown);
if (generate_markdown_flag) {
verilog::GetLintRuleDescriptionsMarkdown(&std::cout);
return 0;
}
int exit_status = 0;
AutofixMode autofix_mode = absl::GetFlag(FLAGS_autofix);
const std::string autofix_output_file =
absl::GetFlag(FLAGS_autofix_output_file);
std::unique_ptr<std::ostream> stream_closer;
std::ostream* autofix_output_stream = nullptr;
if (autofix_mode == AutofixMode::kPatch ||
autofix_mode == AutofixMode::kPatchInteractive ||
autofix_mode == AutofixMode::kGenerateWaiver) {
if (autofix_output_file.empty() || autofix_output_file == "-") {
autofix_output_stream = &std::cout;
} else {
stream_closer.reset(new std::ofstream(autofix_output_file));
if (stream_closer->good()) {
autofix_output_stream = stream_closer.get();
} else {
LOG(ERROR) << "Failed to create/open output patch file: "
<< autofix_output_file;
}
}
if (!autofix_output_stream) {
std::cerr << "--autofix=patch needs --autofix_output_file" << std::endl;
autofix_mode = AutofixMode::kNo;
exit_status = kAutofixErrorExitStatus;
}
} else if (!autofix_output_file.empty()) {
std::cerr << "--autofix_output_file has no effect for --autofix="
<< autofix_mode << std::endl;
}
const verible::ViolationFixer::AnswerChooser applyAllFixes =
[](const verible::LintViolation&,
absl::string_view) -> verible::ViolationFixer::Answer {
return {verible::ViolationFixer::AnswerChoice::kApplyAll, 0};
};
std::unique_ptr<verible::ViolationHandler> violation_handler;
switch (autofix_mode) {
case AutofixMode::kNo:
violation_handler.reset(new verible::ViolationPrinter(&std::cerr));
break;
case AutofixMode::kPatchInteractive:
CHECK(autofix_output_stream);
violation_handler.reset(
new verible::ViolationFixer(&std::cerr, autofix_output_stream));
break;
case AutofixMode::kPatch:
CHECK(autofix_output_stream);
violation_handler.reset(new verible::ViolationFixer(
&std::cerr, autofix_output_stream, applyAllFixes));
break;
case AutofixMode::kInplaceInteractive:
violation_handler.reset(new verible::ViolationFixer(&std::cerr, nullptr));
break;
case AutofixMode::kInplace:
violation_handler.reset(
new verible::ViolationFixer(&std::cerr, nullptr, applyAllFixes));
break;
case AutofixMode::kGenerateWaiver:
violation_handler.reset(new verible::ViolationWaiverPrinter(
&std::cerr, autofix_output_stream));
break;
}
// All positional arguments are file names. Exclude program name.
for (const absl::string_view filename :
verible::make_range(args.begin() + 1, args.end())) {
// Copy configuration, so that it can be locally modified per file.
auto config_status = verilog::LinterConfigurationFromFlags(filename);
if (!config_status.ok()) {
std::cerr << config_status.status().message() << std::endl;
exit_status = 1;
continue;
}
const LinterConfiguration& config = *config_status;
const int lint_status = verilog::LintOneFile(
&std::cout, filename, config, violation_handler.get(),
absl::GetFlag(FLAGS_check_syntax), absl::GetFlag(FLAGS_parse_fatal),
absl::GetFlag(FLAGS_lint_fatal),
absl::GetFlag(FLAGS_show_diagnostic_context));
exit_status = std::max(lint_status, exit_status);
} // for each file
return exit_status;
}