Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 11 additions & 11 deletions src/helpers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,14 @@ impl<'src> QueryHelper<'src> {
///
/// Panics if Tree-sitter fails to parse the query.
#[must_use]
pub fn new(query_src: &str, tree: &'src Tree, code: &'src [u8]) -> Self {
pub fn new(query_src: &str, tree: &'src Tree, code: &'src str) -> Self {
let query =
Query::new(&tree_sitter_c::LANGUAGE.into(), query_src).expect("Failed to parse query");
Self { query, tree, code }
Self {
query,
tree,
code: code.as_bytes(),
}
}

/// Returns a reference to this helper's query.
Expand Down Expand Up @@ -222,7 +226,7 @@ impl<'src> QueryHelper<'src> {
/// - the node's text is not valid UTF-8
///
#[must_use]
pub fn function_definition_name<'code>(node: Node, code: &'code [u8]) -> &'code str {
pub fn function_definition_name<'code>(node: Node, code: &'code str) -> &'code str {
assert_eq!(
"function_definition",
node.kind(),
Expand All @@ -235,7 +239,7 @@ pub fn function_definition_name<'code>(node: Node, code: &'code [u8]) -> &'code
.child_by_field_name("declarator")
.expect("Expected node to have a `declarator' field");
}
node.utf8_text(code).expect("Code is not valid UTF-8")
&code[node.byte_range()]
}

/// Gets the number of columns by which this line is indented. Tab characters (U+0009 or `'\t'`)
Expand Down Expand Up @@ -434,14 +438,10 @@ mod test {
let mut parser = Parser::new();
parser.set_language(&tree_sitter_c::LANGUAGE.into()).unwrap();
let tree = parser.parse(code.as_bytes(), None).unwrap();
let helper =
QueryHelper::new("(function_definition) @function", &tree, code.as_bytes());
let helper = QueryHelper::new("(function_definition) @function", &tree, code);
helper.for_each_capture(|label, capture| {
assert_eq!("function", label);
assert_eq!(
expected_name,
super::function_definition_name(capture.node, code.as_bytes())
);
assert_eq!(expected_name, super::function_definition_name(capture.node, code));
});
}
}
Expand Down Expand Up @@ -478,7 +478,7 @@ mod test {
let mut parser = Parser::new();
parser.set_language(&tree_sitter_c::LANGUAGE.into()).unwrap();
let tree = parser.parse(code.as_bytes(), None).unwrap();
let helper = QueryHelper::new("(preproc_def) @define", &tree, code.as_bytes());
let helper = QueryHelper::new("(preproc_def) @define", &tree, code);
helper.for_each_capture(|_label, capture| ranges.push(capture.node.range()));
let mut collapser = RangeCollapser::from(ranges.clone());
let group1 = collapser.next().unwrap();
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/testing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ pub fn test_captures(query: &str, input: &str) -> ExitCode {
let mut parser = Parser::new();
parser.set_language(&tree_sitter_c::LANGUAGE.into()).unwrap();
let tree = parser.parse(&code, None).unwrap();
let helper = QueryHelper::new(query, &tree, code.as_bytes());
let helper = QueryHelper::new(query, &tree, &code);
let mut failed = false;
helper.for_each_capture(|label, capture| {
let start = capture.node.start_position();
Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ fn main() -> ExitCode {
// Do checks
let rules: Vec<Box<dyn Rule>> = crate::rules::get_rules();
for rule in rules {
let diagnostics = rule.check(&tree, code.as_bytes());
let diagnostics = rule.check(&tree, &code);
for diagnostic in diagnostics {
match cli.format {
OutputFormat::Pretty => {
Expand Down
2 changes: 1 addition & 1 deletion src/rules/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ pub trait Rule {
/// - `tree`: [`Tree`] representing the file.
/// - `code`: Text/code of the given file.
#[must_use]
fn check(&self, tree: &Tree, code: &[u8]) -> Vec<Diagnostic<()>>;
fn check(&self, tree: &Tree, code: &str) -> Vec<Diagnostic<()>>;
}
6 changes: 2 additions & 4 deletions src/rules/rule01a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ const QUERY_STR: &str = indoc! { /* query */ r#"
pub struct Rule01a {}

impl Rule for Rule01a {
fn check(&self, tree: &Tree, code: &[u8]) -> Vec<Diagnostic<()>> {
fn check(&self, tree: &Tree, code: &str) -> Vec<Diagnostic<()>> {
let helper = QueryHelper::new(QUERY_STR, tree, code);
let mut diagnostics = Vec::new();
helper.for_each_capture(|_label, capture| {
Expand All @@ -86,9 +86,7 @@ impl Rule for Rule01a {
)
.with_label(Label::secondary((), capture.node.byte_range()).with_message(format!(
"Perhaps you meant `{}'",
guess_lower_snake_case(
capture.node.utf8_text(code).expect("Code is not valid UTF-8")
)
guess_lower_snake_case(&code[capture.node.byte_range()])
)));
diagnostics.push(diagnostic);
});
Expand Down
2 changes: 1 addition & 1 deletion src/rules/rule01b.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ use crate::rules::api::Rule;
pub struct Rule01b {}

impl Rule for Rule01b {
fn check(&self, _tree: &Tree, _code: &[u8]) -> Vec<Diagnostic<()>> {
fn check(&self, _tree: &Tree, _code: &str) -> Vec<Diagnostic<()>> {
Vec::with_capacity(0)
}
}
4 changes: 2 additions & 2 deletions src/rules/rule01c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ const QUERY_STR: &str = indoc! { /* query */ r#"
pub struct Rule01c {}

impl Rule for Rule01c {
fn check(&self, tree: &Tree, code: &[u8]) -> Vec<Diagnostic<()>> {
fn check(&self, tree: &Tree, code: &str) -> Vec<Diagnostic<()>> {
let helper = QueryHelper::new(QUERY_STR, tree, code);
let mut diagnostics = Vec::new();
helper.for_each_capture(|name: &str, capture: QueryCapture| {
let node_text = capture.node.utf8_text(code).expect("Code is not valid UTF-8");
let node_text = &code[capture.node.byte_range()];
let (message, label, fix) = match name {
"constant.name.short" => (
"Constant name must contain at least 2 characters",
Expand Down
7 changes: 2 additions & 5 deletions src/rules/rule01d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ const QUERY_STR: &str = indoc! {
pub struct Rule01d {}

impl Rule for Rule01d {
fn check(&self, tree: &Tree, code: &[u8]) -> Vec<Diagnostic<()>> {
fn check(&self, tree: &Tree, code: &str) -> Vec<Diagnostic<()>> {
let helper = QueryHelper::new(QUERY_STR, tree, code);
let mut first_function_position = None;
let mut diagnostics = Vec::new();
Expand All @@ -90,10 +90,7 @@ impl Rule for Rule01d {
.with_message("Variable declared here"),
)
.with_label(Label::secondary((), capture.node.byte_range()).with_message(
format!(
"Perhaps you meant `g_{}'",
capture.node.utf8_text(code).expect("Code is not valid UTF-8")
),
format!("Perhaps you meant `g_{}'", &code[capture.node.byte_range()]),
))
}
"declaration.top_level" => {
Expand Down
11 changes: 4 additions & 7 deletions src/rules/rule02a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,10 @@ const QUERY_STR: &str = indoc! { /* query */ r##"
"## };

impl Rule for Rule02a {
fn check(&self, tree: &Tree, code_bytes: &[u8]) -> Vec<Diagnostic<()>> {
fn check(&self, tree: &Tree, code: &str) -> Vec<Diagnostic<()>> {
let mut diagnostics = Vec::new();

// Check for lines >80 columns long
let code = std::str::from_utf8(code_bytes).expect("Code is not valid UTF-8");
for (line, index) in LinesWithPosition::from(code) {
let width = line_width(line);
if width > 80 {
Expand All @@ -122,7 +121,7 @@ impl Rule for Rule02a {
}
}

let helper = QueryHelper::new(QUERY_STR, tree, code_bytes);
let helper = QueryHelper::new(QUERY_STR, tree, code);
let splittable_capture_i = helper.expect_index_for_capture("splittable");
let splittable_begin_capture_i = helper.expect_index_for_capture("splittable.begin");
let splittable_end_capture_i = helper.expect_index_for_capture("splittable.end");
Expand Down Expand Up @@ -157,9 +156,7 @@ impl Rule for Rule02a {
}

// Check indentation of wrapped lines and construct list of labels
let mut code_lines = LinesWithPosition::from(
std::str::from_utf8(code_bytes).expect("Code is not valid UTF-8"),
)
let mut code_lines = LinesWithPosition::from(code)
.skip(range.start_point.row)
.take(range.end_point.row + 1 - range.start_point.row);
let (first_line, first_line_byte_pos) = code_lines.next().unwrap();
Expand Down Expand Up @@ -337,7 +334,7 @@ mod tests {
code.push_str("}\n");
dbg!(&code);
let tree = parser.parse(code.as_bytes(), None).unwrap();
let diagnostics = rule.check(&tree, code.as_bytes());
let diagnostics = rule.check(&tree, &code);
assert_eq!($ndiag, diagnostics.len());
let nlabels_list: &[usize] = &$nlabels_list;
assert_eq!(
Expand Down
4 changes: 2 additions & 2 deletions src/rules/rule02b.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const QUERY_STR: &str = indoc! {
pub struct Rule02b {}

impl Rule for Rule02b {
fn check(&self, tree: &Tree, code: &[u8]) -> Vec<Diagnostic<()>> {
fn check(&self, tree: &Tree, code: &str) -> Vec<Diagnostic<()>> {
let helper = QueryHelper::new(QUERY_STR, tree, code);
let mut diagnostics = Vec::new();
helper.for_each_capture(|label: &str, capture: QueryCapture| match label {
Expand Down Expand Up @@ -110,7 +110,7 @@ mod tests {
let tree = parser.parse(code.as_bytes(), None).unwrap();
let rule02b = Rule02b {};
assert_eq!(
rule02b.check(&tree, code.as_bytes()),
rule02b.check(&tree, &code),
vec![Diagnostic::warning()
.with_code("II:B")
.with_message(format!(
Expand Down
12 changes: 4 additions & 8 deletions src/rules/rule03a.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ const QUERY_STR: &str = indoc! {
pub struct Rule03a {}

impl Rule for Rule03a {
fn check(&self, tree: &Tree, code: &[u8]) -> Vec<Diagnostic<()>> {
fn check(&self, tree: &Tree, code: &str) -> Vec<Diagnostic<()>> {
let mut diagnostics = Vec::new();

// Part 1: Space between parentheses and braces
Expand Down Expand Up @@ -119,10 +119,7 @@ impl Rule for Rule03a {
// Check spacing between keyword and (
let keyword = helper.expect_node_for_capture_index(qmatch, keyword_capture_i);
let lparen = helper.expect_node_for_capture_index(qmatch, lparen_capture_i);
let message = format!(
"Expected a single space after `{}'",
keyword.utf8_text(code).expect("Code is not valid UTF-8")
);
let message = format!("Expected a single space after `{code}'");
if let Some(diagnostic) = check_single_space_between(keyword, lparen, code, &message) {
diagnostics.push(diagnostic);
}
Expand All @@ -137,13 +134,12 @@ impl Rule for Rule03a {
fn check_single_space_between(
left: Node,
right: Node,
code: &[u8],
code: &str,
message: &str,
) -> Option<Diagnostic<()>> {
if (left.end_byte() + 1) == right.start_byte() {
// One byte in between
// TODO: Support multi-byte UTF-8 characters here, not just bytes
if (code[left.end_byte()] as char) == ' ' {
if code.as_bytes()[left.end_byte()] == b' ' {
// Valid
return None;
}
Expand Down
9 changes: 4 additions & 5 deletions src/rules/rule03b.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ const QUERY_STR_FIELD: &str = indoc! {
pub struct Rule03b {}

impl Rule for Rule03b {
fn check(&self, tree: &Tree, code: &[u8]) -> Vec<Diagnostic<()>> {
fn check(&self, tree: &Tree, code: &str) -> Vec<Diagnostic<()>> {
let mut diagnostics = Vec::new();

// Binary expressions
Expand Down Expand Up @@ -180,7 +180,7 @@ fn check_binary_op_spacing(
op: Node,
left: Node,
right: Node,
code: &[u8],
code: &str,
) -> Option<Diagnostic<()>> {
// If the adjacent items are on the same line, check that there's a single space between them.
// If they're on separate lines, we do nothing, and leave it to Rule II:A to check the
Expand Down Expand Up @@ -243,9 +243,8 @@ fn check_field_op_spacing(op: Node, left: Node, right: Node) -> Option<Diagnosti
}

/// Returns `true` if there is a single space separating the two nodes, else `false`.
fn is_single_space_between(left: Node, right: Node, code: &[u8]) -> bool {
// TODO: Support UTF-8, not just bytes
left.end_byte() + 1 == right.start_byte() && code[left.end_byte()] as char == ' '
fn is_single_space_between(left: Node, right: Node, code: &str) -> bool {
left.end_byte() + 1 == right.start_byte() && code.as_bytes()[left.end_byte()] == b' '
}

#[cfg(test)]
Expand Down
6 changes: 3 additions & 3 deletions src/rules/rule03c.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const QUERY_STR: &str = indoc! {
pub struct Rule03c {}

impl Rule for Rule03c {
fn check(&self, tree: &Tree, code: &[u8]) -> Vec<Diagnostic<()>> {
fn check(&self, tree: &Tree, code: &str) -> Vec<Diagnostic<()>> {
let mut diagnostics = Vec::new();
let helper = QueryHelper::new(QUERY_STR, tree, code);
let delim_capture_i = helper.expect_index_for_capture("delim");
Expand Down Expand Up @@ -91,9 +91,9 @@ impl Rule for Rule03c {
}

/// Returns `true` if the two nodes are separated by a single space and `false` otherwise.
fn is_single_space_between(left: Node, right: Node, code: &[u8]) -> bool {
fn is_single_space_between(left: Node, right: Node, code: &str) -> bool {
// TODO: Support UTF-8 and not just bytes
(left.end_byte() + 1) == right.start_byte() && (code[left.end_byte()] as char) == ' '
(left.end_byte() + 1) == right.start_byte() && code.as_bytes()[left.end_byte()] == b' '
}

#[cfg(test)]
Expand Down
18 changes: 8 additions & 10 deletions src/rules/rule03d.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ const QUERY_STR: &str = indoc! {
pub struct Rule03d {}

impl Rule for Rule03d {
fn check(&self, tree: &Tree, code: &[u8]) -> Vec<Diagnostic<()>> {
fn check(&self, tree: &Tree, code: &str) -> Vec<Diagnostic<()>> {
// List of function definition bodies
let mut function_bodies: Vec<Node> = Vec::new();
// List of #define statements
Expand Down Expand Up @@ -150,9 +150,7 @@ impl Rule for Rule03d {
}

// Get lines of the source
let lines: Vec<(&str, usize)> =
LinesWithPosition::from(std::str::from_utf8(code).expect("Code is not valid UTF-8"))
.collect();
let lines: Vec<(&str, usize)> = LinesWithPosition::from(code).collect();

// Collapse #define statements into groups
let define_groups = RangeCollapser::from(definitions.into_iter().map(|def| def.range()));
Expand Down Expand Up @@ -290,8 +288,8 @@ impl Rule for Rule03d {

/// Returns the byte range of a [Node], excluding the trailing end-of-line sequence if it was
/// included in the node's range.
fn range_without_trailing_eol(mut range: Range<usize>, code: &[u8]) -> Range<usize> {
match &code[(range.end - 2)..range.end] {
fn range_without_trailing_eol(mut range: Range<usize>, code: &str) -> Range<usize> {
match &code.as_bytes()[(range.end - 2)..range.end] {
[b'\r', b'\n'] => range.end -= 2,
[_, b'\n'] => range.end -= 1,
_ => (),
Expand Down Expand Up @@ -327,7 +325,7 @@ mod tests {
parser.set_language(&tree_sitter_c::LANGUAGE.into()).unwrap();
let tree = parser.parse(code.as_bytes(), None).unwrap();
let rule = Rule03d {};
let diagnostics = rule.check(&tree, code.as_bytes());
let diagnostics = rule.check(&tree, code);
// Expect 1 diagnostic for the whole group.
assert_eq!(1, diagnostics.len());
}
Expand All @@ -341,7 +339,7 @@ mod tests {
parser.set_language(&tree_sitter_c::LANGUAGE.into()).unwrap();
let tree = parser.parse(code.as_bytes(), None).unwrap();
let rule = Rule03d {};
let diagnostics = rule.check(&tree, code.as_bytes());
let diagnostics = rule.check(&tree, code);
assert_eq!(1, diagnostics.len());
assert_eq!(code.lines().last().unwrap(), &code[diagnostics[0].labels[0].range.clone()]);
}
Expand All @@ -355,7 +353,7 @@ mod tests {
parser.set_language(&tree_sitter_c::LANGUAGE.into()).unwrap();
let tree = parser.parse(code.as_bytes(), None).unwrap();
let rule = Rule03d {};
let diagnostics = rule.check(&tree, code.as_bytes());
let diagnostics = rule.check(&tree, code);
assert!(diagnostics.is_empty());
}

Expand All @@ -368,7 +366,7 @@ mod tests {
parser.set_language(&tree_sitter_c::LANGUAGE.into()).unwrap();
let tree = parser.parse(code.as_bytes(), None).unwrap();
let rule = Rule03d {};
let diagnostics = rule.check(&tree, code.as_bytes());
let diagnostics = rule.check(&tree, code);
// Sanity checks
assert_eq!(1, diagnostics.len());
assert_eq!(LabelStyle::Primary, diagnostics[0].labels[0].style);
Expand Down
7 changes: 3 additions & 4 deletions src/rules/rule03e.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,9 @@ use crate::{helpers::LinesWithPosition, rules::api::Rule};
pub struct Rule03e {}

impl Rule for Rule03e {
fn check(&self, _tree: &Tree, code: &[u8]) -> Vec<Diagnostic<()>> {
fn check(&self, _tree: &Tree, code: &str) -> Vec<Diagnostic<()>> {
let mut diagnostics = Vec::new();
let code_str = std::str::from_utf8(code).expect("Code is not valid UTF-8");
for (line, index) in LinesWithPosition::from(code_str) {
for (line, index) in LinesWithPosition::from(code) {
let trimmed_line = line.trim_end();
if trimmed_line.len() != line.len() {
// Start/end of trailing whitespace
Expand Down Expand Up @@ -67,7 +66,7 @@ mod tests {
parser.set_language(&tree_sitter_c::LANGUAGE.into()).unwrap();
let tree = parser.parse(code, None).unwrap();
let rule = Rule03e {};
let diagnostics = rule.check(&tree, code.as_bytes());
let diagnostics = rule.check(&tree, code);
assert_eq!(2, diagnostics.len());
}
}
2 changes: 1 addition & 1 deletion src/rules/rule03f.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const QUERY_STR: &str = indoc! {
pub struct Rule03f {}

impl Rule for Rule03f {
fn check(&self, tree: &Tree, code: &[u8]) -> Vec<Diagnostic<()>> {
fn check(&self, tree: &Tree, code: &str) -> Vec<Diagnostic<()>> {
let mut diagnostics = Vec::new();
let helper = QueryHelper::new(QUERY_STR, tree, code);
let function_capture_i = helper.expect_index_for_capture("function");
Expand Down
Loading
Loading