forked from chipsalliance/verible
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathlint_rule_status.h
232 lines (190 loc) · 8.51 KB
/
lint_rule_status.h
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
222
223
224
225
226
227
228
229
230
231
232
// 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.
// Used for reporting the outcome of a LintRule.
#ifndef VERIBLE_COMMON_ANALYSIS_LINT_RULE_STATUS_H_
#define VERIBLE_COMMON_ANALYSIS_LINT_RULE_STATUS_H_
#include <functional>
#include <iosfwd>
#include <set>
#include <string>
#include <vector>
#include "absl/strings/string_view.h"
#include "common/strings/line_column_map.h"
#include "common/text/symbol.h"
#include "common/text/syntax_tree_context.h"
#include "common/text/token_info.h"
#include "common/util/logging.h"
namespace verible {
// Represents a single replace operation on a text fragment.
//
// Either fragment or replacement can be strings with zero width, providing a
// way for, respectively, inserting and removing text.
//
// ReplacementEdit differs from editscript's Edit in that it stores a
// replacement string, so it doesn't need the "after" text to be useful.
struct ReplacementEdit {
ReplacementEdit(absl::string_view fragment, const std::string& replacement)
: fragment(fragment), replacement(replacement) {}
ReplacementEdit(const TokenInfo& token, const std::string& replacement)
: fragment(token.text()), replacement(replacement) {}
bool operator<(const ReplacementEdit& other) const {
// Check that the fragment is located before the other's fragment. When they
// overlap, `this<other` and `other<this` return false, which makes them
// equivalent in std::set.
return (fragment.data() + fragment.size()) <= other.fragment.data();
}
absl::string_view fragment;
std::string replacement;
};
// Collection of ReplacementEdits performing single violation fix.
class AutoFix {
public:
AutoFix() : description(), edits() {}
AutoFix(const AutoFix& other)
: description(other.description), edits(other.edits) {}
AutoFix(const AutoFix&& other)
: description(std::move(other.description)),
edits(std::move(other.edits)) {}
AutoFix(const std::string& description,
std::initializer_list<ReplacementEdit> edits)
: description(description), edits(edits) {
CHECK_EQ(this->edits.size(), edits.size()) << "Edits must not overlap.";
}
AutoFix(std::initializer_list<ReplacementEdit> edits)
: AutoFix("Fix", edits) {}
AutoFix(const std::string& description, ReplacementEdit edit)
: AutoFix(description, {edit}) {}
AutoFix(ReplacementEdit edit) : AutoFix({edit}) {}
// Applies the fix on a `base` and returns modified text.
std::string Apply(const absl::string_view base) const;
bool AddEdits(const std::set<ReplacementEdit>& new_edits);
const std::set<ReplacementEdit>& Edits() const { return edits; }
const std::string& Description() const { return description; }
private:
std::string description;
std::set<ReplacementEdit> edits;
};
// LintViolation is a class that represents a single rule violation.
struct LintViolation {
// This construct records a token stream lint violation.
LintViolation(const TokenInfo& token, const std::string& reason,
std::initializer_list<AutoFix> autofixes = {})
: root(nullptr),
token(token),
reason(reason),
context(),
autofixes(autofixes) {}
// This construct records a syntax tree lint violation.
// Use this variation when the violation can be localized to a single token.
LintViolation(const TokenInfo& token, const std::string& reason,
const SyntaxTreeContext& context,
std::initializer_list<AutoFix> autofixes = {})
: root(nullptr),
token(token),
reason(reason),
context(context),
autofixes(autofixes) {}
// This construct records a syntax tree lint violation.
// Use this variation when the range of violation is a subtree that spans
// multiple tokens. The violation will be reported at the location of
// the left-most leaf of the subtree.
LintViolation(const Symbol& root, const std::string& reason,
const SyntaxTreeContext& context,
std::initializer_list<AutoFix> autofixes = {});
// root is a reference into original ConcreteSyntaxTree that
// linter was run against. LintViolations should not outlive this tree.
// It should point to the root symbol that the linter failed on.
const Symbol* root = nullptr;
// The token at which the error occurs, which includes location information.
const TokenInfo token;
// The reason why the violation occurs.
std::string reason;
// The context (list of ancestors) of the offending token.
// For non-syntax-tree analyses, leave this blank.
const SyntaxTreeContext context;
const std::vector<AutoFix> autofixes;
bool operator<(const LintViolation& r) const {
// compares addresses of violations, which correspond to substring
// locations
return token.text().data() < r.token.text().data();
}
};
// LintRuleStatus represents the result of running a single lint rule.
struct LintRuleStatus {
LintRuleStatus() : violations() {}
LintRuleStatus(const std::set<LintViolation>& vs, absl::string_view rule_name,
const std::string& url)
: lint_rule_name(rule_name), url(url), violations(vs) {}
explicit LintRuleStatus(const std::set<LintViolation>& vs) : violations(vs) {}
bool isOk() const { return violations.empty(); }
// Remove subset of violations that is waived from report.
// If `is_waived`() is true, remove the finding from the set of violations.
void WaiveViolations(std::function<bool(const LintViolation&)>&& is_waived);
// Name of the lint rule that produced this status.
absl::string_view lint_rule_name;
// Hold link to engdoc summary of violated rule
std::string url;
// Contains all violations of the LintRule
std::set<LintViolation> violations;
};
// LintStatusFormatter is a class for printing LintRuleStatus's and
// LintViolations to an output stream
// Usage:
// string filename = ...
// string code_text = ...
// LintRuleStatus status = ...
// LintStatusFormatter formatter(code_text);
// formatter.FormatLintRuleStatus(&std::cout, status, filename)
class LintStatusFormatter {
public:
// Constructor takes a reference to the original text in order to setup
// line_column_map
explicit LintStatusFormatter(absl::string_view text)
: line_column_map_(text) {}
// Formats and outputs status to stream.
// Path is the file path of original file. This is needed because it is not
// contained in status.
// Base is the string_view of the entire contents, used only for byte offset
// calculation.
void FormatLintRuleStatus(std::ostream* stream, const LintRuleStatus& status,
absl::string_view base,
absl::string_view path) const;
// Formats, sorts and outputs status to stream with additional vulnerable code
// line printed when enabled.
// The violations contained in the statuses are sorted by their occurrence
// in the code and are not grouped by the status object.
// Path is the file path of original file. This is needed because it is not
// contained in status.
// Base is the string_view of the entire contents, used only for byte offset
// calculation.
void FormatLintRuleStatuses(
std::ostream* stream, const std::vector<LintRuleStatus>& statuses,
absl::string_view base, absl::string_view path,
const std::vector<absl::string_view>& lines) const;
// Formats and outputs violation on stream.
// Path is file path of original file and url is a link to the ratified rule
// that is being violated.
// Base is the string_view of the entire contents, used only for byte offset
// calculation.
void FormatViolation(std::ostream* stream, const LintViolation& violation,
absl::string_view base, absl::string_view path,
absl::string_view url,
absl::string_view rule_name) const;
private:
// Translates byte offsets, which are supplied by LintViolations via
// locations field, to line:column
LineColumnMap line_column_map_;
};
} // namespace verible
#endif // VERIBLE_COMMON_ANALYSIS_LINT_RULE_STATUS_H_