From 7b3ad3a3da020d81f927ce850d26cbe8455148ce Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:32:20 -0800 Subject: [PATCH 01/53] Add c-sharp (with class query) --- Cargo.lock | 11 +++++++++++ Cargo.toml | 1 + qlty-analysis/Cargo.toml | 1 + qlty-analysis/src/lang.rs | 4 +++- qlty-analysis/src/lang/c_sharp.rs | 13 +++++++++++++ 5 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 qlty-analysis/src/lang/c_sharp.rs diff --git a/Cargo.lock b/Cargo.lock index 805a6900f..2051c2fc1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2402,6 +2402,7 @@ dependencies = [ "time", "tracing", "tree-sitter", + "tree-sitter-c-sharp", "tree-sitter-go", "tree-sitter-java", "tree-sitter-javascript", @@ -3700,6 +3701,16 @@ dependencies = [ "regex", ] +[[package]] +name = "tree-sitter-c-sharp" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8997ad04502208449025114e434c9024a33a74e700513c702a9d2cac6522a771" +dependencies = [ + "cc", + "tree-sitter", +] + [[package]] name = "tree-sitter-go" version = "0.21.2" diff --git a/Cargo.toml b/Cargo.toml index 955b104ce..f7cf984d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -121,6 +121,7 @@ tracing-appender = "0.2.3" tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } tracing-test = "0.2.5" tree-sitter = "0.22.6" +tree-sitter-c-sharp = "0.21.3" tree-sitter-go = "0.21.2" tree-sitter-java = "0.21.0" tree-sitter-javascript = "0.21.4" diff --git a/qlty-analysis/Cargo.toml b/qlty-analysis/Cargo.toml index 3ee80ee95..dd3394145 100644 --- a/qlty-analysis/Cargo.toml +++ b/qlty-analysis/Cargo.toml @@ -37,6 +37,7 @@ tempfile.workspace = true time.workspace = true tracing.workspace = true tree-sitter.workspace = true +tree-sitter-c-sharp.workspace = true tree-sitter-go.workspace = true tree-sitter-java.workspace = true tree-sitter-javascript.workspace = true diff --git a/qlty-analysis/src/lang.rs b/qlty-analysis/src/lang.rs index 6c8286a09..9a323ce10 100644 --- a/qlty-analysis/src/lang.rs +++ b/qlty-analysis/src/lang.rs @@ -3,6 +3,7 @@ use core::fmt; use std::sync::Arc; use tree_sitter::{Node, Parser, Query}; +mod c_sharp; mod go; mod java; mod javascript; @@ -16,7 +17,7 @@ mod typescript; mod typescript_common; pub use { - go::*, java::*, javascript::*, kotlin::*, php::*, python::*, ruby::*, rust::*, tsx::*, + c_sharp::*, go::*, java::*, javascript::*, kotlin::*, php::*, python::*, ruby::*, rust::*, tsx::*, typescript::*, }; @@ -30,6 +31,7 @@ use lazy_static::lazy_static; lazy_static! { pub static ref ALL_LANGS: Vec> = { vec![ + Box::::default(), Box::::default(), Box::::default(), Box::::default(), diff --git a/qlty-analysis/src/lang/c_sharp.rs b/qlty-analysis/src/lang/c_sharp.rs new file mode 100644 index 000000000..0e4392987 --- /dev/null +++ b/qlty-analysis/src/lang/c_sharp.rs @@ -0,0 +1,13 @@ +use crate::code::File; +use crate::code::{child_source, node_source}; +use crate::lang::Language; +use tree_sitter::Node; + +const CLASS_QUERY: &str = r#" +[ + (class_declaration + name: (identifier) @name) + (interface_declaration + name: (identifier) @name) +] @definition.class +"#; From 06d945af73f8505f26179c496706a31005df6856 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:32:28 -0800 Subject: [PATCH 02/53] qlty fmt --- qlty-analysis/src/lang.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qlty-analysis/src/lang.rs b/qlty-analysis/src/lang.rs index 9a323ce10..f884762ea 100644 --- a/qlty-analysis/src/lang.rs +++ b/qlty-analysis/src/lang.rs @@ -17,8 +17,8 @@ mod typescript; mod typescript_common; pub use { - c_sharp::*, go::*, java::*, javascript::*, kotlin::*, php::*, python::*, ruby::*, rust::*, tsx::*, - typescript::*, + c_sharp::*, go::*, java::*, javascript::*, kotlin::*, php::*, python::*, ruby::*, rust::*, + tsx::*, typescript::*, }; #[allow(clippy::borrowed_box)] From ed6f9003f1b27ca56446ebd54aa9ed6543afa440 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:46:55 -0800 Subject: [PATCH 03/53] Add more (copying java's implementation for now) --- qlty-analysis/src/lang/c_sharp.rs | 231 +++++++++++++++++++++++++++++- 1 file changed, 230 insertions(+), 1 deletion(-) diff --git a/qlty-analysis/src/lang/c_sharp.rs b/qlty-analysis/src/lang/c_sharp.rs index 0e4392987..f4135769e 100644 --- a/qlty-analysis/src/lang/c_sharp.rs +++ b/qlty-analysis/src/lang/c_sharp.rs @@ -1,5 +1,5 @@ use crate::code::File; -use crate::code::{child_source, node_source}; +use crate::code::node_source; use crate::lang::Language; use tree_sitter::Node; @@ -11,3 +11,232 @@ const CLASS_QUERY: &str = r#" name: (identifier) @name) ] @definition.class "#; + +const FUNCTION_DECLARATION_QUERY: &str = r#" +[ + (method_declaration + name: (identifier) @name + parameters: (_) @parameters) + (constructor_declaration + name: (identifier) @name + parameters: (_) @parameters) +] @definition.function +"#; + +const FIELD_QUERY: &str = r#" +(field_declaration + declarator: (variable_declarator + name: (identifier) @name)) @field +"#; + +pub struct CSharp { + pub class_query: tree_sitter::Query, + pub function_declaration_query: tree_sitter::Query, + pub field_query: tree_sitter::Query, +} + +impl CSharp { + pub const SELF: &'static str = "this"; + pub const BINARY: &'static str = "binary_expression"; + pub const BLOCK: &'static str = "block"; + pub const BREAK: &'static str = "break_statement"; + pub const CATCH: &'static str = "catch_clause"; + pub const CASE: &'static str = "switch_block_statement_group"; + pub const LINE_COMMENT: &'static str = "line_comment"; + pub const BLOCK_COMMENT: &'static str = "block_comment"; + pub const CONTINUE: &'static str = "continue_statement"; + pub const DO: &'static str = "do_statement"; + pub const FIELD_ACCESS: &'static str = "field_access"; + pub const FIELD_DECLARATION: &'static str = "field_declaration"; + pub const FOR_IN: &'static str = "enhanced_for_statement"; + pub const FOR: &'static str = "for_statement"; + pub const METHOD_DECLARATION: &'static str = "method_declaration"; + pub const METHOD_INVOCATION: &'static str = "method_invocation"; + pub const IDENTIFIER: &'static str = "identifier"; + pub const IF: &'static str = "if_statement"; + pub const LAMBDA: &'static str = "lambda_expression"; + pub const PROGRAM: &'static str = "program"; + pub const RETURN: &'static str = "return_statement"; + pub const STRING: &'static str = "string_literal"; + pub const SWITCH: &'static str = "switch_expression"; + pub const TEMPLATE_STRING: &'static str = "template_expression"; + pub const TERNARY: &'static str = "ternary_expression"; + pub const TRY: &'static str = "try_statement"; + pub const TRY_WITH_RESOURCES: &'static str = "try_with_resources_statement"; + pub const WHILE: &'static str = "while_statement"; + + pub const AND: &'static str = "&&"; + pub const OR: &'static str = "||"; +} + +impl Default for CSharp { + fn default() -> Self { + let language = tree_sitter_c_sharp::language(); + + Self { + class_query: tree_sitter::Query::new(&language, CLASS_QUERY).unwrap(), + field_query: tree_sitter::Query::new(&language, FIELD_QUERY).unwrap(), + function_declaration_query: tree_sitter::Query::new( + &language, + FUNCTION_DECLARATION_QUERY, + ) + .unwrap(), + } + } +} + +impl Language for CSharp { + fn name(&self) -> &str { + "c#" + } + + fn self_keyword(&self) -> Option<&str> { + Some(Self::SELF) + } + + fn class_query(&self) -> &tree_sitter::Query { + &self.class_query + } + + fn function_declaration_query(&self) -> &tree_sitter::Query { + &self.function_declaration_query + } + + fn field_query(&self) -> &tree_sitter::Query { + &self.field_query + } + + fn if_nodes(&self) -> Vec<&str> { + vec![Self::IF] + } + + fn block_nodes(&self) -> Vec<&str> { + vec![Self::BLOCK] + } + + fn conditional_assignment_nodes(&self) -> Vec<&str> { + vec![] + } + + fn invisible_container_nodes(&self) -> Vec<&str> { + vec![Self::PROGRAM] + } + + fn switch_nodes(&self) -> Vec<&str> { + vec![Self::SWITCH] + } + + fn case_nodes(&self) -> Vec<&str> { + vec![Self::CASE] + } + + fn ternary_nodes(&self) -> Vec<&str> { + vec![Self::TERNARY] + } + + fn loop_nodes(&self) -> Vec<&str> { + vec![Self::FOR, Self::FOR_IN, Self::WHILE, Self::DO] + } + + fn except_nodes(&self) -> Vec<&str> { + vec![Self::CATCH] + } + + fn try_expression_nodes(&self) -> Vec<&str> { + vec![Self::TRY, Self::TRY_WITH_RESOURCES] + } + + fn jump_nodes(&self) -> Vec<&str> { + vec![Self::BREAK, Self::CONTINUE] + } + + fn return_nodes(&self) -> Vec<&str> { + vec![Self::RETURN] + } + + fn binary_nodes(&self) -> Vec<&str> { + vec![Self::BINARY] + } + + fn boolean_operator_nodes(&self) -> Vec<&str> { + vec![Self::AND, Self::OR] + } + + fn field_nodes(&self) -> Vec<&str> { + vec![Self::FIELD_DECLARATION] + } + + fn call_nodes(&self) -> Vec<&str> { + vec![Self::METHOD_INVOCATION] + } + + fn function_nodes(&self) -> Vec<&str> { + vec![Self::METHOD_DECLARATION] + } + + fn closure_nodes(&self) -> Vec<&str> { + vec![Self::LAMBDA] + } + + fn comment_nodes(&self) -> Vec<&str> { + vec![Self::LINE_COMMENT, Self::BLOCK_COMMENT] + } + + fn string_nodes(&self) -> Vec<&str> { + vec![Self::STRING, Self::TEMPLATE_STRING] + } + + fn is_jump_label(&self, node: &Node) -> bool { + node.kind() == Self::IDENTIFIER + } + + fn has_labeled_jumps(&self) -> bool { + true + } + + fn call_identifiers(&self, source_file: &File, node: &Node) -> (Option, String) { + match node.kind() { + Self::METHOD_INVOCATION => { + let (receiver, object) = self.field_identifiers(source_file, node); + + (Some(receiver), object) + } + _ => (Some("".to_string()), "".to_string()), + } + } + + fn field_identifiers(&self, source_file: &File, node: &Node) -> (String, String) { + let object_node = node.child_by_field_name("object"); + let property_node = node + .child_by_field_name("name") + .or_else(|| node.child_by_field_name("field")); + + match (&object_node, &property_node) { + (Some(obj), Some(prop)) if obj.kind() == Self::FIELD_ACCESS => { + let object_source = + get_node_source_or_default(obj.child_by_field_name("field"), source_file); + let property_source = get_node_source_or_default(Some(*prop), source_file); + (object_source, property_source) + } + (Some(obj), Some(prop)) => ( + get_node_source_or_default(Some(*obj), source_file), + get_node_source_or_default(Some(*prop), source_file), + ), + (None, Some(prop)) => ( + Self::SELF.to_owned(), + get_node_source_or_default(Some(*prop), source_file), + ), + _ => ("".to_string(), "".to_string()), + } + } + + fn tree_sitter_language(&self) -> tree_sitter::Language { + tree_sitter_c_sharp::language() + } +} + +fn get_node_source_or_default(node: Option, source_file: &File) -> String { + node.as_ref() + .map(|n| node_source(n, source_file)) + .unwrap_or("".to_string()) +} From ba275b85d7fa6461567f4b610befd7575b0530c1 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Thu, 2 Jan 2025 15:46:58 -0800 Subject: [PATCH 04/53] qlty fmt --- qlty-analysis/src/lang/c_sharp.rs | 392 +++++++++++++++--------------- 1 file changed, 196 insertions(+), 196 deletions(-) diff --git a/qlty-analysis/src/lang/c_sharp.rs b/qlty-analysis/src/lang/c_sharp.rs index f4135769e..1c2296c5b 100644 --- a/qlty-analysis/src/lang/c_sharp.rs +++ b/qlty-analysis/src/lang/c_sharp.rs @@ -1,5 +1,5 @@ -use crate::code::File; use crate::code::node_source; +use crate::code::File; use crate::lang::Language; use tree_sitter::Node; @@ -30,213 +30,213 @@ const FIELD_QUERY: &str = r#" "#; pub struct CSharp { - pub class_query: tree_sitter::Query, - pub function_declaration_query: tree_sitter::Query, - pub field_query: tree_sitter::Query, + pub class_query: tree_sitter::Query, + pub function_declaration_query: tree_sitter::Query, + pub field_query: tree_sitter::Query, } impl CSharp { - pub const SELF: &'static str = "this"; - pub const BINARY: &'static str = "binary_expression"; - pub const BLOCK: &'static str = "block"; - pub const BREAK: &'static str = "break_statement"; - pub const CATCH: &'static str = "catch_clause"; - pub const CASE: &'static str = "switch_block_statement_group"; - pub const LINE_COMMENT: &'static str = "line_comment"; - pub const BLOCK_COMMENT: &'static str = "block_comment"; - pub const CONTINUE: &'static str = "continue_statement"; - pub const DO: &'static str = "do_statement"; - pub const FIELD_ACCESS: &'static str = "field_access"; - pub const FIELD_DECLARATION: &'static str = "field_declaration"; - pub const FOR_IN: &'static str = "enhanced_for_statement"; - pub const FOR: &'static str = "for_statement"; - pub const METHOD_DECLARATION: &'static str = "method_declaration"; - pub const METHOD_INVOCATION: &'static str = "method_invocation"; - pub const IDENTIFIER: &'static str = "identifier"; - pub const IF: &'static str = "if_statement"; - pub const LAMBDA: &'static str = "lambda_expression"; - pub const PROGRAM: &'static str = "program"; - pub const RETURN: &'static str = "return_statement"; - pub const STRING: &'static str = "string_literal"; - pub const SWITCH: &'static str = "switch_expression"; - pub const TEMPLATE_STRING: &'static str = "template_expression"; - pub const TERNARY: &'static str = "ternary_expression"; - pub const TRY: &'static str = "try_statement"; - pub const TRY_WITH_RESOURCES: &'static str = "try_with_resources_statement"; - pub const WHILE: &'static str = "while_statement"; - - pub const AND: &'static str = "&&"; - pub const OR: &'static str = "||"; + pub const SELF: &'static str = "this"; + pub const BINARY: &'static str = "binary_expression"; + pub const BLOCK: &'static str = "block"; + pub const BREAK: &'static str = "break_statement"; + pub const CATCH: &'static str = "catch_clause"; + pub const CASE: &'static str = "switch_block_statement_group"; + pub const LINE_COMMENT: &'static str = "line_comment"; + pub const BLOCK_COMMENT: &'static str = "block_comment"; + pub const CONTINUE: &'static str = "continue_statement"; + pub const DO: &'static str = "do_statement"; + pub const FIELD_ACCESS: &'static str = "field_access"; + pub const FIELD_DECLARATION: &'static str = "field_declaration"; + pub const FOR_IN: &'static str = "enhanced_for_statement"; + pub const FOR: &'static str = "for_statement"; + pub const METHOD_DECLARATION: &'static str = "method_declaration"; + pub const METHOD_INVOCATION: &'static str = "method_invocation"; + pub const IDENTIFIER: &'static str = "identifier"; + pub const IF: &'static str = "if_statement"; + pub const LAMBDA: &'static str = "lambda_expression"; + pub const PROGRAM: &'static str = "program"; + pub const RETURN: &'static str = "return_statement"; + pub const STRING: &'static str = "string_literal"; + pub const SWITCH: &'static str = "switch_expression"; + pub const TEMPLATE_STRING: &'static str = "template_expression"; + pub const TERNARY: &'static str = "ternary_expression"; + pub const TRY: &'static str = "try_statement"; + pub const TRY_WITH_RESOURCES: &'static str = "try_with_resources_statement"; + pub const WHILE: &'static str = "while_statement"; + + pub const AND: &'static str = "&&"; + pub const OR: &'static str = "||"; } impl Default for CSharp { - fn default() -> Self { - let language = tree_sitter_c_sharp::language(); - - Self { - class_query: tree_sitter::Query::new(&language, CLASS_QUERY).unwrap(), - field_query: tree_sitter::Query::new(&language, FIELD_QUERY).unwrap(), - function_declaration_query: tree_sitter::Query::new( - &language, - FUNCTION_DECLARATION_QUERY, - ) - .unwrap(), - } - } + fn default() -> Self { + let language = tree_sitter_c_sharp::language(); + + Self { + class_query: tree_sitter::Query::new(&language, CLASS_QUERY).unwrap(), + field_query: tree_sitter::Query::new(&language, FIELD_QUERY).unwrap(), + function_declaration_query: tree_sitter::Query::new( + &language, + FUNCTION_DECLARATION_QUERY, + ) + .unwrap(), + } + } } impl Language for CSharp { - fn name(&self) -> &str { - "c#" - } + fn name(&self) -> &str { + "c#" + } - fn self_keyword(&self) -> Option<&str> { - Some(Self::SELF) - } + fn self_keyword(&self) -> Option<&str> { + Some(Self::SELF) + } - fn class_query(&self) -> &tree_sitter::Query { - &self.class_query - } - - fn function_declaration_query(&self) -> &tree_sitter::Query { - &self.function_declaration_query - } - - fn field_query(&self) -> &tree_sitter::Query { - &self.field_query - } - - fn if_nodes(&self) -> Vec<&str> { - vec![Self::IF] - } - - fn block_nodes(&self) -> Vec<&str> { - vec![Self::BLOCK] - } - - fn conditional_assignment_nodes(&self) -> Vec<&str> { - vec![] - } - - fn invisible_container_nodes(&self) -> Vec<&str> { - vec![Self::PROGRAM] - } - - fn switch_nodes(&self) -> Vec<&str> { - vec![Self::SWITCH] - } - - fn case_nodes(&self) -> Vec<&str> { - vec![Self::CASE] - } - - fn ternary_nodes(&self) -> Vec<&str> { - vec![Self::TERNARY] - } - - fn loop_nodes(&self) -> Vec<&str> { - vec![Self::FOR, Self::FOR_IN, Self::WHILE, Self::DO] - } - - fn except_nodes(&self) -> Vec<&str> { - vec![Self::CATCH] - } - - fn try_expression_nodes(&self) -> Vec<&str> { - vec![Self::TRY, Self::TRY_WITH_RESOURCES] - } - - fn jump_nodes(&self) -> Vec<&str> { - vec![Self::BREAK, Self::CONTINUE] - } - - fn return_nodes(&self) -> Vec<&str> { - vec![Self::RETURN] - } - - fn binary_nodes(&self) -> Vec<&str> { - vec![Self::BINARY] - } - - fn boolean_operator_nodes(&self) -> Vec<&str> { - vec![Self::AND, Self::OR] - } - - fn field_nodes(&self) -> Vec<&str> { - vec![Self::FIELD_DECLARATION] - } - - fn call_nodes(&self) -> Vec<&str> { - vec![Self::METHOD_INVOCATION] - } - - fn function_nodes(&self) -> Vec<&str> { - vec![Self::METHOD_DECLARATION] - } - - fn closure_nodes(&self) -> Vec<&str> { - vec![Self::LAMBDA] - } - - fn comment_nodes(&self) -> Vec<&str> { - vec![Self::LINE_COMMENT, Self::BLOCK_COMMENT] - } - - fn string_nodes(&self) -> Vec<&str> { - vec![Self::STRING, Self::TEMPLATE_STRING] - } - - fn is_jump_label(&self, node: &Node) -> bool { - node.kind() == Self::IDENTIFIER - } - - fn has_labeled_jumps(&self) -> bool { - true - } - - fn call_identifiers(&self, source_file: &File, node: &Node) -> (Option, String) { - match node.kind() { - Self::METHOD_INVOCATION => { - let (receiver, object) = self.field_identifiers(source_file, node); - - (Some(receiver), object) - } - _ => (Some("".to_string()), "".to_string()), - } - } - - fn field_identifiers(&self, source_file: &File, node: &Node) -> (String, String) { - let object_node = node.child_by_field_name("object"); - let property_node = node - .child_by_field_name("name") - .or_else(|| node.child_by_field_name("field")); - - match (&object_node, &property_node) { - (Some(obj), Some(prop)) if obj.kind() == Self::FIELD_ACCESS => { - let object_source = - get_node_source_or_default(obj.child_by_field_name("field"), source_file); - let property_source = get_node_source_or_default(Some(*prop), source_file); - (object_source, property_source) - } - (Some(obj), Some(prop)) => ( - get_node_source_or_default(Some(*obj), source_file), - get_node_source_or_default(Some(*prop), source_file), - ), - (None, Some(prop)) => ( - Self::SELF.to_owned(), - get_node_source_or_default(Some(*prop), source_file), - ), - _ => ("".to_string(), "".to_string()), - } - } - - fn tree_sitter_language(&self) -> tree_sitter::Language { - tree_sitter_c_sharp::language() - } + fn class_query(&self) -> &tree_sitter::Query { + &self.class_query + } + + fn function_declaration_query(&self) -> &tree_sitter::Query { + &self.function_declaration_query + } + + fn field_query(&self) -> &tree_sitter::Query { + &self.field_query + } + + fn if_nodes(&self) -> Vec<&str> { + vec![Self::IF] + } + + fn block_nodes(&self) -> Vec<&str> { + vec![Self::BLOCK] + } + + fn conditional_assignment_nodes(&self) -> Vec<&str> { + vec![] + } + + fn invisible_container_nodes(&self) -> Vec<&str> { + vec![Self::PROGRAM] + } + + fn switch_nodes(&self) -> Vec<&str> { + vec![Self::SWITCH] + } + + fn case_nodes(&self) -> Vec<&str> { + vec![Self::CASE] + } + + fn ternary_nodes(&self) -> Vec<&str> { + vec![Self::TERNARY] + } + + fn loop_nodes(&self) -> Vec<&str> { + vec![Self::FOR, Self::FOR_IN, Self::WHILE, Self::DO] + } + + fn except_nodes(&self) -> Vec<&str> { + vec![Self::CATCH] + } + + fn try_expression_nodes(&self) -> Vec<&str> { + vec![Self::TRY, Self::TRY_WITH_RESOURCES] + } + + fn jump_nodes(&self) -> Vec<&str> { + vec![Self::BREAK, Self::CONTINUE] + } + + fn return_nodes(&self) -> Vec<&str> { + vec![Self::RETURN] + } + + fn binary_nodes(&self) -> Vec<&str> { + vec![Self::BINARY] + } + + fn boolean_operator_nodes(&self) -> Vec<&str> { + vec![Self::AND, Self::OR] + } + + fn field_nodes(&self) -> Vec<&str> { + vec![Self::FIELD_DECLARATION] + } + + fn call_nodes(&self) -> Vec<&str> { + vec![Self::METHOD_INVOCATION] + } + + fn function_nodes(&self) -> Vec<&str> { + vec![Self::METHOD_DECLARATION] + } + + fn closure_nodes(&self) -> Vec<&str> { + vec![Self::LAMBDA] + } + + fn comment_nodes(&self) -> Vec<&str> { + vec![Self::LINE_COMMENT, Self::BLOCK_COMMENT] + } + + fn string_nodes(&self) -> Vec<&str> { + vec![Self::STRING, Self::TEMPLATE_STRING] + } + + fn is_jump_label(&self, node: &Node) -> bool { + node.kind() == Self::IDENTIFIER + } + + fn has_labeled_jumps(&self) -> bool { + true + } + + fn call_identifiers(&self, source_file: &File, node: &Node) -> (Option, String) { + match node.kind() { + Self::METHOD_INVOCATION => { + let (receiver, object) = self.field_identifiers(source_file, node); + + (Some(receiver), object) + } + _ => (Some("".to_string()), "".to_string()), + } + } + + fn field_identifiers(&self, source_file: &File, node: &Node) -> (String, String) { + let object_node = node.child_by_field_name("object"); + let property_node = node + .child_by_field_name("name") + .or_else(|| node.child_by_field_name("field")); + + match (&object_node, &property_node) { + (Some(obj), Some(prop)) if obj.kind() == Self::FIELD_ACCESS => { + let object_source = + get_node_source_or_default(obj.child_by_field_name("field"), source_file); + let property_source = get_node_source_or_default(Some(*prop), source_file); + (object_source, property_source) + } + (Some(obj), Some(prop)) => ( + get_node_source_or_default(Some(*obj), source_file), + get_node_source_or_default(Some(*prop), source_file), + ), + (None, Some(prop)) => ( + Self::SELF.to_owned(), + get_node_source_or_default(Some(*prop), source_file), + ), + _ => ("".to_string(), "".to_string()), + } + } + + fn tree_sitter_language(&self) -> tree_sitter::Language { + tree_sitter_c_sharp::language() + } } fn get_node_source_or_default(node: Option, source_file: &File) -> String { - node.as_ref() - .map(|n| node_source(n, source_file)) - .unwrap_or("".to_string()) + node.as_ref() + .map(|n| node_source(n, source_file)) + .unwrap_or("".to_string()) } From c5486efb6ce79d103761e083fe6cc1987ba817bf Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Thu, 2 Jan 2025 16:19:27 -0800 Subject: [PATCH 05/53] Update field query --- qlty-analysis/src/lang/c_sharp.rs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/qlty-analysis/src/lang/c_sharp.rs b/qlty-analysis/src/lang/c_sharp.rs index 1c2296c5b..c20b09ad2 100644 --- a/qlty-analysis/src/lang/c_sharp.rs +++ b/qlty-analysis/src/lang/c_sharp.rs @@ -20,13 +20,18 @@ const FUNCTION_DECLARATION_QUERY: &str = r#" (constructor_declaration name: (identifier) @name parameters: (_) @parameters) + (local_function_statement + name: (identifier) @name + parameters: (_) @parameters) ] @definition.function "#; const FIELD_QUERY: &str = r#" -(field_declaration - declarator: (variable_declarator - name: (identifier) @name)) @field + (field_declaration + (variable_declaration + (variable_declarator name: (identifier) @name) + ) + ) @field "#; pub struct CSharp { From 942f9237f5958a88aadc5a070b5e9f7111d0af7e Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Thu, 2 Jan 2025 16:39:53 -0800 Subject: [PATCH 06/53] Add c sharp file extension --- qlty-config/default.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/qlty-config/default.toml b/qlty-config/default.toml index f11e96c68..ba680e496 100644 --- a/qlty-config/default.toml +++ b/qlty-config/default.toml @@ -31,6 +31,9 @@ exclude_patterns = [ [file_types.ALL] globs = ["*.*"] +[file_types.c_sharp] +globs = ["*.cs"] + [file_types.css] globs = ["*.css"] From 887c0621dbe83268c058183cb67ce6130334d35c Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Thu, 2 Jan 2025 17:28:44 -0800 Subject: [PATCH 07/53] More C-Sharp updates --- qlty-analysis/src/lang/c_sharp.rs | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) diff --git a/qlty-analysis/src/lang/c_sharp.rs b/qlty-analysis/src/lang/c_sharp.rs index c20b09ad2..c5f12c19b 100644 --- a/qlty-analysis/src/lang/c_sharp.rs +++ b/qlty-analysis/src/lang/c_sharp.rs @@ -41,33 +41,28 @@ pub struct CSharp { } impl CSharp { - pub const SELF: &'static str = "this"; pub const BINARY: &'static str = "binary_expression"; pub const BLOCK: &'static str = "block"; pub const BREAK: &'static str = "break_statement"; pub const CATCH: &'static str = "catch_clause"; - pub const CASE: &'static str = "switch_block_statement_group"; - pub const LINE_COMMENT: &'static str = "line_comment"; - pub const BLOCK_COMMENT: &'static str = "block_comment"; + pub const CASE: &'static str = "switch_section"; + pub const COMMENT: &'static str = "comment"; pub const CONTINUE: &'static str = "continue_statement"; pub const DO: &'static str = "do_statement"; - pub const FIELD_ACCESS: &'static str = "field_access"; pub const FIELD_DECLARATION: &'static str = "field_declaration"; - pub const FOR_IN: &'static str = "enhanced_for_statement"; + pub const FIELD_ACCESS: &'static str = "member_access_expression"; pub const FOR: &'static str = "for_statement"; pub const METHOD_DECLARATION: &'static str = "method_declaration"; - pub const METHOD_INVOCATION: &'static str = "method_invocation"; + pub const METHOD_INVOCATION: &'static str = "invocation_expression"; pub const IDENTIFIER: &'static str = "identifier"; pub const IF: &'static str = "if_statement"; pub const LAMBDA: &'static str = "lambda_expression"; - pub const PROGRAM: &'static str = "program"; pub const RETURN: &'static str = "return_statement"; + pub const SELF: &'static str = "this"; pub const STRING: &'static str = "string_literal"; pub const SWITCH: &'static str = "switch_expression"; - pub const TEMPLATE_STRING: &'static str = "template_expression"; - pub const TERNARY: &'static str = "ternary_expression"; + pub const TERNARY: &'static str = "conditional_expression"; pub const TRY: &'static str = "try_statement"; - pub const TRY_WITH_RESOURCES: &'static str = "try_with_resources_statement"; pub const WHILE: &'static str = "while_statement"; pub const AND: &'static str = "&&"; @@ -124,7 +119,7 @@ impl Language for CSharp { } fn invisible_container_nodes(&self) -> Vec<&str> { - vec![Self::PROGRAM] + vec![] } fn switch_nodes(&self) -> Vec<&str> { @@ -140,7 +135,7 @@ impl Language for CSharp { } fn loop_nodes(&self) -> Vec<&str> { - vec![Self::FOR, Self::FOR_IN, Self::WHILE, Self::DO] + vec![Self::FOR, Self::WHILE, Self::DO] } fn except_nodes(&self) -> Vec<&str> { @@ -148,7 +143,7 @@ impl Language for CSharp { } fn try_expression_nodes(&self) -> Vec<&str> { - vec![Self::TRY, Self::TRY_WITH_RESOURCES] + vec![Self::TRY] } fn jump_nodes(&self) -> Vec<&str> { @@ -184,11 +179,11 @@ impl Language for CSharp { } fn comment_nodes(&self) -> Vec<&str> { - vec![Self::LINE_COMMENT, Self::BLOCK_COMMENT] + vec![Self::COMMENT] } fn string_nodes(&self) -> Vec<&str> { - vec![Self::STRING, Self::TEMPLATE_STRING] + vec![Self::STRING] } fn is_jump_label(&self, node: &Node) -> bool { From 323cd9265b170634ac3fbac1a6b696a67de478a7 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Thu, 2 Jan 2025 23:37:18 -0800 Subject: [PATCH 08/53] Change language name --- qlty-analysis/src/lang/c_sharp.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/qlty-analysis/src/lang/c_sharp.rs b/qlty-analysis/src/lang/c_sharp.rs index c5f12c19b..de12f3a14 100644 --- a/qlty-analysis/src/lang/c_sharp.rs +++ b/qlty-analysis/src/lang/c_sharp.rs @@ -47,6 +47,7 @@ impl CSharp { pub const CATCH: &'static str = "catch_clause"; pub const CASE: &'static str = "switch_section"; pub const COMMENT: &'static str = "comment"; + pub const COMPILATION_UNIT: &'static str = "complication_unit"; pub const CONTINUE: &'static str = "continue_statement"; pub const DO: &'static str = "do_statement"; pub const FIELD_DECLARATION: &'static str = "field_declaration"; @@ -87,7 +88,7 @@ impl Default for CSharp { impl Language for CSharp { fn name(&self) -> &str { - "c#" + "c_sharp" } fn self_keyword(&self) -> Option<&str> { @@ -119,7 +120,7 @@ impl Language for CSharp { } fn invisible_container_nodes(&self) -> Vec<&str> { - vec![] + vec![Self::COMPILATION_UNIT] } fn switch_nodes(&self) -> Vec<&str> { From 500bcfe65e2ab0adcba79b1afbae981598e170df Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Fri, 3 Jan 2025 14:26:33 -0800 Subject: [PATCH 09/53] Renames / integration tests --- qlty-analysis/src/lang.rs | 6 +- .../src/lang/{c_sharp.rs => csharp.rs} | 2 +- qlty-cli/tests/lang.rs | 5 ++ .../tests/lang/csharp/basic.in/.gitignore | 4 ++ .../lang/csharp/basic.in/.qlty/qlty.toml | 1 + .../lang/csharp/basic.in/BooleanLogic.cs | 28 ++++++++ qlty-cli/tests/lang/csharp/basic.stdout | 69 +++++++++++++++++++ qlty-cli/tests/lang/csharp/basic.toml | 3 + qlty-config/default.toml | 5 +- qlty-types/src/lib.rs | 1 + qlty-types/src/protos/qlty.analysis.v1.rs | 3 + .../src/protos/qlty.analysis.v1.serde.rs | 3 + 12 files changed, 125 insertions(+), 5 deletions(-) rename qlty-analysis/src/lang/{c_sharp.rs => csharp.rs} (99%) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/.gitignore create mode 100644 qlty-cli/tests/lang/csharp/basic.in/.qlty/qlty.toml create mode 100644 qlty-cli/tests/lang/csharp/basic.in/BooleanLogic.cs create mode 100644 qlty-cli/tests/lang/csharp/basic.stdout create mode 100644 qlty-cli/tests/lang/csharp/basic.toml diff --git a/qlty-analysis/src/lang.rs b/qlty-analysis/src/lang.rs index f884762ea..1c4278ca9 100644 --- a/qlty-analysis/src/lang.rs +++ b/qlty-analysis/src/lang.rs @@ -3,7 +3,7 @@ use core::fmt; use std::sync::Arc; use tree_sitter::{Node, Parser, Query}; -mod c_sharp; +mod csharp; mod go; mod java; mod javascript; @@ -17,7 +17,7 @@ mod typescript; mod typescript_common; pub use { - c_sharp::*, go::*, java::*, javascript::*, kotlin::*, php::*, python::*, ruby::*, rust::*, + csharp::*, go::*, java::*, javascript::*, kotlin::*, php::*, python::*, ruby::*, rust::*, tsx::*, typescript::*, }; @@ -31,7 +31,7 @@ use lazy_static::lazy_static; lazy_static! { pub static ref ALL_LANGS: Vec> = { vec![ - Box::::default(), + Box::::default(), Box::::default(), Box::::default(), Box::::default(), diff --git a/qlty-analysis/src/lang/c_sharp.rs b/qlty-analysis/src/lang/csharp.rs similarity index 99% rename from qlty-analysis/src/lang/c_sharp.rs rename to qlty-analysis/src/lang/csharp.rs index de12f3a14..a258f0926 100644 --- a/qlty-analysis/src/lang/c_sharp.rs +++ b/qlty-analysis/src/lang/csharp.rs @@ -88,7 +88,7 @@ impl Default for CSharp { impl Language for CSharp { fn name(&self) -> &str { - "c_sharp" + "csharp" } fn self_keyword(&self) -> Option<&str> { diff --git a/qlty-cli/tests/lang.rs b/qlty-cli/tests/lang.rs index 76fdeab21..8b6249777 100644 --- a/qlty-cli/tests/lang.rs +++ b/qlty-cli/tests/lang.rs @@ -49,3 +49,8 @@ fn python_tests() { fn go_tests() { setup_and_run_test_cases("tests/lang/go/**/*.toml"); } + +#[test] +fn c_sharp_tests() { + setup_and_run_test_cases("tests/lang/csharp/**/*.toml"); +} diff --git a/qlty-cli/tests/lang/csharp/basic.in/.gitignore b/qlty-cli/tests/lang/csharp/basic.in/.gitignore new file mode 100644 index 000000000..f5c3477bb --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/.gitignore @@ -0,0 +1,4 @@ +.qlty/results +.qlty/logs +.qlty/out +.qlty/sources \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.in/.qlty/qlty.toml b/qlty-cli/tests/lang/csharp/basic.in/.qlty/qlty.toml new file mode 100644 index 000000000..4db0969f4 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/.qlty/qlty.toml @@ -0,0 +1 @@ +config_version = "0" \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.in/BooleanLogic.cs b/qlty-cli/tests/lang/csharp/basic.in/BooleanLogic.cs new file mode 100644 index 000000000..7c563a846 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/BooleanLogic.cs @@ -0,0 +1,28 @@ +public class BooleanLogic +{ + private int foo; + private int bar; + + private void F0() + { + var x = foo - bar + 1; + } +} + +public class BooleanLogic1 +{ + private bool foo; + private bool bar; + private bool baz; + private bool qux; + private bool zoo; + + private void F1() + { + if (foo && bar && baz && qux && zoo) + { + return; + } + } +} + diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout new file mode 100644 index 000000000..18e89bac6 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -0,0 +1,69 @@ +{ + "metadata": { + "buildId": "[..]", + "result": "ANALYSIS_RESULT_SUCCESS", + "filesAnalyzed": 1, + "startTime": "[..]", + "finishTime": "[..]", + "commitMessage": "initial/n", + "committedAt": "2024-01-01T00:00:00+00:00", + "committerEmail": "test@codeclimate.com", + "committerName": "TEST", + "authorEmail": "test@codeclimate.com", + "authorName": "TEST", + "authoredAt": "2024-01-01T00:00:00+00:00" + }, + "messages": [], + "invocations": [], + "issues": [ + { + "buildId": "[..]", + "analyzedAt": "[..]", + "tool": "qlty", + "driver": "structure", + "ruleKey": "boolean-logic", + "message": "Complex binary expression", + "level": "LEVEL_MEDIUM", + "language": "LANGUAGE_C_SHARP", + "category": "CATEGORY_STRUCTURE", + "snippet": "foo && bar", + "snippetWithContext": "public class BooleanLogic1/n{/n private bool foo;/n private bool bar;/n private bool baz;/n private bool qux;/n private bool zoo;/n/n private void F1()/n {/n if (foo && bar && baz && qux && zoo)/n {/n return;/n }/n }/n}/n", + "effortMinutes": 10, + "value": 4, + "location": { + "path": "BooleanLogic.cs", + "range": { + "startLine": 22, + "startColumn": 13, + "endLine": 22, + "endColumn": 23, + "startByte": 319, + "endByte": 329 + } + }, + "mode": "MODE_BLOCK" + } + ], + "stats": [ + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "BooleanLogic.cs", + "fullyQualifiedName": "BooleanLogic.cs", + "path": "BooleanLogic.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 2, + "functions": 2, + "fields": 5, + "lines": 28, + "codeLines": 22, + "commentLines": 0, + "blankLines": 6, + "complexity": 2, + "cyclomatic": 8, + "lcom4": 0 + } + ] +} diff --git a/qlty-cli/tests/lang/csharp/basic.toml b/qlty-cli/tests/lang/csharp/basic.toml new file mode 100644 index 000000000..f8004557d --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.toml @@ -0,0 +1,3 @@ +bin.name = "qlty" +args = ["build", "--no-plugins", "--print"] +status.code = 0 diff --git a/qlty-config/default.toml b/qlty-config/default.toml index ba680e496..7811a2909 100644 --- a/qlty-config/default.toml +++ b/qlty-config/default.toml @@ -31,7 +31,7 @@ exclude_patterns = [ [file_types.ALL] globs = ["*.*"] -[file_types.c_sharp] +[file_types.csharp] globs = ["*.cs"] [file_types.css] @@ -435,6 +435,9 @@ smells.duplication.filter_patterns = ["(import_statement _)"] [language.tsx] globs = ["*.tsx", "*.mtsx", "*.ctsx"] +[language.csharp] +globs = ["*.cs"] + [smells.boolean_logic] threshold = 4 diff --git a/qlty-types/src/lib.rs b/qlty-types/src/lib.rs index 9c7409300..678e69f76 100644 --- a/qlty-types/src/lib.rs +++ b/qlty-types/src/lib.rs @@ -312,6 +312,7 @@ pub fn language_enum_from_name(name: &str) -> analysis::v1::Language { "rust" => analysis::v1::Language::Rust, "tsx" => analysis::v1::Language::Tsx, "typescript" => analysis::v1::Language::Typescript, + "csharp" => analysis::v1::Language::CSharp, _ => panic!("Unrecognized language name: {}", name), } } diff --git a/qlty-types/src/protos/qlty.analysis.v1.rs b/qlty-types/src/protos/qlty.analysis.v1.rs index ad3aaf8db..6e67b4fbc 100644 --- a/qlty-types/src/protos/qlty.analysis.v1.rs +++ b/qlty-types/src/protos/qlty.analysis.v1.rs @@ -677,6 +677,7 @@ pub enum Language { Rust = 10, Kotlin = 11, Php = 12, + CSharp = 13, } impl Language { /// String value of the enum field names used in the ProtoBuf definition. @@ -698,6 +699,7 @@ impl Language { Self::Rust => "LANGUAGE_RUST", Self::Kotlin => "LANGUAGE_KOTLIN", Self::Php => "LANGUAGE_PHP", + Self::CSharp => "LANGUAGE_C_SHARP", } } /// Creates an enum from field names used in the ProtoBuf definition. @@ -716,6 +718,7 @@ impl Language { "LANGUAGE_RUST" => Some(Self::Rust), "LANGUAGE_KOTLIN" => Some(Self::Kotlin), "LANGUAGE_PHP" => Some(Self::Php), + "LANGUAGE_C_SHARP" => Some(Self::CSharp), _ => None, } } diff --git a/qlty-types/src/protos/qlty.analysis.v1.serde.rs b/qlty-types/src/protos/qlty.analysis.v1.serde.rs index 03977a2a2..f8c1766f7 100644 --- a/qlty-types/src/protos/qlty.analysis.v1.serde.rs +++ b/qlty-types/src/protos/qlty.analysis.v1.serde.rs @@ -1794,6 +1794,7 @@ impl serde::Serialize for Language { Self::Rust => "LANGUAGE_RUST", Self::Kotlin => "LANGUAGE_KOTLIN", Self::Php => "LANGUAGE_PHP", + Self::CSharp => "LANGUAGE_C_SHARP", }; serializer.serialize_str(variant) } @@ -1818,6 +1819,7 @@ impl<'de> serde::Deserialize<'de> for Language { "LANGUAGE_RUST", "LANGUAGE_KOTLIN", "LANGUAGE_PHP", + "LANGUAGE_C_SHARP", ]; struct GeneratedVisitor; @@ -1871,6 +1873,7 @@ impl<'de> serde::Deserialize<'de> for Language { "LANGUAGE_RUST" => Ok(Language::Rust), "LANGUAGE_KOTLIN" => Ok(Language::Kotlin), "LANGUAGE_PHP" => Ok(Language::Php), + "LANGUAGE_C_SHARP" => Ok(Language::CSharp), _ => Err(serde::de::Error::unknown_variant(value, FIELDS)), } } From 6d4cb13681e755e83c3e47e38f90e01e1adc8d53 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Fri, 3 Jan 2025 14:57:06 -0800 Subject: [PATCH 10/53] File and function complexity test --- .../lang/csharp/basic.in/FileComplexity.cs | 41 +++++++ qlty-cli/tests/lang/csharp/basic.stdout | 115 +++++++++++++++++- 2 files changed, 153 insertions(+), 3 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/FileComplexity.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/FileComplexity.cs b/qlty-cli/tests/lang/csharp/basic.in/FileComplexity.cs new file mode 100644 index 000000000..91fb68e8d --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/FileComplexity.cs @@ -0,0 +1,41 @@ +using System; + +public class FileComplexity +{ + public static void Main(string[] args) + { + int foo = 42; + + if (foo > 0) + { + if (foo > 10) + { + if (foo < 20) + { + if (foo % 2 == 0) + { + if (foo % 3 == 0) + { + if (foo % 5 == 0) + { + if (foo % 7 == 0) + { + if (foo % 11 == 0) + { + if (foo % 13 == 0) + { + if (foo % 17 == 0) + { + Console.WriteLine("Nested!"); + } + } + } + } + } + } + } + } + } + } + } +} diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 18e89bac6..ba3d5ebaa 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 1, + "filesAnalyzed": 2, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -42,12 +42,101 @@ } }, "mode": "MODE_BLOCK" + }, + { + "buildId": "b02520fe-4947-4fad-9d84-5728dfba3399", + "analyzedAt": "2025-01-03T22:56:44.556091+00:00", + "tool": "qlty", + "driver": "structure", + "ruleKey": "file-complexity", + "message": "High total complexity (count = 55)", + "level": "LEVEL_MEDIUM", + "language": "LANGUAGE_C_SHARP", + "category": "CATEGORY_STRUCTURE", + "snippet": "using System;/n/npublic class FileComplexity/n{/n public static void Main(string[] args)/n {/n int foo = 42;/n /n if (foo > 0)/n {/n if (foo > 10)/n {/n if (foo < 20)/n {/n if (foo % 2 == 0)/n {/n if (foo % 3 == 0)/n {/n if (foo % 5 == 0)/n {/n if (foo % 7 == 0)/n {/n if (foo % 11 == 0)/n {/n if (foo % 13 == 0)/n {/n if (foo % 17 == 0)/n {/n Console.WriteLine(/"Nested!/");/n }/n }/n }/n }/n }/n }/n }/n }/n }/n }/n }/n}/n", + "snippetWithContext": "using System;/n/npublic class FileComplexity/n{/n public static void Main(string[] args)/n {/n int foo = 42;/n /n if (foo > 0)/n {/n if (foo > 10)/n {/n if (foo < 20)/n {/n if (foo % 2 == 0)/n {/n if (foo % 3 == 0)/n {/n if (foo % 5 == 0)/n {/n if (foo % 7 == 0)/n {/n if (foo % 11 == 0)/n {/n if (foo % 13 == 0)/n {/n if (foo % 17 == 0)/n {/n Console.WriteLine(/"Nested!/");/n }/n }/n }/n }/n }/n }/n }/n }/n }/n }/n }/n}", + "effortMinutes": 150, + "value": 55, + "valueDelta": 5, + "location": { + "path": "FileComplexity.cs", + "range": { + "startLine": 1, + "startColumn": 1, + "endLine": 42, + "endColumn": 1, + "startByte": 0, + "endByte": 1201 + } + }, + "partialFingerprints": { + "file.path": "FileComplexity.cs" + }, + "mode": "MODE_BLOCK" + }, + { + "buildId": "b02520fe-4947-4fad-9d84-5728dfba3399", + "analyzedAt": "2025-01-03T22:56:44.556091+00:00", + "tool": "qlty", + "driver": "structure", + "ruleKey": "function-complexity", + "message": "Function with high complexity (count = 55): Main", + "level": "LEVEL_MEDIUM", + "language": "LANGUAGE_C_SHARP", + "category": "CATEGORY_STRUCTURE", + "snippet": "public static void Main(string[] args)/n {/n int foo = 42;/n /n if (foo > 0)/n {/n if (foo > 10)/n {/n if (foo < 20)/n {/n if (foo % 2 == 0)/n {/n if (foo % 3 == 0)/n {/n if (foo % 5 == 0)/n {/n if (foo % 7 == 0)/n {/n if (foo % 11 == 0)/n {/n if (foo % 13 == 0)/n {/n if (foo % 17 == 0)/n {/n Console.WriteLine(/"Nested!/");/n }/n }/n }/n }/n }/n }/n }/n }/n }/n }/n }", + "snippetWithContext": "using System;/n/npublic class FileComplexity/n{/n public static void Main(string[] args)/n {/n int foo = 42;/n /n if (foo > 0)/n {/n if (foo > 10)/n {/n if (foo < 20)/n {/n if (foo % 2 == 0)/n {/n if (foo % 3 == 0)/n {/n if (foo % 5 == 0)/n {/n if (foo % 7 == 0)/n {/n if (foo % 11 == 0)/n {/n if (foo % 13 == 0)/n {/n if (foo % 17 == 0)/n {/n Console.WriteLine(/"Nested!/");/n }/n }/n }/n }/n }/n }/n }/n }/n }/n }/n }/n}", + "effortMinutes": 195, + "value": 55, + "valueDelta": 37, + "location": { + "path": "FileComplexity.cs", + "range": { + "startLine": 5, + "startColumn": 5, + "endLine": 40, + "endColumn": 6, + "startByte": 49, + "endByte": 1198 + } + }, + "partialFingerprints": { + "function.name": "Main" + }, + "mode": "MODE_BLOCK" + }, + { + "buildId": "b02520fe-4947-4fad-9d84-5728dfba3399", + "analyzedAt": "2025-01-03T22:56:44.556091+00:00", + "tool": "qlty", + "driver": "structure", + "ruleKey": "nested-control-flow", + "message": "Deeply nested control flow (level = 5)", + "level": "LEVEL_MEDIUM", + "language": "LANGUAGE_C_SHARP", + "category": "CATEGORY_STRUCTURE", + "snippet": "if (foo % 3 == 0)/n {/n if (foo % 5 == 0)/n {/n if (foo % 7 == 0)/n {/n if (foo % 11 == 0)/n {/n if (foo % 13 == 0)/n {/n if (foo % 17 == 0)/n {/n Console.WriteLine(/"Nested!/");/n }/n }/n }/n }/n }/n }", + "snippetWithContext": " int foo = 42;/n /n if (foo > 0)/n {/n if (foo > 10)/n {/n if (foo < 20)/n {/n if (foo % 2 == 0)/n {/n if (foo % 3 == 0)/n {/n if (foo % 5 == 0)/n {/n if (foo % 7 == 0)/n {/n if (foo % 11 == 0)/n {/n if (foo % 13 == 0)/n {/n if (foo % 17 == 0)/n {/n Console.WriteLine(/"Nested!/");/n }/n }/n }/n }/n }/n }/n }/n }/n }/n }/n }/n}", + "effortMinutes": 15, + "value": 5, + "location": { + "path": "FileComplexity.cs", + "range": { + "startLine": 17, + "startColumn": 25, + "endLine": 35, + "endColumn": 26, + "startByte": 328, + "endByte": 1128 + } + }, + "mode": "MODE_BLOCK" } ], "stats": [ { - "buildId": "[..]", - "analyzedAt": "[..]", + "buildId": "b02520fe-4947-4fad-9d84-5728dfba3399", + "analyzedAt": "2025-01-03T22:56:44.556091+00:00", "name": "BooleanLogic.cs", "fullyQualifiedName": "BooleanLogic.cs", "path": "BooleanLogic.cs", @@ -64,6 +153,26 @@ "complexity": 2, "cyclomatic": 8, "lcom4": 0 + }, + { + "buildId": "b02520fe-4947-4fad-9d84-5728dfba3399", + "analyzedAt": "2025-01-03T22:56:44.556091+00:00", + "name": "FileComplexity.cs", + "fullyQualifiedName": "FileComplexity.cs", + "path": "FileComplexity.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 41, + "codeLines": 29, + "commentLines": 0, + "blankLines": 12, + "complexity": 55, + "cyclomatic": 28, + "lcom4": 0 } ] } From b23edcc3434737e1acdcf36a1cf8d68d8d0ae9dd Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Fri, 3 Jan 2025 15:05:52 -0800 Subject: [PATCH 11/53] Function complexity --- .../csharp/basic.in/FunctionComplexity.cs | 30 ++++++++ qlty-cli/tests/lang/csharp/basic.stdout | 69 ++++++++++++++++--- 2 files changed, 88 insertions(+), 11 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/FunctionComplexity.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/FunctionComplexity.cs b/qlty-cli/tests/lang/csharp/basic.in/FunctionComplexity.cs new file mode 100644 index 000000000..e6d00b498 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/FunctionComplexity.cs @@ -0,0 +1,30 @@ +using System; + +public class FunctionComplexity +{ + public void Simple() + { + } + + public void Complex() + { + int bar = 42; + + if (bar > 0) + { + if (bar > 10) + { + if (bar < 20) + { + if (bar % 2 == 0) + { + if (bar % 3 == 0) + { + Console.WriteLine("Nested!"); + } + } + } + } + } + } +} diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index ba3d5ebaa..0d9565c5b 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 2, + "filesAnalyzed": 3, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -44,8 +44,8 @@ "mode": "MODE_BLOCK" }, { - "buildId": "b02520fe-4947-4fad-9d84-5728dfba3399", - "analyzedAt": "2025-01-03T22:56:44.556091+00:00", + "buildId": "[..]", + "analyzedAt": "[..]", "tool": "qlty", "driver": "structure", "ruleKey": "file-complexity", @@ -75,8 +75,8 @@ "mode": "MODE_BLOCK" }, { - "buildId": "b02520fe-4947-4fad-9d84-5728dfba3399", - "analyzedAt": "2025-01-03T22:56:44.556091+00:00", + "buildId": "[..]", + "analyzedAt": "[..]", "tool": "qlty", "driver": "structure", "ruleKey": "function-complexity", @@ -106,8 +106,8 @@ "mode": "MODE_BLOCK" }, { - "buildId": "b02520fe-4947-4fad-9d84-5728dfba3399", - "analyzedAt": "2025-01-03T22:56:44.556091+00:00", + "buildId": "[..]", + "analyzedAt": "[..]", "tool": "qlty", "driver": "structure", "ruleKey": "nested-control-flow", @@ -131,12 +131,39 @@ } }, "mode": "MODE_BLOCK" + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "tool": "qlty", + "driver": "structure", + "ruleKey": "nested-control-flow", + "message": "Deeply nested control flow (level = 5)", + "level": "LEVEL_MEDIUM", + "language": "LANGUAGE_C_SHARP", + "category": "CATEGORY_STRUCTURE", + "snippet": "if (bar % 3 == 0)/n {/n Console.WriteLine(/"Nested!/");/n }", + "snippetWithContext": " int bar = 42;/n/n if (bar > 0)/n {/n if (bar > 10)/n {/n if (bar < 20)/n {/n if (bar % 2 == 0)/n {/n if (bar % 3 == 0)/n {/n Console.WriteLine(/"Nested!/");/n }/n }/n }/n }/n }/n }/n}", + "effortMinutes": 15, + "value": 5, + "location": { + "path": "FunctionComplexity.cs", + "range": { + "startLine": 21, + "startColumn": 25, + "endLine": 24, + "endColumn": 26, + "startByte": 345, + "endByte": 472 + } + }, + "mode": "MODE_BLOCK" } ], "stats": [ { - "buildId": "b02520fe-4947-4fad-9d84-5728dfba3399", - "analyzedAt": "2025-01-03T22:56:44.556091+00:00", + "buildId": "[..]", + "analyzedAt": "[..]", "name": "BooleanLogic.cs", "fullyQualifiedName": "BooleanLogic.cs", "path": "BooleanLogic.cs", @@ -155,8 +182,8 @@ "lcom4": 0 }, { - "buildId": "b02520fe-4947-4fad-9d84-5728dfba3399", - "analyzedAt": "2025-01-03T22:56:44.556091+00:00", + "buildId": "[..]", + "analyzedAt": "[..]", "name": "FileComplexity.cs", "fullyQualifiedName": "FileComplexity.cs", "path": "FileComplexity.cs", @@ -173,6 +200,26 @@ "complexity": 55, "cyclomatic": 28, "lcom4": 0 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "FunctionComplexity.cs", + "fullyQualifiedName": "FunctionComplexity.cs", + "path": "FunctionComplexity.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 2, + "fields": 0, + "lines": 30, + "codeLines": 21, + "commentLines": 0, + "blankLines": 9, + "complexity": 15, + "cyclomatic": 13, + "lcom4": 0 } ] } From 0858ecf71714fd722c18a4b4bfabf5f88c4bd4f3 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Fri, 3 Jan 2025 16:07:07 -0800 Subject: [PATCH 12/53] Add duplication test --- .../tests/lang/csharp/basic.in/Identical.cs | 56 ++++++++++ qlty-cli/tests/lang/csharp/basic.stdout | 104 +++++++++++++++++- 2 files changed, 159 insertions(+), 1 deletion(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/Identical.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/Identical.cs b/qlty-cli/tests/lang/csharp/basic.in/Identical.cs new file mode 100644 index 000000000..98f919e83 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/Identical.cs @@ -0,0 +1,56 @@ +using System; + +public class Identical +{ + public static double[] f0(double[] numbers) + { + double sum = 0; + foreach (double num in numbers) + { + sum += num; + } + double mean = sum / numbers.Length; + + double[] sortedNumbers = (double[])numbers.Clone(); + Array.Sort(sortedNumbers); + + double median; + int length = sortedNumbers.Length; + if (length % 2 == 0) + { + median = (sortedNumbers[length / 2 - 1] + sortedNumbers[length / 2]) / 2.0; + } + else + { + median = sortedNumbers[length / 2]; + } + + return new double[] { mean, median }; + } + + public static double[] f1(double[] numbers) + { + double sum = 0; + foreach (double num in numbers) + { + sum += num; + } + double mean = sum / numbers.Length; + + double[] sortedNumbers = (double[])numbers.Clone(); + Array.Sort(sortedNumbers); + + double median; + int length = sortedNumbers.Length; + if (length % 2 == 0) + { + median = (sortedNumbers[length / 2 - 1] + sortedNumbers[length / 2]) / 2.0; + } + else + { + median = sortedNumbers[length / 2]; + } + + return new double[] { mean, median }; + } +} diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 0d9565c5b..5f0efd67f 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 3, + "filesAnalyzed": 4, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -16,6 +16,88 @@ "messages": [], "invocations": [], "issues": [ + { + "buildId": "[..]", + "analyzedAt": "[..]", + "tool": "qlty", + "driver": "duplication", + "ruleKey": "similar-code", + "message": "Found 25 lines of similar code in 2 locations (mass = 125)", + "level": "LEVEL_MEDIUM", + "language": "LANGUAGE_C_SHARP", + "category": "CATEGORY_DUPLICATION", + "snippet": "public static double[] f0(double[] numbers)/n {/n double sum = 0;/n foreach (double num in numbers)/n {/n sum += num;/n }/n double mean = sum / numbers.Length;/n/n double[] sortedNumbers = (double[])numbers.Clone();/n Array.Sort(sortedNumbers);/n/n double median;/n int length = sortedNumbers.Length;/n if (length % 2 == 0)/n {/n median = (sortedNumbers[length / 2 - 1] + sortedNumbers[length / 2]) / 2.0;/n }/n else/n {/n median = sortedNumbers[length / 2];/n }/n/n return new double[] { mean, median };/n }", + "snippetWithContext": "using System;/n/npublic class Identical/n{/n public static double[] f0(double[] numbers)/n {/n double sum = 0;/n foreach (double num in numbers)/n {/n sum += num;/n }/n double mean = sum / numbers.Length;/n/n double[] sortedNumbers = (double[])numbers.Clone();/n Array.Sort(sortedNumbers);/n/n double median;/n int length = sortedNumbers.Length;/n if (length % 2 == 0)/n {/n median = (sortedNumbers[length / 2 - 1] + sortedNumbers[length / 2]) / 2.0;/n }/n else/n {/n median = sortedNumbers[length / 2];/n }/n/n return new double[] { mean, median };/n }/n/n public static double[] f1(double[] numbers)/n {/n double sum = 0;/n foreach (double num in numbers)/n {/n sum += num;/n }/n double mean = sum / numbers.Length;/n/n double[] sortedNumbers = (double[])numbers.Clone();", + "effortMinutes": 60, + "value": 25, + "valueDelta": 10, + "location": { + "path": "Identical.cs", + "range": { + "startLine": 5, + "endLine": 29, + "startByte": 44, + "endByte": 679 + } + }, + "otherLocations": [ + { + "path": "Identical.cs", + [..] + [..] + [..] + [..] + } + ], + "properties": { + [..] + [..] + [..] + [..] + }, + "mode": "MODE_BLOCK" + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "tool": "qlty", + "driver": "duplication", + "ruleKey": "similar-code", + "message": "Found 25 lines of similar code in 2 locations (mass = 125)", + "level": "LEVEL_MEDIUM", + "language": "LANGUAGE_C_SHARP", + "category": "CATEGORY_DUPLICATION", + "snippet": "public static double[] f1(double[] numbers)/n {/n double sum = 0;/n foreach (double num in numbers)/n {/n sum += num;/n }/n double mean = sum / numbers.Length;/n/n double[] sortedNumbers = (double[])numbers.Clone();/n Array.Sort(sortedNumbers);/n/n double median;/n int length = sortedNumbers.Length;/n if (length % 2 == 0)/n {/n median = (sortedNumbers[length / 2 - 1] + sortedNumbers[length / 2]) / 2.0;/n }/n else/n {/n median = sortedNumbers[length / 2];/n }/n/n return new double[] { mean, median };/n }", + "snippetWithContext": " }/n else/n {/n median = sortedNumbers[length / 2];/n }/n/n return new double[] { mean, median };/n }/n/n public static double[] f1(double[] numbers)/n {/n double sum = 0;/n foreach (double num in numbers)/n {/n sum += num;/n }/n double mean = sum / numbers.Length;/n/n double[] sortedNumbers = (double[])numbers.Clone();/n Array.Sort(sortedNumbers);/n/n double median;/n int length = sortedNumbers.Length;/n if (length % 2 == 0)/n {/n median = (sortedNumbers[length / 2 - 1] + sortedNumbers[length / 2]) / 2.0;/n }/n else/n {/n median = sortedNumbers[length / 2];/n }/n/n return new double[] { mean, median };/n }/n}", + "effortMinutes": 60, + "value": 25, + "valueDelta": 10, + "location": { + "path": "Identical.cs", + "range": { + "startLine": 31, + "endLine": 55, + "startByte": 685, + "endByte": 1320 + } + }, + "otherLocations": [ + { + "path": "Identical.cs", + [..] + [..] + [..] + [..] + } + ], + "properties": { + [..] + [..] + [..] + [..] + }, + "mode": "MODE_BLOCK" + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -220,6 +302,26 @@ "complexity": 15, "cyclomatic": 13, "lcom4": 0 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "Identical.cs", + "fullyQualifiedName": "Identical.cs", + "path": "Identical.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 2, + "fields": 0, + "lines": 56, + "codeLines": 37, + "commentLines": 0, + "blankLines": 19, + "complexity": 4, + "cyclomatic": 21, + "lcom4": 0 } ] } From c5038dc70ab53dd66c18fe18a8717cddbdcdc31d Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Fri, 3 Jan 2025 22:12:37 -0800 Subject: [PATCH 13/53] Add Lines.cs --- qlty-cli/tests/lang/csharp/basic.in/Lines.cs | 57 ++++++++++++++++++++ qlty-cli/tests/lang/csharp/basic.stdout | 22 +++++++- 2 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/Lines.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/Lines.cs b/qlty-cli/tests/lang/csharp/basic.in/Lines.cs new file mode 100644 index 000000000..f85669ac9 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/Lines.cs @@ -0,0 +1,57 @@ +using System; +using System.IO; + +public class Main +{ + public static void F1() + { + try + { + string tempFilePath = Path.Combine( + Path.GetTempPath(), + $"ruby{Guid.NewGuid()}.kt" + ); + + using (var writer = new StreamWriter(tempFilePath)) + { + writer.Write("foo(...args)"); + } + + object tree = ParseFile(tempFilePath); + + Bar(); + } + catch (IOException e) + { + Console.Error.WriteLine(e); + } + } + + public static object ParseFile(string filePath) + { + return new object(); + } + + // Foo + public static void F2() + { + Bar(); // does not count as comment line + } + + // multi-line comment + /* + * line1 + * line2 + * line4 + */ + + public static void F3() + { + Bar(); + } + + public static void Bar() + { + Console.WriteLine("bar() called"); + } +} diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 5f0efd67f..29a78f024 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 4, + "filesAnalyzed": 5, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -322,6 +322,26 @@ "complexity": 4, "cyclomatic": 21, "lcom4": 0 + }, + { + "buildId": "1e0563bf-7a4b-4bac-ad95-31e63a74a305", + "analyzedAt": "2025-01-04T06:11:47.862391+00:00", + "name": "Lines.cs", + "fullyQualifiedName": "Lines.cs", + "path": "Lines.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 5, + "fields": 0, + "lines": 57, + "codeLines": 32, + "commentLines": 7, + "blankLines": 18, + "complexity": 1, + "cyclomatic": 3, + "lcom4": 0 } ] } From b7f0d519ffea66bf67c6840cea5a1de24a2ffcfa Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 13:26:12 -0800 Subject: [PATCH 14/53] Ignore buildid and analyzed at --- qlty-cli/tests/lang/csharp/basic.stdout | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 29a78f024..e90fc7155 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -324,8 +324,8 @@ "lcom4": 0 }, { - "buildId": "1e0563bf-7a4b-4bac-ad95-31e63a74a305", - "analyzedAt": "2025-01-04T06:11:47.862391+00:00", + "buildId": "[..]", + "analyzedAt": "[..]", "name": "Lines.cs", "fullyQualifiedName": "Lines.cs", "path": "Lines.cs", From 6acf02c9af5b42ac0e9ea40b26719beaac462d98 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 13:45:55 -0800 Subject: [PATCH 15/53] Nested control aka too many return statements --- .../lang/csharp/basic.in/NestedControl.cs | 62 +++++++++++++++++++ qlty-cli/tests/lang/csharp/basic.stdout | 50 ++++++++++++++- 2 files changed, 111 insertions(+), 1 deletion(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/NestedControl.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/NestedControl.cs b/qlty-cli/tests/lang/csharp/basic.in/NestedControl.cs new file mode 100644 index 000000000..bbef1cc38 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/NestedControl.cs @@ -0,0 +1,62 @@ +using System; + +public class Main +{ + public static void NotNested(string foo, string bar) + { + if ((foo == "cat" && bar == "dog") || (foo == "dog" && bar == "cat")) + { + Console.WriteLine("Got a cat and a dog!"); + } + else + { + Console.WriteLine("Got nothing"); + } + } + + public static void F0(bool bar, bool baz, bool qux, bool quux) + { + if (bar) + { + if (baz) + { + if (qux) + { + if (quux) + { + Console.WriteLine("Not deeply nested enough!"); + } + } + } + } + } + + public static string F2(int foo) + { + switch (foo) + { + case 1: + return "bar1"; + case 2: + return "bar2"; + case 3: + return "bar3"; + case 4: + return "bar4"; + case 5: + return "bar5"; + case 6: + return "bar6"; + case 7: + return "bar7"; + case 8: + return "bar8"; + case 9: + return "bar9"; + case 10: + return "bar10"; + default: + throw new ArgumentException("Invalid foo value"); + } + } +} diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index e90fc7155..8e865ef35 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 5, + "filesAnalyzed": 6, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -240,6 +240,34 @@ } }, "mode": "MODE_BLOCK" + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "tool": "qlty", + "driver": "structure", + "ruleKey": "return-statements", + "message": "Function with many returns (count = 10): F2", + "level": "LEVEL_MEDIUM", + "language": "LANGUAGE_C_SHARP", + "category": "CATEGORY_STRUCTURE", + "snippet": "public static string F2(int foo)/n {/n switch (foo)/n {/n case 1:/n return /"bar1/";/n case 2:/n return /"bar2/";/n case 3:/n return /"bar3/";/n case 4:/n return /"bar4/";/n case 5:/n return /"bar5/";/n case 6:/n return /"bar6/";/n case 7:/n return /"bar7/";/n case 8:/n return /"bar8/";/n case 9:/n return /"bar9/";/n case 10:/n return /"bar10/";/n default:/n throw new ArgumentException(/"Invalid foo value/");/n }/n }", + "snippetWithContext": " {/n if (quux)/n {/n Console.WriteLine(/"Not deeply nested enough!/");/n }/n }/n }/n }/n }/n/n public static string F2(int foo)/n {/n switch (foo)/n {/n case 1:/n return /"bar1/";/n case 2:/n return /"bar2/";/n case 3:/n return /"bar3/";/n case 4:/n return /"bar4/";/n case 5:/n return /"bar5/";/n case 6:/n return /"bar6/";/n case 7:/n return /"bar7/";/n case 8:/n return /"bar8/";/n case 9:/n return /"bar9/";/n case 10:/n return /"bar10/";/n default:/n throw new ArgumentException(/"Invalid foo value/");/n }/n }/n}", + "effortMinutes": 35, + "value": 10, + "valueDelta": 4, + "location": { + "path": "NestedControl.cs", + "range": { + "startLine": 34, + "startColumn": 5, + "endLine": 61, + "endColumn": 6, + "startByte": 714, + "endByte": 1398 + } + }, + "mode": "MODE_BLOCK" } ], "stats": [ @@ -342,6 +370,26 @@ "complexity": 1, "cyclomatic": 3, "lcom4": 0 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "NestedControl.cs", + "fullyQualifiedName": "NestedControl.cs", + "path": "NestedControl.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 3, + "fields": 0, + "lines": 62, + "codeLines": 48, + "commentLines": 0, + "blankLines": 14, + "complexity": 15, + "cyclomatic": 24, + "lcom4": 0 } ] } From ffbc80cf00bff9a7dab1b80a1dc5b0c6cc77aee7 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 13:54:18 -0800 Subject: [PATCH 16/53] Too many parameters integration test --- .../tests/lang/csharp/basic.in/Parameters.cs | 26 ++++++++++ qlty-cli/tests/lang/csharp/basic.stdout | 49 ++++++++++++++++++- 2 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/Parameters.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/Parameters.cs b/qlty-cli/tests/lang/csharp/basic.in/Parameters.cs new file mode 100644 index 000000000..49b7dc0e9 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/Parameters.cs @@ -0,0 +1,26 @@ +using System; + +public class Parameters +{ + public static void F0() + { + } + + public static void F1(object dog, object cat) + { + } + + public static void F2(object a, object b, object c, object d, object e, object f) + { + } + + public static void F3() + { + object foo = Bar(1, 2, 3, 4); + } + + public static object Bar(int a, int b, int c, int d) + { + return new object(); + } +} diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 8e865ef35..e6b12f392 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 6, + "filesAnalyzed": 7, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -187,6 +187,33 @@ }, "mode": "MODE_BLOCK" }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "tool": "qlty", + "driver": "structure", + "ruleKey": "function-parameters", + "message": "Function with many parameters (count = 6): F2", + "level": "LEVEL_MEDIUM", + "language": "LANGUAGE_C_SHARP", + "category": "CATEGORY_STRUCTURE", + "snippet": "(object a, object b, object c, object d, object e, object f)", + "snippetWithContext": "public class Parameters/n{/n public static void F0()/n {/n }/n/n public static void F1(object dog, object cat)/n {/n }/n/n public static void F2(object a, object b, object c, object d, object e, object f)/n {/n }/n/n public static void F3()/n {/n object foo = Bar(1, 2, 3, 4);/n }/n/n public static object Bar(int a, int b, int c, int d)/n {", + "effortMinutes": 15, + "value": 6, + "location": { + "path": "Parameters.cs", + "range": { + "startLine": 13, + "startColumn": 26, + "endLine": 13, + "endColumn": 86, + "startByte": 170, + "endByte": 230 + } + }, + "mode": "MODE_BLOCK" + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -390,6 +417,26 @@ "complexity": 15, "cyclomatic": 24, "lcom4": 0 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "Parameters.cs", + "fullyQualifiedName": "Parameters.cs", + "path": "Parameters.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 5, + "fields": 0, + "lines": 26, + "codeLines": 17, + "commentLines": 0, + "blankLines": 9, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 } ] } From a9630c360cd5c3673b513e9cc6caca1f7a082667 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 13:56:48 -0800 Subject: [PATCH 17/53] Returns file for C# --- .../tests/lang/csharp/basic.in/Returns.cs | 61 +++++++++++++++++++ qlty-cli/tests/lang/csharp/basic.stdout | 22 ++++++- 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/Returns.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/Returns.cs b/qlty-cli/tests/lang/csharp/basic.in/Returns.cs new file mode 100644 index 000000000..d47a26ab2 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/Returns.cs @@ -0,0 +1,61 @@ +using System; + +public class Returns +{ + public void F0() + { + } + + public void F1() + { + return; + } + + public void F2() + { + if (true) + { + return; + } + else + { + return; + } + } + + public void F3() + { + if (true) + { + return; + } + else if (true) + { + return; + } + else + { + return; + } + } + + public void F4() + { + if (true) + { + return; + } + else if (true) + { + return; + } + else if (true) + { + return; + } + else + { + return; + } + } +} diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index e6b12f392..02f00c37c 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 7, + "filesAnalyzed": 8, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -437,6 +437,26 @@ "complexity": 0, "cyclomatic": 1, "lcom4": 0 + }, + { + "buildId": "96e26162-d478-43be-8b24-4e17ad685ee2", + "analyzedAt": "2025-01-06T21:56:34.969635+00:00", + "name": "Returns.cs", + "fullyQualifiedName": "Returns.cs", + "path": "Returns.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 5, + "fields": 0, + "lines": 61, + "codeLines": 34, + "commentLines": 0, + "blankLines": 27, + "complexity": 9, + "cyclomatic": 7, + "lcom4": 0 } ] } From 1b4a79474a0a94f43decf7a0d61cbb75ee3fe4a6 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 13:57:24 -0800 Subject: [PATCH 18/53] -- --- qlty-cli/tests/lang/csharp/basic.stdout | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 02f00c37c..8eae9d907 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -439,8 +439,8 @@ "lcom4": 0 }, { - "buildId": "96e26162-d478-43be-8b24-4e17ad685ee2", - "analyzedAt": "2025-01-06T21:56:34.969635+00:00", + "buildId": "[..]", + "analyzedAt": "[..]", "name": "Returns.cs", "fullyQualifiedName": "Returns.cs", "path": "Returns.cs", From ad652ed88747f363c7623b2a3a6f2128f3e44dc4 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 14:57:52 -0800 Subject: [PATCH 19/53] Conditional assignment --- .../cognitive/CountConditionalAssignment.cs | 16 ++++++++ qlty-cli/tests/lang/csharp/basic.stdout | 41 ++++++++++++++++++- 2 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/cognitive/CountConditionalAssignment.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/cognitive/CountConditionalAssignment.cs b/qlty-cli/tests/lang/csharp/basic.in/cognitive/CountConditionalAssignment.cs new file mode 100644 index 000000000..9fab85923 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/cognitive/CountConditionalAssignment.cs @@ -0,0 +1,16 @@ +using System; + +namespace Cognitive +{ + class CountConditionalAssignment + { + public static void Main(string[] args) + { + int bar = 0; + bar = bar != 0 ? bar : 10; + + int foo = 0; + foo = foo != 0 && foo != 10 ? foo : 10; + } + } +} diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 8eae9d907..b69724c79 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 8, + "filesAnalyzed": 9, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -457,6 +457,45 @@ "complexity": 9, "cyclomatic": 7, "lcom4": 0 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "CountConditionalAssignment.cs", + "fullyQualifiedName": "cognitive/CountConditionalAssignment.cs", + "path": "cognitive/CountConditionalAssignment.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 16, + "codeLines": 14, + "commentLines": 0, + "blankLines": 2, + "complexity": 3, + "cyclomatic": 7, + "lcom4": 0 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "cognitive", + "fullyQualifiedName": "cognitive", + "path": "cognitive", + "kind": "COMPONENT_TYPE_DIRECTORY", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 16, + "codeLines": 14, + "commentLines": 0, + "blankLines": 2, + "complexity": 3, + "cyclomatic": 7, + "lcom4": 0 } ] } From b95cd5923d94ddd2d32f52c650801c10b067b7b6 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 15:01:00 -0800 Subject: [PATCH 20/53] Count function with ternary --- .../cognitive/CountFunctionWithTernary.cs | 8 +++++ qlty-cli/tests/lang/csharp/basic.stdout | 36 ++++++++++++++----- 2 files changed, 36 insertions(+), 8 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/cognitive/CountFunctionWithTernary.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/cognitive/CountFunctionWithTernary.cs b/qlty-cli/tests/lang/csharp/basic.in/cognitive/CountFunctionWithTernary.cs new file mode 100644 index 000000000..fefb933d7 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/cognitive/CountFunctionWithTernary.cs @@ -0,0 +1,8 @@ +namespace cognitive +{ + class CountFunctionWithTernary { + public static int Main(int num) { + return num > 0 ? num : num * -1; + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index b69724c79..fa7f4d20e 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 9, + "filesAnalyzed": 10, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -481,20 +481,40 @@ { "buildId": "[..]", "analyzedAt": "[..]", + "name": "CountFunctionWithTernary.cs", + "fullyQualifiedName": "cognitive/CountFunctionWithTernary.cs", + "path": "cognitive/CountFunctionWithTernary.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 8, + "codeLines": 8, + "commentLines": 0, + "blankLines": 0, + "complexity": 1, + "cyclomatic": 4, + "lcom4": 0 + }, + { + "buildId": "5558c31d-837f-4304-b7b5-c311dc30d5b1", + "analyzedAt": "2025-01-06T23:00:37.510021+00:00", "name": "cognitive", "fullyQualifiedName": "cognitive", "path": "cognitive", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 1, - "classes": 1, - "functions": 1, + "files": 2, + "classes": 2, + "functions": 2, "fields": 0, - "lines": 16, - "codeLines": 14, + "lines": 24, + "codeLines": 22, "commentLines": 0, "blankLines": 2, - "complexity": 3, - "cyclomatic": 7, + "complexity": 4, + "cyclomatic": 11, "lcom4": 0 } ] From 2551060239e14551f44e0327d8716d5a5429c8b5 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 15:01:28 -0800 Subject: [PATCH 21/53] Count function with ternary --- qlty-cli/tests/lang/csharp/basic.stdout | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index fa7f4d20e..6c9f0a520 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -499,8 +499,8 @@ "lcom4": 0 }, { - "buildId": "5558c31d-837f-4304-b7b5-c311dc30d5b1", - "analyzedAt": "2025-01-06T23:00:37.510021+00:00", + "buildId": "[..]", + "analyzedAt": "[..]", "name": "cognitive", "fullyQualifiedName": "cognitive", "path": "cognitive", From 1c29a36abe4ff8aa7f0c6dd41e696942bb91cb4f Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 15:15:14 -0800 Subject: [PATCH 22/53] Count non sequential logical operators test --- .../CountNonSequentialLogicalOperators.cs | 8 +++ qlty-cli/tests/lang/csharp/basic.stdout | 63 ++++++++++++++++--- 2 files changed, 63 insertions(+), 8 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/cognitive/CountNonSequentialLogicalOperators.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/cognitive/CountNonSequentialLogicalOperators.cs b/qlty-cli/tests/lang/csharp/basic.in/cognitive/CountNonSequentialLogicalOperators.cs new file mode 100644 index 000000000..0dcced0b2 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/cognitive/CountNonSequentialLogicalOperators.cs @@ -0,0 +1,8 @@ +namespace cognitive +{ + class CountNonSequentialLogicalOperators { + public static boolean Main(String[] args) { + return true || false && true && false || true; + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 6c9f0a520..1c583d5be 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 10, + "filesAnalyzed": 11, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -125,6 +125,33 @@ }, "mode": "MODE_BLOCK" }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "tool": "qlty", + "driver": "structure", + "ruleKey": "boolean-logic", + "message": "Complex binary expression", + "level": "LEVEL_MEDIUM", + "language": "LANGUAGE_C_SHARP", + "category": "CATEGORY_STRUCTURE", + "snippet": "false && true", + "snippetWithContext": "namespace cognitive/n{/n class CountNonSequentialLogicalOperators {/n public static boolean Main(String[] args) {/n return true || false && true && false || true;/n }/n }/n}", + "effortMinutes": 10, + "value": 4, + "location": { + "path": "cognitive/CountNonSequentialLogicalOperators.cs", + "range": { + "startLine": 5, + "startColumn": 22, + "endLine": 5, + "endColumn": 35, + "startByte": 136, + "endByte": 149 + } + }, + "mode": "MODE_BLOCK" + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -498,6 +525,26 @@ "cyclomatic": 4, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "CountNonSequentialLogicalOperators.cs", + "fullyQualifiedName": "cognitive/CountNonSequentialLogicalOperators.cs", + "path": "cognitive/CountNonSequentialLogicalOperators.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 8, + "codeLines": 8, + "commentLines": 0, + "blankLines": 0, + "complexity": 3, + "cyclomatic": 5, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -505,16 +552,16 @@ "fullyQualifiedName": "cognitive", "path": "cognitive", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 2, - "classes": 2, - "functions": 2, + "files": 3, + "classes": 3, + "functions": 3, "fields": 0, - "lines": 24, - "codeLines": 22, + "lines": 32, + "codeLines": 30, "commentLines": 0, "blankLines": 2, - "complexity": 4, - "cyclomatic": 11, + "complexity": 7, + "cyclomatic": 16, "lcom4": 0 } ] From 24d71ffa6342f8e9fcb3c0e345c0f0d17c450c32 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 20:48:08 -0800 Subject: [PATCH 23/53] Multiple conditionals --- .../CountNonSequentialLogicalOperators.cs | 2 +- .../cognitive/MultipleConditionals.cs | 20 ++++++ qlty-cli/tests/lang/csharp/basic.stdout | 67 ++++++++++++++++--- .../lang/csharp/pending/CountRecursion.cs | 8 +++ 4 files changed, 86 insertions(+), 11 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/cognitive/MultipleConditionals.cs create mode 100644 qlty-cli/tests/lang/csharp/pending/CountRecursion.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/cognitive/CountNonSequentialLogicalOperators.cs b/qlty-cli/tests/lang/csharp/basic.in/cognitive/CountNonSequentialLogicalOperators.cs index 0dcced0b2..598bbb30e 100644 --- a/qlty-cli/tests/lang/csharp/basic.in/cognitive/CountNonSequentialLogicalOperators.cs +++ b/qlty-cli/tests/lang/csharp/basic.in/cognitive/CountNonSequentialLogicalOperators.cs @@ -1,7 +1,7 @@ namespace cognitive { class CountNonSequentialLogicalOperators { - public static boolean Main(String[] args) { + public static boolean Main(string[] args) { return true || false && true && false || true; } } diff --git a/qlty-cli/tests/lang/csharp/basic.in/cognitive/MultipleConditionals.cs b/qlty-cli/tests/lang/csharp/basic.in/cognitive/MultipleConditionals.cs new file mode 100644 index 000000000..f6e0e9fc8 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/cognitive/MultipleConditionals.cs @@ -0,0 +1,20 @@ +namespace cognitive +{ + class MultipleConditionals { + public static string Main(int foo) { + if (foo >= 80 && foo <= 100) { + return "Most complex!"; + } else if (foo >= 60 && foo <= 79) { + return "Very complex"; + } else if (foo >= 40 && foo <= 59) { + return "Somewhat complex"; + } else if (foo >= 20 && foo <= 39) { + return "Not complex"; + } else if (foo >= 0 && foo <= 19) { + return "Least complex!"; + } else { + return null; + } + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 1c583d5be..85ec25c73 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 11, + "filesAnalyzed": 12, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -136,7 +136,7 @@ "language": "LANGUAGE_C_SHARP", "category": "CATEGORY_STRUCTURE", "snippet": "false && true", - "snippetWithContext": "namespace cognitive/n{/n class CountNonSequentialLogicalOperators {/n public static boolean Main(String[] args) {/n return true || false && true && false || true;/n }/n }/n}", + "snippetWithContext": "namespace cognitive/n{/n class CountNonSequentialLogicalOperators {/n public static boolean Main(string[] args) {/n return true || false && true && false || true;/n }/n }/n}", "effortMinutes": 10, "value": 4, "location": { @@ -322,6 +322,33 @@ } }, "mode": "MODE_BLOCK" + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "tool": "qlty", + "driver": "structure", + "ruleKey": "return-statements", + "message": "Function with many returns (count = 6): Main", + "level": "LEVEL_MEDIUM", + "language": "LANGUAGE_C_SHARP", + "category": "CATEGORY_STRUCTURE", + "snippet": "public static string Main(int foo) {/n if (foo >= 80 && foo <= 100) {/n return /"Most complex!/";/n } else if (foo >= 60 && foo <= 79) {/n return /"Very complex/";/n } else if (foo >= 40 && foo <= 59) {/n return /"Somewhat complex/";/n } else if (foo >= 20 && foo <= 39) {/n return /"Not complex/";/n } else if (foo >= 0 && foo <= 19) {/n return /"Least complex!/";/n } else {/n return null;/n }/n }", + "snippetWithContext": "namespace cognitive/n{/n class MultipleConditionals {/n public static string Main(int foo) {/n if (foo >= 80 && foo <= 100) {/n return /"Most complex!/";/n } else if (foo >= 60 && foo <= 79) {/n return /"Very complex/";/n } else if (foo >= 40 && foo <= 59) {/n return /"Somewhat complex/";/n } else if (foo >= 20 && foo <= 39) {/n return /"Not complex/";/n } else if (foo >= 0 && foo <= 19) {/n return /"Least complex!/";/n } else {/n return null;/n }/n }/n }/n}", + "effortMinutes": 15, + "value": 6, + "location": { + "path": "cognitive/MultipleConditionals.cs", + "range": { + "startLine": 4, + "startColumn": 5, + "endLine": 18, + "endColumn": 6, + "startByte": 57, + "endByte": 512 + } + }, + "mode": "MODE_BLOCK" } ], "stats": [ @@ -545,6 +572,26 @@ "cyclomatic": 5, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "MultipleConditionals.cs", + "fullyQualifiedName": "cognitive/MultipleConditionals.cs", + "path": "cognitive/MultipleConditionals.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 20, + "codeLines": 19, + "commentLines": 0, + "blankLines": 1, + "complexity": 7, + "cyclomatic": 21, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -552,16 +599,16 @@ "fullyQualifiedName": "cognitive", "path": "cognitive", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 3, - "classes": 3, - "functions": 3, + "files": 4, + "classes": 4, + "functions": 4, "fields": 0, - "lines": 32, - "codeLines": 30, + "lines": 52, + "codeLines": 49, "commentLines": 0, - "blankLines": 2, - "complexity": 7, - "cyclomatic": 16, + "blankLines": 3, + "complexity": 14, + "cyclomatic": 37, "lcom4": 0 } ] diff --git a/qlty-cli/tests/lang/csharp/pending/CountRecursion.cs b/qlty-cli/tests/lang/csharp/pending/CountRecursion.cs new file mode 100644 index 000000000..aecd1e25c --- /dev/null +++ b/qlty-cli/tests/lang/csharp/pending/CountRecursion.cs @@ -0,0 +1,8 @@ +namespace cognitive +{ + class CountRecursion { + public static void Main() { + Main(); + } + } +} \ No newline at end of file From 7a6b0c8ec3a3bd03da6a209c6a7b76768852f7e3 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:23:28 -0800 Subject: [PATCH 24/53] Add Cyclo basic --- .../csharp/basic.in/cyclomatic/CycloBasic.cs | 7 ++++ qlty-cli/tests/lang/csharp/basic.stdout | 41 ++++++++++++++++++- 2 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloBasic.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloBasic.cs b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloBasic.cs new file mode 100644 index 000000000..d54d0a340 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloBasic.cs @@ -0,0 +1,7 @@ +namespace Cyclomatic { + class CycloBasic { + public static void Main(string args[]) { + int x = 1; + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 85ec25c73..50949f667 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 12, + "filesAnalyzed": 13, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -592,6 +592,26 @@ "cyclomatic": 21, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "CycloBasic.cs", + "fullyQualifiedName": "cyclomatic/CycloBasic.cs", + "path": "cyclomatic/CycloBasic.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 7, + "codeLines": 7, + "commentLines": 0, + "blankLines": 0, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -610,6 +630,25 @@ "complexity": 14, "cyclomatic": 37, "lcom4": 0 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "cyclomatic", + "fullyQualifiedName": "cyclomatic", + "path": "cyclomatic", + "kind": "COMPONENT_TYPE_DIRECTORY", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 7, + "codeLines": 7, + "commentLines": 0, + "blankLines": 0, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 } ] } From 88da24e550375b808d4cadac877757de4b41af79 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:31:23 -0800 Subject: [PATCH 25/53] CylcoIf --- .../csharp/basic.in/cyclomatic/CycloIf.cs | 11 ++++++ qlty-cli/tests/lang/csharp/basic.stdout | 36 ++++++++++++++----- 2 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloIf.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloIf.cs b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloIf.cs new file mode 100644 index 000000000..3583dea7f --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloIf.cs @@ -0,0 +1,11 @@ +namespace Cyclomatic +{ + class CycloIf { + public static string Main(string args[]) { + int x = 1; + if (x > 0) { + int y = 1; + } + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 50949f667..6e2f6c34f 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 13, + "filesAnalyzed": 14, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -612,6 +612,26 @@ "cyclomatic": 1, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "CycloIf.cs", + "fullyQualifiedName": "cyclomatic/CycloIf.cs", + "path": "cyclomatic/CycloIf.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 11, + "codeLines": 11, + "commentLines": 0, + "blankLines": 0, + "complexity": 1, + "cyclomatic": 3, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -638,16 +658,16 @@ "fullyQualifiedName": "cyclomatic", "path": "cyclomatic", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 1, - "classes": 1, - "functions": 1, + "files": 2, + "classes": 2, + "functions": 2, "fields": 0, - "lines": 7, - "codeLines": 7, + "lines": 18, + "codeLines": 18, "commentLines": 0, "blankLines": 0, - "complexity": 0, - "cyclomatic": 1, + "complexity": 1, + "cyclomatic": 4, "lcom4": 0 } ] From dc88e6887997426754fda86f98bd6db416e0b5b1 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:46:57 -0800 Subject: [PATCH 26/53] cycloifelse --- .../csharp/basic.in/cyclomatic/CycloIfElse.cs | 13 +++++++ qlty-cli/tests/lang/csharp/basic.stdout | 38 ++++++++++++++----- 2 files changed, 42 insertions(+), 9 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloIfElse.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloIfElse.cs b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloIfElse.cs new file mode 100644 index 000000000..5bf619083 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloIfElse.cs @@ -0,0 +1,13 @@ +namespace Cyclomatic +{ + class CycloIfElse { + public static void Main(string[] args) { + int x = 1; + if (x > 0) { + int y = 1; + } else { + int y = 2; + } + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 6e2f6c34f..023bc5640 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 14, + "filesAnalyzed": 15, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -632,6 +632,26 @@ "cyclomatic": 3, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "CycloIfElse.cs", + "fullyQualifiedName": "cyclomatic/CycloIfElse.cs", + "path": "cyclomatic/CycloIfElse.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 13, + "codeLines": 12, + "commentLines": 0, + "blankLines": 1, + "complexity": 2, + "cyclomatic": 3, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -658,16 +678,16 @@ "fullyQualifiedName": "cyclomatic", "path": "cyclomatic", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 2, - "classes": 2, - "functions": 2, + "files": 3, + "classes": 3, + "functions": 3, "fields": 0, - "lines": 18, - "codeLines": 18, + "lines": 31, + "codeLines": 30, "commentLines": 0, - "blankLines": 0, - "complexity": 1, - "cyclomatic": 4, + "blankLines": 1, + "complexity": 3, + "cyclomatic": 7, "lcom4": 0 } ] From 386bf32c54ec8d936e23d40ec7fd94cde9b7a313 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 21:59:49 -0800 Subject: [PATCH 27/53] IfElseIf --- .../basic.in/cyclomatic/CycloIfElseIf.cs | 13 +++++++ qlty-cli/tests/lang/csharp/basic.stdout | 36 ++++++++++++++----- 2 files changed, 41 insertions(+), 8 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloIfElseIf.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloIfElseIf.cs b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloIfElseIf.cs new file mode 100644 index 000000000..19210ea95 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloIfElseIf.cs @@ -0,0 +1,13 @@ +namespace Cyclomatic +{ + class CycloIfElseIf { + public static void Main(string[] args) { + int x = 1; + if (x > 0) { + int y = 1; + } else if (x < 0) { + int y = 2; + } + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 023bc5640..32a112c1a 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 15, + "filesAnalyzed": 16, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -652,6 +652,26 @@ "cyclomatic": 3, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "CycloIfElseIf.cs", + "fullyQualifiedName": "cyclomatic/CycloIfElseIf.cs", + "path": "cyclomatic/CycloIfElseIf.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 13, + "codeLines": 13, + "commentLines": 0, + "blankLines": 0, + "complexity": 2, + "cyclomatic": 5, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -678,16 +698,16 @@ "fullyQualifiedName": "cyclomatic", "path": "cyclomatic", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 3, - "classes": 3, - "functions": 3, + "files": 4, + "classes": 4, + "functions": 4, "fields": 0, - "lines": 31, - "codeLines": 30, + "lines": 44, + "codeLines": 43, "commentLines": 0, "blankLines": 1, - "complexity": 3, - "cyclomatic": 7, + "complexity": 5, + "cyclomatic": 12, "lcom4": 0 } ] From 12179db2717d05c43688c1b1352e0dc57cd5580c Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 22:01:54 -0800 Subject: [PATCH 28/53] IfElseIfElse --- .../basic.in/cyclomatic/CycloIfElseIfElse.cs | 15 ++++++++ qlty-cli/tests/lang/csharp/basic.stdout | 38 ++++++++++++++----- 2 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloIfElseIfElse.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloIfElseIfElse.cs b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloIfElseIfElse.cs new file mode 100644 index 000000000..d4423889d --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/CycloIfElseIfElse.cs @@ -0,0 +1,15 @@ +namespace Cyclomatic +{ + class CycloIfElseIfElse { + public static void Main(string[] args) { + int x = 1; + if (x > 0) { + int y = 1; + } else if (x < 0) { + int y = 2; + } else { + int y = 3; + } + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 32a112c1a..60fdf5969 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 16, + "filesAnalyzed": 17, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -672,6 +672,26 @@ "cyclomatic": 5, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "CycloIfElseIfElse.cs", + "fullyQualifiedName": "cyclomatic/CycloIfElseIfElse.cs", + "path": "cyclomatic/CycloIfElseIfElse.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 15, + "codeLines": 14, + "commentLines": 0, + "blankLines": 1, + "complexity": 3, + "cyclomatic": 5, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -698,16 +718,16 @@ "fullyQualifiedName": "cyclomatic", "path": "cyclomatic", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 4, - "classes": 4, - "functions": 4, + "files": 5, + "classes": 5, + "functions": 5, "fields": 0, - "lines": 44, - "codeLines": 43, + "lines": 59, + "codeLines": 57, "commentLines": 0, - "blankLines": 1, - "complexity": 5, - "cyclomatic": 12, + "blankLines": 2, + "complexity": 8, + "cyclomatic": 17, "lcom4": 0 } ] From b857c4518b9793e5af07c15216ddd3a2b55be64b Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 22:03:50 -0800 Subject: [PATCH 29/53] Empty function --- .../basic.in/cyclomatic/EmptyFunction.cs | 6 +++ qlty-cli/tests/lang/csharp/basic.stdout | 40 ++++++++++++++----- 2 files changed, 36 insertions(+), 10 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/cyclomatic/EmptyFunction.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/EmptyFunction.cs b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/EmptyFunction.cs new file mode 100644 index 000000000..b8742b52b --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/EmptyFunction.cs @@ -0,0 +1,6 @@ +namespace Cyclomatic +{ + class EmptyFunction { + public static string Main(string args[]) { + } + } \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 60fdf5969..30ef54d16 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 17, + "filesAnalyzed": 18, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -692,6 +692,26 @@ "cyclomatic": 5, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "EmptyFunction.cs", + "fullyQualifiedName": "cyclomatic/EmptyFunction.cs", + "path": "cyclomatic/EmptyFunction.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 6, + "codeLines": 5, + "commentLines": 0, + "blankLines": 1, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -712,22 +732,22 @@ "lcom4": 0 }, { - "buildId": "[..]", - "analyzedAt": "[..]", + "buildId": "15dc4eb3-4676-4ad5-a517-c42f24bf719b", + "analyzedAt": "2025-01-07T06:03:17.463615+00:00", "name": "cyclomatic", "fullyQualifiedName": "cyclomatic", "path": "cyclomatic", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 5, - "classes": 5, - "functions": 5, + "files": 6, + "classes": 6, + "functions": 6, "fields": 0, - "lines": 59, - "codeLines": 57, + "lines": 65, + "codeLines": 62, "commentLines": 0, - "blankLines": 2, + "blankLines": 3, "complexity": 8, - "cyclomatic": 17, + "cyclomatic": 18, "lcom4": 0 } ] From 536c508df3c55eb93cfa359b23b9214108a8d184 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 22:06:27 -0800 Subject: [PATCH 30/53] Empty If --- .../csharp/basic.in/cyclomatic/EmptyIf.cs | 9 +++++ qlty-cli/tests/lang/csharp/basic.stdout | 40 ++++++++++++++----- 2 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/cyclomatic/EmptyIf.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/EmptyIf.cs b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/EmptyIf.cs new file mode 100644 index 000000000..38fb54c23 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/EmptyIf.cs @@ -0,0 +1,9 @@ +namespace Cyclomatic +{ + class EmptyIf { + public static string Main(bool arg) { + if (arg) { + } + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 30ef54d16..027fb0256 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 18, + "filesAnalyzed": 19, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -712,6 +712,26 @@ "cyclomatic": 1, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "EmptyIf.cs", + "fullyQualifiedName": "cyclomatic/EmptyIf.cs", + "path": "cyclomatic/EmptyIf.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 9, + "codeLines": 9, + "commentLines": 0, + "blankLines": 0, + "complexity": 1, + "cyclomatic": 2, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -732,22 +752,22 @@ "lcom4": 0 }, { - "buildId": "15dc4eb3-4676-4ad5-a517-c42f24bf719b", - "analyzedAt": "2025-01-07T06:03:17.463615+00:00", + "buildId": "[..]", + "analyzedAt": "[..]", "name": "cyclomatic", "fullyQualifiedName": "cyclomatic", "path": "cyclomatic", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 6, - "classes": 6, - "functions": 6, + "files": 7, + "classes": 7, + "functions": 7, "fields": 0, - "lines": 65, - "codeLines": 62, + "lines": 74, + "codeLines": 71, "commentLines": 0, "blankLines": 3, - "complexity": 8, - "cyclomatic": 18, + "complexity": 9, + "cyclomatic": 20, "lcom4": 0 } ] From 9e437c16f60db48e902bd1749bdb4fa2dd386c8c Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 22:08:44 -0800 Subject: [PATCH 31/53] IfWithBool --- .../csharp/basic.in/cyclomatic/IfWithBool.cs | 9 +++++ qlty-cli/tests/lang/csharp/basic.stdout | 36 ++++++++++++++----- 2 files changed, 37 insertions(+), 8 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/cyclomatic/IfWithBool.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/IfWithBool.cs b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/IfWithBool.cs new file mode 100644 index 000000000..04f434d8d --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/IfWithBool.cs @@ -0,0 +1,9 @@ +namespace Cyclomatic +{ + class IfWithBool { + public static string Main(bool[] arg) { + if (args[0] && args[1]) { + } + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 027fb0256..861d7216d 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 19, + "filesAnalyzed": 20, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -732,6 +732,26 @@ "cyclomatic": 2, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "IfWithBool.cs", + "fullyQualifiedName": "cyclomatic/IfWithBool.cs", + "path": "cyclomatic/IfWithBool.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 9, + "codeLines": 9, + "commentLines": 0, + "blankLines": 0, + "complexity": 2, + "cyclomatic": 3, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -758,16 +778,16 @@ "fullyQualifiedName": "cyclomatic", "path": "cyclomatic", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 7, - "classes": 7, - "functions": 7, + "files": 8, + "classes": 8, + "functions": 8, "fields": 0, - "lines": 74, - "codeLines": 71, + "lines": 83, + "codeLines": 80, "commentLines": 0, "blankLines": 3, - "complexity": 9, - "cyclomatic": 20, + "complexity": 11, + "cyclomatic": 23, "lcom4": 0 } ] From 5dd91df82cd51a462e0008f0600106b3956b9ced Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 22:15:53 -0800 Subject: [PATCH 32/53] IterativeForOf / Iterative Map --- qlty-analysis/src/lang/csharp.rs | 3 +- .../basic.in/cyclomatic/IterativeForOf.cs | 12 ++++ .../basic.in/cyclomatic/IterativeMap.cs | 17 +++++ qlty-cli/tests/lang/csharp/basic.stdout | 62 +++++++++++++++---- 4 files changed, 82 insertions(+), 12 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/cyclomatic/IterativeForOf.cs create mode 100644 qlty-cli/tests/lang/csharp/basic.in/cyclomatic/IterativeMap.cs diff --git a/qlty-analysis/src/lang/csharp.rs b/qlty-analysis/src/lang/csharp.rs index a258f0926..ee52d4339 100644 --- a/qlty-analysis/src/lang/csharp.rs +++ b/qlty-analysis/src/lang/csharp.rs @@ -53,6 +53,7 @@ impl CSharp { pub const FIELD_DECLARATION: &'static str = "field_declaration"; pub const FIELD_ACCESS: &'static str = "member_access_expression"; pub const FOR: &'static str = "for_statement"; + pub const FOREACH: &'static str = "foreach_statement"; pub const METHOD_DECLARATION: &'static str = "method_declaration"; pub const METHOD_INVOCATION: &'static str = "invocation_expression"; pub const IDENTIFIER: &'static str = "identifier"; @@ -136,7 +137,7 @@ impl Language for CSharp { } fn loop_nodes(&self) -> Vec<&str> { - vec![Self::FOR, Self::WHILE, Self::DO] + vec![Self::FOR, Self::FOREACH, Self::WHILE, Self::DO] } fn except_nodes(&self) -> Vec<&str> { diff --git a/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/IterativeForOf.cs b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/IterativeForOf.cs new file mode 100644 index 000000000..c3d4bbe46 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/IterativeForOf.cs @@ -0,0 +1,12 @@ +using System; + +namespace Cyclomatic +{ + class IterativeForOf { + public static void Main(string[] args) { + foreach (var animal in new string[] { "dog", "cat", "bear" }) { + Console.WriteLine(animal); + } + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/IterativeMap.cs b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/IterativeMap.cs new file mode 100644 index 000000000..34c525cb2 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/IterativeMap.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Cyclomatic +{ + class IterativeMap { + public static void Main(string[] args) { + List animals = new List { "dog", "cat", "bear" }; + + animals.Select(animal => { + Console.WriteLine(animal); + return animal; + }).ToList(); + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 861d7216d..27acb4eda 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 20, + "filesAnalyzed": 22, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -428,8 +428,8 @@ "codeLines": 37, "commentLines": 0, "blankLines": 19, - "complexity": 4, - "cyclomatic": 21, + "complexity": 6, + "cyclomatic": 23, "lcom4": 0 }, { @@ -752,6 +752,46 @@ "cyclomatic": 3, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "IterativeForOf.cs", + "fullyQualifiedName": "cyclomatic/IterativeForOf.cs", + "path": "cyclomatic/IterativeForOf.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 12, + "codeLines": 11, + "commentLines": 0, + "blankLines": 1, + "complexity": 1, + "cyclomatic": 2, + "lcom4": 0 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "IterativeMap.cs", + "fullyQualifiedName": "cyclomatic/IterativeMap.cs", + "path": "cyclomatic/IterativeMap.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 17, + "codeLines": 15, + "commentLines": 0, + "blankLines": 2, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -778,16 +818,16 @@ "fullyQualifiedName": "cyclomatic", "path": "cyclomatic", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 8, - "classes": 8, - "functions": 8, + "files": 10, + "classes": 10, + "functions": 10, "fields": 0, - "lines": 83, - "codeLines": 80, + "lines": 112, + "codeLines": 106, "commentLines": 0, - "blankLines": 3, - "complexity": 11, - "cyclomatic": 23, + "blankLines": 6, + "complexity": 12, + "cyclomatic": 26, "lcom4": 0 } ] From 59b15aca7358bc1dd2821095936dbda081b11009 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 22:23:57 -0800 Subject: [PATCH 33/53] IterativeMethods --- .../IterativeMethodsWithFilterAndInclude.cs | 20 ++++++++++ qlty-cli/tests/lang/csharp/basic.stdout | 38 ++++++++++++++----- 2 files changed, 49 insertions(+), 9 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/cyclomatic/IterativeMethodsWithFilterAndInclude.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/IterativeMethodsWithFilterAndInclude.cs b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/IterativeMethodsWithFilterAndInclude.cs new file mode 100644 index 000000000..2a6a1e6c5 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/IterativeMethodsWithFilterAndInclude.cs @@ -0,0 +1,20 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Cyclomatic +{ + class IterativeMethodsWithFilterAndInclude { + public static void Main(string[] args) { + List animals = new List { "dog", "cat", "bear", "tiger" }; + + animals.Where(animal => animal.Length > 3) + .ToList() + .ForEach(animal => Console.WriteLine(animal)); + + if (animals.Contains("cat")) { + Console.WriteLine("Found a cat!"); + } + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 27acb4eda..9e9362e47 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 22, + "filesAnalyzed": 23, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -792,6 +792,26 @@ "cyclomatic": 1, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "IterativeMethodsWithFilterAndInclude.cs", + "fullyQualifiedName": "cyclomatic/IterativeMethodsWithFilterAndInclude.cs", + "path": "cyclomatic/IterativeMethodsWithFilterAndInclude.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 20, + "codeLines": 17, + "commentLines": 0, + "blankLines": 3, + "complexity": 1, + "cyclomatic": 3, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -818,16 +838,16 @@ "fullyQualifiedName": "cyclomatic", "path": "cyclomatic", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 10, - "classes": 10, - "functions": 10, + "files": 11, + "classes": 11, + "functions": 11, "fields": 0, - "lines": 112, - "codeLines": 106, + "lines": 132, + "codeLines": 123, "commentLines": 0, - "blankLines": 6, - "complexity": 12, - "cyclomatic": 26, + "blankLines": 9, + "complexity": 13, + "cyclomatic": 29, "lcom4": 0 } ] From 1efc874bbf03aa39e8eb90b94f214315b77947b1 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Mon, 6 Jan 2025 22:26:09 -0800 Subject: [PATCH 34/53] While loop --- .../csharp/basic.in/cyclomatic/WhileLoop.cs | 15 +++++++ qlty-cli/tests/lang/csharp/basic.stdout | 40 ++++++++++++++----- 2 files changed, 45 insertions(+), 10 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/cyclomatic/WhileLoop.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/WhileLoop.cs b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/WhileLoop.cs new file mode 100644 index 000000000..0ba6808e1 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/cyclomatic/WhileLoop.cs @@ -0,0 +1,15 @@ +using System; + +namespace CyclomaticComplexity { + public class WhileLoop { + public static void Main(string[] args) { + Foo(); + } + + public static void Foo() { + while (true) { + // Infinite loop + } + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 9e9362e47..50638d015 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 23, + "filesAnalyzed": 24, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -812,6 +812,26 @@ "cyclomatic": 3, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "WhileLoop.cs", + "fullyQualifiedName": "cyclomatic/WhileLoop.cs", + "path": "cyclomatic/WhileLoop.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 2, + "fields": 0, + "lines": 15, + "codeLines": 12, + "commentLines": 1, + "blankLines": 2, + "complexity": 1, + "cyclomatic": 2, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -838,16 +858,16 @@ "fullyQualifiedName": "cyclomatic", "path": "cyclomatic", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 11, - "classes": 11, - "functions": 11, + "files": 12, + "classes": 12, + "functions": 13, "fields": 0, - "lines": 132, - "codeLines": 123, - "commentLines": 0, - "blankLines": 9, - "complexity": 13, - "cyclomatic": 29, + "lines": 147, + "codeLines": 135, + "commentLines": 1, + "blankLines": 11, + "complexity": 14, + "cyclomatic": 31, "lcom4": 0 } ] From 4847ab9f874ee3a1f8032fc3bb1ce8315b809110 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:13:46 -0800 Subject: [PATCH 35/53] Unit tests for call_identifiers --- qlty-analysis/src/lang/csharp.rs | 92 +++++++++++++++++++++++++------- 1 file changed, 72 insertions(+), 20 deletions(-) diff --git a/qlty-analysis/src/lang/csharp.rs b/qlty-analysis/src/lang/csharp.rs index ee52d4339..3c77a3e1b 100644 --- a/qlty-analysis/src/lang/csharp.rs +++ b/qlty-analysis/src/lang/csharp.rs @@ -199,34 +199,32 @@ impl Language for CSharp { fn call_identifiers(&self, source_file: &File, node: &Node) -> (Option, String) { match node.kind() { Self::METHOD_INVOCATION => { - let (receiver, object) = self.field_identifiers(source_file, node); - - (Some(receiver), object) + let function_node = node.child_by_field_name("function"); + match function_node { + Some(f) => { + if f.kind() == Self::FIELD_ACCESS { + let (obj, property) = self.field_identifiers(source_file, &f); + (Some(obj), property) + } else { + (Some(Self::SELF.to_owned()), get_node_source_or_default(Some(f), source_file)) + } + }, + None => (Some("".to_string()), "".to_string()) + } } - _ => (Some("".to_string()), "".to_string()), + _ => (Some("".to_string()), "".to_string()) } } fn field_identifiers(&self, source_file: &File, node: &Node) -> (String, String) { - let object_node = node.child_by_field_name("object"); + let object_node = node.child_by_field_name("expression"); let property_node = node - .child_by_field_name("name") - .or_else(|| node.child_by_field_name("field")); + .child_by_field_name("name"); match (&object_node, &property_node) { - (Some(obj), Some(prop)) if obj.kind() == Self::FIELD_ACCESS => { - let object_source = - get_node_source_or_default(obj.child_by_field_name("field"), source_file); - let property_source = get_node_source_or_default(Some(*prop), source_file); - (object_source, property_source) - } - (Some(obj), Some(prop)) => ( - get_node_source_or_default(Some(*obj), source_file), - get_node_source_or_default(Some(*prop), source_file), - ), - (None, Some(prop)) => ( - Self::SELF.to_owned(), - get_node_source_or_default(Some(*prop), source_file), + (Some(o), Some(p)) => ( + get_node_source_or_default(Some(*o), source_file), + get_node_source_or_default(Some(*p), source_file), ), _ => ("".to_string(), "".to_string()), } @@ -242,3 +240,57 @@ fn get_node_source_or_default(node: Option, source_file: &File) -> String .map(|n| node_source(n, source_file)) .unwrap_or("".to_string()) } + + +#[cfg(test)] +mod test { + use super::*; + use tree_sitter::Tree; + + #[test] + fn call_identifier() { + let source_file = File::from_string("csharp", "foo()"); + let tree = source_file.parse(); + let call = root_node(&tree); + let language = CSharp::default(); + + assert_eq!( + language.call_identifiers(&source_file, &call), + (Some("this".to_string()), "foo".to_string()) + ); + } + + #[test] + fn call_member() { + let source_file = File::from_string("csharp", "foo.bar()"); + let tree = source_file.parse(); + let call = root_node(&tree); + let language = CSharp::default(); + + assert_eq!( + language.call_identifiers(&source_file, &call), + (Some("foo".into()), "bar".into()) + ); + } + + #[test] + fn call_with_custom_context() { + let source_file = File::from_string("csharp", "foo.bar(context)"); + let tree = source_file.parse(); + let root = root_node(&tree); + let call = root.child(0).unwrap(); + let language = CSharp::default(); + + assert_eq!( + language.call_identifiers(&source_file, &call), + (Some("foo".into()), "bar".into()) + ); + } + + // navigates down from "(compilation_unit (global statement ...))" + fn root_node(tree: &Tree) -> Node { + let root_node = tree.root_node(); + let expression = root_node.named_child(0).unwrap(); + expression.named_child(0).unwrap() + } +} \ No newline at end of file From 7fd3f1bb1fb39aa7731538539639944a9bbe91db Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:29:25 -0800 Subject: [PATCH 36/53] All call_identifier unit tests --- qlty-analysis/src/lang/csharp.rs | 20 ++++++++++++++++++++ qlty-analysis/src/lang/java.rs | 1 + 2 files changed, 21 insertions(+) diff --git a/qlty-analysis/src/lang/csharp.rs b/qlty-analysis/src/lang/csharp.rs index 3c77a3e1b..bacf46a87 100644 --- a/qlty-analysis/src/lang/csharp.rs +++ b/qlty-analysis/src/lang/csharp.rs @@ -222,6 +222,12 @@ impl Language for CSharp { .child_by_field_name("name"); match (&object_node, &property_node) { + (Some(obj), Some(prop)) if obj.kind() == Self::FIELD_ACCESS => { + let object_source = + get_node_source_or_default(obj.child_by_field_name("name"), source_file); + let property_source = get_node_source_or_default(Some(*prop), source_file); + (object_source, property_source) + } (Some(o), Some(p)) => ( get_node_source_or_default(Some(*o), source_file), get_node_source_or_default(Some(*p), source_file), @@ -287,6 +293,20 @@ mod test { ); } + #[test] + fn method_call_on_nested_object() { + let source_file = File::from_string("csharp", "obj.nestedObj.foo()"); + let tree = source_file.parse(); + let root = root_node(&tree); + let call = root.child(0).unwrap(); + let language = CSharp::default(); + + assert_eq!( + language.call_identifiers(&source_file, &call), + (Some("nestedObj".into()), "foo".into()) + ); + } + // navigates down from "(compilation_unit (global statement ...))" fn root_node(tree: &Tree) -> Node { let root_node = tree.root_node(); diff --git a/qlty-analysis/src/lang/java.rs b/qlty-analysis/src/lang/java.rs index 8ff9aa1db..ec4860850 100644 --- a/qlty-analysis/src/lang/java.rs +++ b/qlty-analysis/src/lang/java.rs @@ -366,6 +366,7 @@ mod test { let source_file = File::from_string("java", "obj.nestedObj.foo();"); let tree = source_file.parse(); let call = call_node(&tree); + eprintln!("{:?}", call.to_sexp()); let language = Java::default(); assert_eq!( From a7168b3414dc7fb36880d91df27195ee9485a880 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Tue, 7 Jan 2025 15:29:31 -0800 Subject: [PATCH 37/53] qlty fmt --- qlty-analysis/src/lang/csharp.rs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/qlty-analysis/src/lang/csharp.rs b/qlty-analysis/src/lang/csharp.rs index bacf46a87..3f867ac2e 100644 --- a/qlty-analysis/src/lang/csharp.rs +++ b/qlty-analysis/src/lang/csharp.rs @@ -206,20 +206,22 @@ impl Language for CSharp { let (obj, property) = self.field_identifiers(source_file, &f); (Some(obj), property) } else { - (Some(Self::SELF.to_owned()), get_node_source_or_default(Some(f), source_file)) + ( + Some(Self::SELF.to_owned()), + get_node_source_or_default(Some(f), source_file), + ) } - }, - None => (Some("".to_string()), "".to_string()) + } + None => (Some("".to_string()), "".to_string()), } } - _ => (Some("".to_string()), "".to_string()) + _ => (Some("".to_string()), "".to_string()), } } fn field_identifiers(&self, source_file: &File, node: &Node) -> (String, String) { let object_node = node.child_by_field_name("expression"); - let property_node = node - .child_by_field_name("name"); + let property_node = node.child_by_field_name("name"); match (&object_node, &property_node) { (Some(obj), Some(prop)) if obj.kind() == Self::FIELD_ACCESS => { @@ -247,7 +249,6 @@ fn get_node_source_or_default(node: Option, source_file: &File) -> String .unwrap_or("".to_string()) } - #[cfg(test)] mod test { use super::*; @@ -313,4 +314,4 @@ mod test { let expression = root_node.named_child(0).unwrap(); expression.named_child(0).unwrap() } -} \ No newline at end of file +} From a4d7b4ed609ebce0aae11fae6587e28b1a00b63d Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Tue, 7 Jan 2025 16:00:34 -0800 Subject: [PATCH 38/53] Field identifier tests --- qlty-analysis/src/lang/csharp.rs | 54 ++++++++++++++++++++++++++++++++ qlty-analysis/src/lang/java.rs | 1 - 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/qlty-analysis/src/lang/csharp.rs b/qlty-analysis/src/lang/csharp.rs index 3f867ac2e..75a82e249 100644 --- a/qlty-analysis/src/lang/csharp.rs +++ b/qlty-analysis/src/lang/csharp.rs @@ -254,6 +254,47 @@ mod test { use super::*; use tree_sitter::Tree; + #[test] + fn field_identifier_read() { + let source_file = File::from_string("csharp", "this.foo"); + let tree = source_file.parse(); + let root_node = root_node(&tree); + let language = CSharp::default(); + + assert_eq!( + language.field_identifiers(&source_file, &root_node), + ("this".to_string(), "foo".to_string()) + ); + } + + #[test] + fn field_identifier_write() { + let source_file = File::from_string("csharp", "this.foo = 1"); + let tree = source_file.parse(); + let root_node = root_node(&tree); + let assignment = root_node.named_child(0).unwrap(); + let field = assignment.named_child(0).unwrap(); + let language = CSharp::default(); + + assert_eq!( + language.field_identifiers(&source_file, &field), + ("this".to_string(), "foo".to_string()) + ); + } + + #[test] + fn field_identifier_collaborator() { + let source_file = File::from_string("csharp", "other.foo"); + let tree = source_file.parse(); + let root_node = root_node(&tree); + let language = CSharp::default(); + + assert_eq!( + language.field_identifiers(&source_file, &root_node), + ("other".to_string(), "foo".to_string()) + ); + } + #[test] fn call_identifier() { let source_file = File::from_string("csharp", "foo()"); @@ -308,6 +349,19 @@ mod test { ); } + #[test] + fn nested_field_access() { + let source_file = File::from_string("csharp", "obj.nestedObj.oneMoreObj"); + let tree = source_file.parse(); + let root = root_node(&tree); + let language = CSharp::default(); + + assert_eq!( + language.field_identifiers(&source_file, &root), + ("nestedObj".to_string(), "oneMoreObj".to_string()) + ); + } + // navigates down from "(compilation_unit (global statement ...))" fn root_node(tree: &Tree) -> Node { let root_node = tree.root_node(); diff --git a/qlty-analysis/src/lang/java.rs b/qlty-analysis/src/lang/java.rs index ec4860850..8ff9aa1db 100644 --- a/qlty-analysis/src/lang/java.rs +++ b/qlty-analysis/src/lang/java.rs @@ -366,7 +366,6 @@ mod test { let source_file = File::from_string("java", "obj.nestedObj.foo();"); let tree = source_file.parse(); let call = call_node(&tree); - eprintln!("{:?}", call.to_sexp()); let language = Java::default(); assert_eq!( From bf2d5757266b6c6fd44dcbdd56d98e0b7f9d6635 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Tue, 7 Jan 2025 16:15:15 -0800 Subject: [PATCH 39/53] Recursion --- .../cognitive}/CountRecursion.cs | 0 qlty-cli/tests/lang/csharp/basic.stdout | 44 ++++++++++++++----- 2 files changed, 32 insertions(+), 12 deletions(-) rename qlty-cli/tests/lang/csharp/{pending => basic.in/cognitive}/CountRecursion.cs (100%) diff --git a/qlty-cli/tests/lang/csharp/pending/CountRecursion.cs b/qlty-cli/tests/lang/csharp/basic.in/cognitive/CountRecursion.cs similarity index 100% rename from qlty-cli/tests/lang/csharp/pending/CountRecursion.cs rename to qlty-cli/tests/lang/csharp/basic.in/cognitive/CountRecursion.cs diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 50638d015..74ef346b3 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 24, + "filesAnalyzed": 25, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -450,7 +450,7 @@ "blankLines": 18, "complexity": 1, "cyclomatic": 3, - "lcom4": 0 + "lcom4": 1 }, { "buildId": "[..]", @@ -490,7 +490,7 @@ "blankLines": 9, "complexity": 0, "cyclomatic": 1, - "lcom4": 0 + "lcom4": 1 }, { "buildId": "[..]", @@ -572,6 +572,26 @@ "cyclomatic": 5, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "CountRecursion.cs", + "fullyQualifiedName": "cognitive/CountRecursion.cs", + "path": "cognitive/CountRecursion.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 8, + "codeLines": 8, + "commentLines": 0, + "blankLines": 0, + "complexity": 1, + "cyclomatic": 1, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -830,7 +850,7 @@ "blankLines": 2, "complexity": 1, "cyclomatic": 2, - "lcom4": 0 + "lcom4": 1 }, { "buildId": "[..]", @@ -839,16 +859,16 @@ "fullyQualifiedName": "cognitive", "path": "cognitive", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 4, - "classes": 4, - "functions": 4, + "files": 5, + "classes": 5, + "functions": 5, "fields": 0, - "lines": 52, - "codeLines": 49, + "lines": 60, + "codeLines": 57, "commentLines": 0, "blankLines": 3, - "complexity": 14, - "cyclomatic": 37, + "complexity": 15, + "cyclomatic": 38, "lcom4": 0 }, { @@ -868,7 +888,7 @@ "blankLines": 11, "complexity": 14, "cyclomatic": 31, - "lcom4": 0 + "lcom4": 1 } ] } From d10ecb9f3c55dac5c8f40076e90f63decc0bd372 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:11:11 -0800 Subject: [PATCH 40/53] Fields in a class declaration --- .../basic.in/fields/ClassDeclaration.cs | 31 ++++++++++++++ qlty-cli/tests/lang/csharp/basic.stdout | 41 ++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/fields/ClassDeclaration.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/fields/ClassDeclaration.cs b/qlty-cli/tests/lang/csharp/basic.in/fields/ClassDeclaration.cs new file mode 100644 index 000000000..e2662a3ac --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/fields/ClassDeclaration.cs @@ -0,0 +1,31 @@ +namespace Fields +{ + class Foo + { + public string bar; + public string baz; + + // Constructor + public Foo() + { + this.bar = ""; + this.baz = ""; + } + } + + public class ClassDeclaration + { + public static void Main(string[] args) + { + System.Console.WriteLine(DoSomething()); + } + + public static string DoSomething() + { + Foo foo = new Foo(); + foo.bar = "Hello"; + foo.baz = "World"; + return foo.bar + foo.baz; + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 74ef346b3..3880070e8 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 25, + "filesAnalyzed": 26, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -852,6 +852,26 @@ "cyclomatic": 2, "lcom4": 1 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "ClassDeclaration.cs", + "fullyQualifiedName": "fields/ClassDeclaration.cs", + "path": "fields/ClassDeclaration.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 2, + "functions": 3, + "fields": 2, + "lines": 31, + "codeLines": 24, + "commentLines": 1, + "blankLines": 6, + "complexity": 0, + "cyclomatic": 2, + "lcom4": 1 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -889,6 +909,25 @@ "complexity": 14, "cyclomatic": 31, "lcom4": 1 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "fields", + "fullyQualifiedName": "fields", + "path": "fields", + "kind": "COMPONENT_TYPE_DIRECTORY", + "files": 1, + "classes": 2, + "functions": 3, + "fields": 2, + "lines": 31, + "codeLines": 24, + "commentLines": 1, + "blankLines": 6, + "complexity": 0, + "cyclomatic": 2, + "lcom4": 1 } ] } From 5d5baffb958e79a683b167548146d425f66155bb Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:25:51 -0800 Subject: [PATCH 41/53] Multiple test --- .../lang/csharp/basic.in/fields/Multiple.cs | 15 +++++++ qlty-cli/tests/lang/csharp/basic.stdout | 40 ++++++++++++++----- 2 files changed, 45 insertions(+), 10 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/fields/Multiple.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/fields/Multiple.cs b/qlty-cli/tests/lang/csharp/basic.in/fields/Multiple.cs new file mode 100644 index 000000000..c091d69fa --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/fields/Multiple.cs @@ -0,0 +1,15 @@ +namespace Fields +{ + public class Multiple + { + public string bar; + public string baz; + + // Constructor + public Multiple() + { + this.bar = ""; + this.baz = ""; + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 3880070e8..d53a9b83f 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 26, + "filesAnalyzed": 27, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -872,6 +872,26 @@ "cyclomatic": 2, "lcom4": 1 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "Multiple.cs", + "fullyQualifiedName": "fields/Multiple.cs", + "path": "fields/Multiple.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 2, + "lines": 15, + "codeLines": 12, + "commentLines": 1, + "blankLines": 2, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -917,16 +937,16 @@ "fullyQualifiedName": "fields", "path": "fields", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 1, - "classes": 2, - "functions": 3, - "fields": 2, - "lines": 31, - "codeLines": 24, - "commentLines": 1, - "blankLines": 6, + "files": 2, + "classes": 3, + "functions": 4, + "fields": 4, + "lines": 46, + "codeLines": 36, + "commentLines": 2, + "blankLines": 8, "complexity": 0, - "cyclomatic": 2, + "cyclomatic": 3, "lcom4": 1 } ] From b527ec8807c816390224b2f7a7bd58b9a1f3a929 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:37:43 -0800 Subject: [PATCH 42/53] Other --- .../lang/csharp/basic.in/fields/Other.cs | 15 ++++++++ qlty-cli/tests/lang/csharp/basic.stdout | 38 ++++++++++++++----- 2 files changed, 44 insertions(+), 9 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/fields/Other.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/fields/Other.cs b/qlty-cli/tests/lang/csharp/basic.in/fields/Other.cs new file mode 100644 index 000000000..322b7bf99 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/fields/Other.cs @@ -0,0 +1,15 @@ +namespace Fields +{ + public class Other + { + public int foo; + public int bar; + + public static void Main(string[] args) + { + Other other = new Other(); + other.foo = 1; + int barValue = other.bar; + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index d53a9b83f..20755052a 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 27, + "filesAnalyzed": 28, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -892,6 +892,26 @@ "cyclomatic": 1, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "Other.cs", + "fullyQualifiedName": "fields/Other.cs", + "path": "fields/Other.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 2, + "lines": 15, + "codeLines": 13, + "commentLines": 0, + "blankLines": 2, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -937,16 +957,16 @@ "fullyQualifiedName": "fields", "path": "fields", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 2, - "classes": 3, - "functions": 4, - "fields": 4, - "lines": 46, - "codeLines": 36, + "files": 3, + "classes": 4, + "functions": 5, + "fields": 6, + "lines": 61, + "codeLines": 49, "commentLines": 2, - "blankLines": 8, + "blankLines": 10, "complexity": 0, - "cyclomatic": 3, + "cyclomatic": 4, "lcom4": 1 } ] From 97c90f2a2a2b6ac91b45206e0067e7e62e2f10b2 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Tue, 7 Jan 2025 17:51:47 -0800 Subject: [PATCH 43/53] Read --- .../tests/lang/csharp/basic.in/fields/Read.cs | 12 ++++++ qlty-cli/tests/lang/csharp/basic.stdout | 38 ++++++++++++++----- 2 files changed, 41 insertions(+), 9 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/fields/Read.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/fields/Read.cs b/qlty-cli/tests/lang/csharp/basic.in/fields/Read.cs new file mode 100644 index 000000000..b15e97bb8 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/fields/Read.cs @@ -0,0 +1,12 @@ +namespace Fields +{ + public class Read + { + string foo = "foo"; + + public void Main(string[] args) + { + System.Console.WriteLine(this.foo); + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 20755052a..67ce512c3 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 28, + "filesAnalyzed": 29, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -912,6 +912,26 @@ "cyclomatic": 1, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "Read.cs", + "fullyQualifiedName": "fields/Read.cs", + "path": "fields/Read.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 1, + "lines": 12, + "codeLines": 10, + "commentLines": 0, + "blankLines": 2, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -957,16 +977,16 @@ "fullyQualifiedName": "fields", "path": "fields", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 3, - "classes": 4, - "functions": 5, - "fields": 6, - "lines": 61, - "codeLines": 49, + "files": 4, + "classes": 5, + "functions": 6, + "fields": 7, + "lines": 73, + "codeLines": 59, "commentLines": 2, - "blankLines": 10, + "blankLines": 12, "complexity": 0, - "cyclomatic": 4, + "cyclomatic": 5, "lcom4": 1 } ] From 2e1098674ca8e51f85fe62663a3057b76346b8e7 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Tue, 7 Jan 2025 19:17:52 -0800 Subject: [PATCH 44/53] Private Field Declaration --- .../fields/PrivateFieldDeclaration.cs | 17 ++++++++ qlty-cli/tests/lang/csharp/basic.stdout | 40 ++++++++++++++----- .../csharp/pending/GetterSetterDeclaration.cs | 19 +++++++++ .../csharp/pending/PublicFieldDeclaration.cs | 9 +++++ .../csharp/pending/StaticFieldDeclaration.cs | 9 +++++ qlty-cli/tests/lang/csharp/pending/Unique.cs | 10 +++++ qlty-cli/tests/lang/csharp/pending/Write.cs | 11 +++++ 7 files changed, 105 insertions(+), 10 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/fields/PrivateFieldDeclaration.cs create mode 100644 qlty-cli/tests/lang/csharp/pending/GetterSetterDeclaration.cs create mode 100644 qlty-cli/tests/lang/csharp/pending/PublicFieldDeclaration.cs create mode 100644 qlty-cli/tests/lang/csharp/pending/StaticFieldDeclaration.cs create mode 100644 qlty-cli/tests/lang/csharp/pending/Unique.cs create mode 100644 qlty-cli/tests/lang/csharp/pending/Write.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/fields/PrivateFieldDeclaration.cs b/qlty-cli/tests/lang/csharp/basic.in/fields/PrivateFieldDeclaration.cs new file mode 100644 index 000000000..d65ae2295 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/fields/PrivateFieldDeclaration.cs @@ -0,0 +1,17 @@ +namespace Fields +{ + public class PrivateFieldDeclaration + { + private string privateField = "privateValue"; + + public string GetPrivateField() + { + return this.privateField; + } + + public static void Main(string[] args) + { + // Entry point + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 67ce512c3..58af46df6 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 29, + "filesAnalyzed": 30, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -912,6 +912,26 @@ "cyclomatic": 1, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "PrivateFieldDeclaration.cs", + "fullyQualifiedName": "fields/PrivateFieldDeclaration.cs", + "path": "fields/PrivateFieldDeclaration.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 2, + "fields": 1, + "lines": 17, + "codeLines": 12, + "commentLines": 1, + "blankLines": 4, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -977,16 +997,16 @@ "fullyQualifiedName": "fields", "path": "fields", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 4, - "classes": 5, - "functions": 6, - "fields": 7, - "lines": 73, - "codeLines": 59, - "commentLines": 2, - "blankLines": 12, + "files": 5, + "classes": 6, + "functions": 8, + "fields": 8, + "lines": 90, + "codeLines": 71, + "commentLines": 3, + "blankLines": 16, "complexity": 0, - "cyclomatic": 5, + "cyclomatic": 6, "lcom4": 1 } ] diff --git a/qlty-cli/tests/lang/csharp/pending/GetterSetterDeclaration.cs b/qlty-cli/tests/lang/csharp/pending/GetterSetterDeclaration.cs new file mode 100644 index 000000000..6db56d8e2 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/pending/GetterSetterDeclaration.cs @@ -0,0 +1,19 @@ +package fields; + +public class GetterSetterDeclaration { + private String field; + + public String getFieldName() { + return this.field; + } + + public void setFieldName(String value) { + this.field = value; + } + + public static void main(String[] args) { + GetterSetterDeclaration obj = new GetterSetterDeclaration(); + obj.setFieldName("Hello"); + System.out.println(obj.getFieldName()); + } +} diff --git a/qlty-cli/tests/lang/csharp/pending/PublicFieldDeclaration.cs b/qlty-cli/tests/lang/csharp/pending/PublicFieldDeclaration.cs new file mode 100644 index 000000000..7d3fc0df5 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/pending/PublicFieldDeclaration.cs @@ -0,0 +1,9 @@ +package fields; + +public class PublicFieldDeclaration { + String fieldName = "someValue"; + + public static void main(String[] args) { + + } +} diff --git a/qlty-cli/tests/lang/csharp/pending/StaticFieldDeclaration.cs b/qlty-cli/tests/lang/csharp/pending/StaticFieldDeclaration.cs new file mode 100644 index 000000000..cf90b7616 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/pending/StaticFieldDeclaration.cs @@ -0,0 +1,9 @@ +package fields; + +public class StaticFieldDeclaration { + public static String staticField = "staticValue"; + + public static void main(String[] args) { + System.out.println(StaticFieldDeclaration.staticField); + } +} diff --git a/qlty-cli/tests/lang/csharp/pending/Unique.cs b/qlty-cli/tests/lang/csharp/pending/Unique.cs new file mode 100644 index 000000000..f9c142bcb --- /dev/null +++ b/qlty-cli/tests/lang/csharp/pending/Unique.cs @@ -0,0 +1,10 @@ +package fields; + +public class Unique { + public int foo; + + public void main(String[] args) { + this.foo = 1; + System.out.println(this.foo); + } +} diff --git a/qlty-cli/tests/lang/csharp/pending/Write.cs b/qlty-cli/tests/lang/csharp/pending/Write.cs new file mode 100644 index 000000000..ccc96723b --- /dev/null +++ b/qlty-cli/tests/lang/csharp/pending/Write.cs @@ -0,0 +1,11 @@ +package fields; + +public class Write { + public int foo; + public int bar; + + public void main(String[] args) { + this.foo = 1; + this.bar = 2; + } +} From 55fbeffe01360e844a214e4ebb65d71bfb25a5b8 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Tue, 7 Jan 2025 19:21:28 -0800 Subject: [PATCH 45/53] Unique --- .../lang/csharp/basic.in/fields/Unique.cs | 13 +++++++ qlty-cli/tests/lang/csharp/basic.stdout | 38 ++++++++++++++----- qlty-cli/tests/lang/csharp/pending/Unique.cs | 10 ----- 3 files changed, 42 insertions(+), 19 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/fields/Unique.cs delete mode 100644 qlty-cli/tests/lang/csharp/pending/Unique.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/fields/Unique.cs b/qlty-cli/tests/lang/csharp/basic.in/fields/Unique.cs new file mode 100644 index 000000000..909a05be0 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/fields/Unique.cs @@ -0,0 +1,13 @@ +namespace Fields +{ + public class Unique + { + public int foo; + + public void Main(string[] args) + { + this.foo = 1; + System.Console.WriteLine(this.foo); + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 58af46df6..edac3445e 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 30, + "filesAnalyzed": 31, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -952,6 +952,26 @@ "cyclomatic": 1, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "Unique.cs", + "fullyQualifiedName": "fields/Unique.cs", + "path": "fields/Unique.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 1, + "lines": 13, + "codeLines": 11, + "commentLines": 0, + "blankLines": 2, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -997,16 +1017,16 @@ "fullyQualifiedName": "fields", "path": "fields", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 5, - "classes": 6, - "functions": 8, - "fields": 8, - "lines": 90, - "codeLines": 71, + "files": 6, + "classes": 7, + "functions": 9, + "fields": 9, + "lines": 103, + "codeLines": 82, "commentLines": 3, - "blankLines": 16, + "blankLines": 18, "complexity": 0, - "cyclomatic": 6, + "cyclomatic": 7, "lcom4": 1 } ] diff --git a/qlty-cli/tests/lang/csharp/pending/Unique.cs b/qlty-cli/tests/lang/csharp/pending/Unique.cs deleted file mode 100644 index f9c142bcb..000000000 --- a/qlty-cli/tests/lang/csharp/pending/Unique.cs +++ /dev/null @@ -1,10 +0,0 @@ -package fields; - -public class Unique { - public int foo; - - public void main(String[] args) { - this.foo = 1; - System.out.println(this.foo); - } -} From 510b487580d2ab577d0ac6916e70f219741d0e2d Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Tue, 7 Jan 2025 19:33:15 -0800 Subject: [PATCH 46/53] 3 more field tests --- .../basic.in/fields/PublicFieldDeclaration.cs | 12 +++ .../basic.in/fields/StaticFieldDeclaration.cs | 12 +++ .../{pending => basic.in/fields}/Write.cs | 0 qlty-cli/tests/lang/csharp/basic.stdout | 92 +++++++++++++++---- .../csharp/pending/PublicFieldDeclaration.cs | 9 -- .../csharp/pending/StaticFieldDeclaration.cs | 9 -- 6 files changed, 100 insertions(+), 34 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/fields/PublicFieldDeclaration.cs create mode 100644 qlty-cli/tests/lang/csharp/basic.in/fields/StaticFieldDeclaration.cs rename qlty-cli/tests/lang/csharp/{pending => basic.in/fields}/Write.cs (100%) delete mode 100644 qlty-cli/tests/lang/csharp/pending/PublicFieldDeclaration.cs delete mode 100644 qlty-cli/tests/lang/csharp/pending/StaticFieldDeclaration.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/fields/PublicFieldDeclaration.cs b/qlty-cli/tests/lang/csharp/basic.in/fields/PublicFieldDeclaration.cs new file mode 100644 index 000000000..af6cb5d28 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/fields/PublicFieldDeclaration.cs @@ -0,0 +1,12 @@ +namespace Fields +{ + public class PublicFieldDeclaration + { + public string fieldName = "someValue"; + + public static void Main(string[] args) + { + // Entry point + } + } +} diff --git a/qlty-cli/tests/lang/csharp/basic.in/fields/StaticFieldDeclaration.cs b/qlty-cli/tests/lang/csharp/basic.in/fields/StaticFieldDeclaration.cs new file mode 100644 index 000000000..1e31b5800 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/fields/StaticFieldDeclaration.cs @@ -0,0 +1,12 @@ +namespace Fields +{ + public class StaticFieldDeclaration + { + public static string staticField = "staticValue"; + + public static void Main(string[] args) + { + System.Console.WriteLine(StaticFieldDeclaration.staticField); + } + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/pending/Write.cs b/qlty-cli/tests/lang/csharp/basic.in/fields/Write.cs similarity index 100% rename from qlty-cli/tests/lang/csharp/pending/Write.cs rename to qlty-cli/tests/lang/csharp/basic.in/fields/Write.cs diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index edac3445e..47ca907e6 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 31, + "filesAnalyzed": 34, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -932,6 +932,26 @@ "cyclomatic": 1, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "PublicFieldDeclaration.cs", + "fullyQualifiedName": "fields/PublicFieldDeclaration.cs", + "path": "fields/PublicFieldDeclaration.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 1, + "lines": 12, + "codeLines": 10, + "commentLines": 1, + "blankLines": 1, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -955,6 +975,26 @@ { "buildId": "[..]", "analyzedAt": "[..]", + "name": "StaticFieldDeclaration.cs", + "fullyQualifiedName": "fields/StaticFieldDeclaration.cs", + "path": "fields/StaticFieldDeclaration.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 1, + "lines": 12, + "codeLines": 10, + "commentLines": 0, + "blankLines": 2, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 + }, + { + "buildId": "7d9708e2-e7ab-4b9c-8347-d2bef72927b0", + "analyzedAt": "2025-01-08T03:31:31.248192+00:00", "name": "Unique.cs", "fullyQualifiedName": "fields/Unique.cs", "path": "fields/Unique.cs", @@ -973,8 +1013,28 @@ "lcom4": 0 }, { - "buildId": "[..]", - "analyzedAt": "[..]", + "buildId": "7d9708e2-e7ab-4b9c-8347-d2bef72927b0", + "analyzedAt": "2025-01-08T03:31:31.248192+00:00", + "name": "Write.cs", + "fullyQualifiedName": "fields/Write.cs", + "path": "fields/Write.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 2, + "lines": 11, + "codeLines": 10, + "commentLines": 0, + "blankLines": 1, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 + }, + { + "buildId": "7d9708e2-e7ab-4b9c-8347-d2bef72927b0", + "analyzedAt": "2025-01-08T03:31:31.248192+00:00", "name": "cognitive", "fullyQualifiedName": "cognitive", "path": "cognitive", @@ -992,8 +1052,8 @@ "lcom4": 0 }, { - "buildId": "[..]", - "analyzedAt": "[..]", + "buildId": "7d9708e2-e7ab-4b9c-8347-d2bef72927b0", + "analyzedAt": "2025-01-08T03:31:31.248192+00:00", "name": "cyclomatic", "fullyQualifiedName": "cyclomatic", "path": "cyclomatic", @@ -1011,22 +1071,22 @@ "lcom4": 1 }, { - "buildId": "[..]", - "analyzedAt": "[..]", + "buildId": "7d9708e2-e7ab-4b9c-8347-d2bef72927b0", + "analyzedAt": "2025-01-08T03:31:31.248192+00:00", "name": "fields", "fullyQualifiedName": "fields", "path": "fields", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 6, - "classes": 7, - "functions": 9, - "fields": 9, - "lines": 103, - "codeLines": 82, - "commentLines": 3, - "blankLines": 18, + "files": 9, + "classes": 10, + "functions": 12, + "fields": 13, + "lines": 138, + "codeLines": 112, + "commentLines": 4, + "blankLines": 22, "complexity": 0, - "cyclomatic": 7, + "cyclomatic": 10, "lcom4": 1 } ] diff --git a/qlty-cli/tests/lang/csharp/pending/PublicFieldDeclaration.cs b/qlty-cli/tests/lang/csharp/pending/PublicFieldDeclaration.cs deleted file mode 100644 index 7d3fc0df5..000000000 --- a/qlty-cli/tests/lang/csharp/pending/PublicFieldDeclaration.cs +++ /dev/null @@ -1,9 +0,0 @@ -package fields; - -public class PublicFieldDeclaration { - String fieldName = "someValue"; - - public static void main(String[] args) { - - } -} diff --git a/qlty-cli/tests/lang/csharp/pending/StaticFieldDeclaration.cs b/qlty-cli/tests/lang/csharp/pending/StaticFieldDeclaration.cs deleted file mode 100644 index cf90b7616..000000000 --- a/qlty-cli/tests/lang/csharp/pending/StaticFieldDeclaration.cs +++ /dev/null @@ -1,9 +0,0 @@ -package fields; - -public class StaticFieldDeclaration { - public static String staticField = "staticValue"; - - public static void main(String[] args) { - System.out.println(StaticFieldDeclaration.staticField); - } -} From 2bfb5755bff417430c0e432f340fdbfc33f6acbf Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Tue, 7 Jan 2025 19:33:32 -0800 Subject: [PATCH 47/53] - --- qlty-cli/tests/lang/csharp/basic.stdout | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 47ca907e6..7486a6926 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -1013,8 +1013,8 @@ "lcom4": 0 }, { - "buildId": "7d9708e2-e7ab-4b9c-8347-d2bef72927b0", - "analyzedAt": "2025-01-08T03:31:31.248192+00:00", + "buildId": "[..]", + "analyzedAt": "[..]", "name": "Write.cs", "fullyQualifiedName": "fields/Write.cs", "path": "fields/Write.cs", @@ -1033,8 +1033,8 @@ "lcom4": 0 }, { - "buildId": "7d9708e2-e7ab-4b9c-8347-d2bef72927b0", - "analyzedAt": "2025-01-08T03:31:31.248192+00:00", + "buildId": "[..]", + "analyzedAt": "[..]", "name": "cognitive", "fullyQualifiedName": "cognitive", "path": "cognitive", @@ -1052,8 +1052,8 @@ "lcom4": 0 }, { - "buildId": "7d9708e2-e7ab-4b9c-8347-d2bef72927b0", - "analyzedAt": "2025-01-08T03:31:31.248192+00:00", + "buildId": "[..]", + "analyzedAt": "[..]", "name": "cyclomatic", "fullyQualifiedName": "cyclomatic", "path": "cyclomatic", @@ -1071,8 +1071,8 @@ "lcom4": 1 }, { - "buildId": "7d9708e2-e7ab-4b9c-8347-d2bef72927b0", - "analyzedAt": "2025-01-08T03:31:31.248192+00:00", + "buildId": "[..]", + "analyzedAt": "[..]", "name": "fields", "fullyQualifiedName": "fields", "path": "fields", From 4ddff3fa5c11108eb387203e8ca00d97bbaa197a Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Tue, 7 Jan 2025 19:50:46 -0800 Subject: [PATCH 48/53] Add Methods tests --- .../basic.in/functions/MethodsWithParams.cs | 18 +++ .../functions/MethodsWithoutParams.cs | 22 ++++ .../functions/SingletonMethodsWithParams.cs | 13 +++ .../SingletonMethodsWithoutParams.cs | 7 ++ qlty-cli/tests/lang/csharp/basic.stdout | 105 +++++++++++++++++- 5 files changed, 162 insertions(+), 3 deletions(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/functions/MethodsWithParams.cs create mode 100644 qlty-cli/tests/lang/csharp/basic.in/functions/MethodsWithoutParams.cs create mode 100644 qlty-cli/tests/lang/csharp/basic.in/functions/SingletonMethodsWithParams.cs create mode 100644 qlty-cli/tests/lang/csharp/basic.in/functions/SingletonMethodsWithoutParams.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/functions/MethodsWithParams.cs b/qlty-cli/tests/lang/csharp/basic.in/functions/MethodsWithParams.cs new file mode 100644 index 000000000..75d4e81ce --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/functions/MethodsWithParams.cs @@ -0,0 +1,18 @@ +public class MethodsWithParams +{ + private string bar; + private string baz; + + public MethodsWithParams() + { + this.bar = ""; + this.baz = ""; + } + + public string DoSomething(string baz, string bar) + { + this.bar = bar; + this.baz = baz; + return this.bar + this.baz; + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.in/functions/MethodsWithoutParams.cs b/qlty-cli/tests/lang/csharp/basic.in/functions/MethodsWithoutParams.cs new file mode 100644 index 000000000..2a2602bf9 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/functions/MethodsWithoutParams.cs @@ -0,0 +1,22 @@ +class MethodsWithOutParams +{ + private double width; + private double height; + + public MethodsWithOutParams() + { + } + + public double Area() + { + return this.width * this.height; + } + + public void Foo() + { + } + + public void Bar() + { + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.in/functions/SingletonMethodsWithParams.cs b/qlty-cli/tests/lang/csharp/basic.in/functions/SingletonMethodsWithParams.cs new file mode 100644 index 000000000..108eab998 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/functions/SingletonMethodsWithParams.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +public class SingletonMethodsWithParams +{ + public static List Bar(object dog, object cat) + { + return new List { dog, cat } + .Select(animal => animal.ToString()) + .ToList(); + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.in/functions/SingletonMethodsWithoutParams.cs b/qlty-cli/tests/lang/csharp/basic.in/functions/SingletonMethodsWithoutParams.cs new file mode 100644 index 000000000..fcd4c14cc --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/functions/SingletonMethodsWithoutParams.cs @@ -0,0 +1,7 @@ +public class SingletonMethodsWithoutParams +{ + public static string Bar() + { + return "bar"; + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 7486a6926..230ef3090 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 34, + "filesAnalyzed": 38, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -993,8 +993,8 @@ "lcom4": 0 }, { - "buildId": "7d9708e2-e7ab-4b9c-8347-d2bef72927b0", - "analyzedAt": "2025-01-08T03:31:31.248192+00:00", + "buildId": "[..]", + "analyzedAt": "[..]", "name": "Unique.cs", "fullyQualifiedName": "fields/Unique.cs", "path": "fields/Unique.cs", @@ -1032,6 +1032,86 @@ "cyclomatic": 1, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "MethodsWithParams.cs", + "fullyQualifiedName": "functions/MethodsWithParams.cs", + "path": "functions/MethodsWithParams.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 2, + "fields": 2, + "lines": 18, + "codeLines": 14, + "commentLines": 0, + "blankLines": 4, + "complexity": 0, + "cyclomatic": 2, + "lcom4": 0 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "MethodsWithoutParams.cs", + "fullyQualifiedName": "functions/MethodsWithoutParams.cs", + "path": "functions/MethodsWithoutParams.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 4, + "fields": 2, + "lines": 22, + "codeLines": 14, + "commentLines": 0, + "blankLines": 8, + "complexity": 0, + "cyclomatic": 2, + "lcom4": 0 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "SingletonMethodsWithParams.cs", + "fullyQualifiedName": "functions/SingletonMethodsWithParams.cs", + "path": "functions/SingletonMethodsWithParams.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 13, + "codeLines": 11, + "commentLines": 0, + "blankLines": 2, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "SingletonMethodsWithoutParams.cs", + "fullyQualifiedName": "functions/SingletonMethodsWithoutParams.cs", + "path": "functions/SingletonMethodsWithoutParams.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 0, + "lines": 7, + "codeLines": 6, + "commentLines": 0, + "blankLines": 1, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -1088,6 +1168,25 @@ "complexity": 0, "cyclomatic": 10, "lcom4": 1 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "functions", + "fullyQualifiedName": "functions", + "path": "functions", + "kind": "COMPONENT_TYPE_DIRECTORY", + "files": 4, + "classes": 4, + "functions": 8, + "fields": 4, + "lines": 60, + "codeLines": 45, + "commentLines": 0, + "blankLines": 15, + "complexity": 0, + "cyclomatic": 6, + "lcom4": 0 } ] } From d5b26228614eb22f9aa4893775e5119791dd4901 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Tue, 7 Jan 2025 20:00:03 -0800 Subject: [PATCH 49/53] Add lcom tests --- .../tests/lang/csharp/basic.in/lcom/lcom_0.cs | 48 +++++++++ .../lang/csharp/basic.in/lcom/lcom_1-1.cs | 18 ++++ .../tests/lang/csharp/basic.in/lcom/lcom_1.cs | 20 ++++ .../tests/lang/csharp/basic.in/lcom/lcom_2.cs | 47 ++++++++ qlty-cli/tests/lang/csharp/basic.stdout | 101 +++++++++++++++++- 5 files changed, 233 insertions(+), 1 deletion(-) create mode 100644 qlty-cli/tests/lang/csharp/basic.in/lcom/lcom_0.cs create mode 100644 qlty-cli/tests/lang/csharp/basic.in/lcom/lcom_1-1.cs create mode 100644 qlty-cli/tests/lang/csharp/basic.in/lcom/lcom_1.cs create mode 100644 qlty-cli/tests/lang/csharp/basic.in/lcom/lcom_2.cs diff --git a/qlty-cli/tests/lang/csharp/basic.in/lcom/lcom_0.cs b/qlty-cli/tests/lang/csharp/basic.in/lcom/lcom_0.cs new file mode 100644 index 000000000..46fca6b17 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/lcom/lcom_0.cs @@ -0,0 +1,48 @@ +// lcom = 0 for all the tests in this file, totalling 0 + +class Foo +{ + private string bar; + + public string foo() + { + return this.bar; + } +} + +class Klass1 +{ + public Klass1() + { + } + + public object foo() + { + return null; + } +} + +class Klass2 +{ + private Bar bar; + + public Klass2(Bar bar) + { + this.bar = bar; + } + + public object foo() + { + return this.bar.getBaz(); + } +} + +class Bar +{ + private string baz; + + public string getBaz() + { + return this.baz; + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.in/lcom/lcom_1-1.cs b/qlty-cli/tests/lang/csharp/basic.in/lcom/lcom_1-1.cs new file mode 100644 index 000000000..40c0edfa8 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/lcom/lcom_1-1.cs @@ -0,0 +1,18 @@ +// lcom=1 + +class Klass +{ + public Klass() + { + } + + public string Foo() + { + return this.Baz(); + } + + private string Baz() + { + return "baz method called"; + } +} diff --git a/qlty-cli/tests/lang/csharp/basic.in/lcom/lcom_1.cs b/qlty-cli/tests/lang/csharp/basic.in/lcom/lcom_1.cs new file mode 100644 index 000000000..4573d6d94 --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/lcom/lcom_1.cs @@ -0,0 +1,20 @@ +// lcom=1 + +class Klass +{ + private string bar; + + public Klass() + { + } + + public string GetBar() + { + return this.bar; + } + + public string Foo() + { + return this.GetBar(); + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.in/lcom/lcom_2.cs b/qlty-cli/tests/lang/csharp/basic.in/lcom/lcom_2.cs new file mode 100644 index 000000000..f8274b10d --- /dev/null +++ b/qlty-cli/tests/lang/csharp/basic.in/lcom/lcom_2.cs @@ -0,0 +1,47 @@ +// lcom=2 + +class KlassA +{ + private string aaa; + private string bbb; + + public string GetBbb() + { + return this.bbb; + } + + public string GetAaa() + { + return this.aaa; + } + + private string Foo() + { + return this.GetAaa(); + } + + private string Bar() + { + return this.GetBbb(); + } +} + +class KlassB +{ + private string baz; + + public string GetBar() + { + return this.baz; + } + + private string Foo() + { + return this.GetBar(); + } + + private string Bar() + { + return this.GetBar(); + } +} \ No newline at end of file diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index 230ef3090..a85450790 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 38, + "filesAnalyzed": 42, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -1112,6 +1112,86 @@ "cyclomatic": 1, "lcom4": 0 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "lcom_0.cs", + "fullyQualifiedName": "lcom/lcom_0.cs", + "path": "lcom/lcom_0.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 4, + "functions": 6, + "fields": 2, + "lines": 48, + "codeLines": 33, + "commentLines": 0, + "blankLines": 15, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "lcom_1-1.cs", + "fullyQualifiedName": "lcom/lcom_1-1.cs", + "path": "lcom/lcom_1-1.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 3, + "fields": 0, + "lines": 18, + "codeLines": 13, + "commentLines": 0, + "blankLines": 5, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 1 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "lcom_1.cs", + "fullyQualifiedName": "lcom/lcom_1.cs", + "path": "lcom/lcom_1.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 3, + "fields": 1, + "lines": 20, + "codeLines": 13, + "commentLines": 0, + "blankLines": 7, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 1 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "lcom_2.cs", + "fullyQualifiedName": "lcom/lcom_2.cs", + "path": "lcom/lcom_2.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 2, + "functions": 7, + "fields": 3, + "lines": 47, + "codeLines": 31, + "commentLines": 0, + "blankLines": 16, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 2 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -1187,6 +1267,25 @@ "complexity": 0, "cyclomatic": 6, "lcom4": 0 + }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "lcom", + "fullyQualifiedName": "lcom", + "path": "lcom", + "kind": "COMPONENT_TYPE_DIRECTORY", + "files": 4, + "classes": 8, + "functions": 19, + "fields": 6, + "lines": 133, + "codeLines": 90, + "commentLines": 0, + "blankLines": 43, + "complexity": 0, + "cyclomatic": 4, + "lcom4": 4 } ] } From 0cc33420439d65b3324b11458372fc3423af2467 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Tue, 7 Jan 2025 20:03:24 -0800 Subject: [PATCH 50/53] Add real pending test --- qlty-cli/tests/lang.rs | 2 +- .../csharp/pending/GetterSetterDeclaration.cs | 33 ++++++++----------- 2 files changed, 15 insertions(+), 20 deletions(-) diff --git a/qlty-cli/tests/lang.rs b/qlty-cli/tests/lang.rs index 8b6249777..21ec20f8c 100644 --- a/qlty-cli/tests/lang.rs +++ b/qlty-cli/tests/lang.rs @@ -51,6 +51,6 @@ fn go_tests() { } #[test] -fn c_sharp_tests() { +fn csharp_tests() { setup_and_run_test_cases("tests/lang/csharp/**/*.toml"); } diff --git a/qlty-cli/tests/lang/csharp/pending/GetterSetterDeclaration.cs b/qlty-cli/tests/lang/csharp/pending/GetterSetterDeclaration.cs index 6db56d8e2..73bdbff58 100644 --- a/qlty-cli/tests/lang/csharp/pending/GetterSetterDeclaration.cs +++ b/qlty-cli/tests/lang/csharp/pending/GetterSetterDeclaration.cs @@ -1,19 +1,14 @@ -package fields; - -public class GetterSetterDeclaration { - private String field; - - public String getFieldName() { - return this.field; - } - - public void setFieldName(String value) { - this.field = value; - } - - public static void main(String[] args) { - GetterSetterDeclaration obj = new GetterSetterDeclaration(); - obj.setFieldName("Hello"); - System.out.println(obj.getFieldName()); - } -} +namespace Fields +{ + public class GetterSetterDeclaration + { + public string Field { get; set; } + + public static void Main(string[] args) + { + GetterSetterDeclaration obj = new GetterSetterDeclaration(); + obj.Field = "Hello"; + System.Console.WriteLine(obj.Field); + } + } +} \ No newline at end of file From c7fb1e7385184108d767940decd7a4c2863cba48 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Wed, 8 Jan 2025 10:24:25 -0800 Subject: [PATCH 51/53] Count properties as fields --- qlty-analysis/src/lang/csharp.rs | 11 +++--- .../fields}/GetterSetterDeclaration.cs | 2 + qlty-cli/tests/lang/csharp/basic.stdout | 38 ++++++++++++++----- 3 files changed, 37 insertions(+), 14 deletions(-) rename qlty-cli/tests/lang/csharp/{pending => basic.in/fields}/GetterSetterDeclaration.cs (83%) diff --git a/qlty-analysis/src/lang/csharp.rs b/qlty-analysis/src/lang/csharp.rs index 75a82e249..7490197cd 100644 --- a/qlty-analysis/src/lang/csharp.rs +++ b/qlty-analysis/src/lang/csharp.rs @@ -27,11 +27,12 @@ const FUNCTION_DECLARATION_QUERY: &str = r#" "#; const FIELD_QUERY: &str = r#" - (field_declaration - (variable_declaration - (variable_declarator name: (identifier) @name) - ) - ) @field + [(field_declaration + (variable_declaration + (variable_declarator name: (identifier) @name) + ) + ) @field + (property_declaration name: (identifier) @name) @field] "#; pub struct CSharp { diff --git a/qlty-cli/tests/lang/csharp/pending/GetterSetterDeclaration.cs b/qlty-cli/tests/lang/csharp/basic.in/fields/GetterSetterDeclaration.cs similarity index 83% rename from qlty-cli/tests/lang/csharp/pending/GetterSetterDeclaration.cs rename to qlty-cli/tests/lang/csharp/basic.in/fields/GetterSetterDeclaration.cs index 73bdbff58..02eb16bf2 100644 --- a/qlty-cli/tests/lang/csharp/pending/GetterSetterDeclaration.cs +++ b/qlty-cli/tests/lang/csharp/basic.in/fields/GetterSetterDeclaration.cs @@ -3,11 +3,13 @@ namespace Fields public class GetterSetterDeclaration { public string Field { get; set; } + public string _field2 public static void Main(string[] args) { GetterSetterDeclaration obj = new GetterSetterDeclaration(); obj.Field = "Hello"; + obj._field2 = "World"; System.Console.WriteLine(obj.Field); } } diff --git a/qlty-cli/tests/lang/csharp/basic.stdout b/qlty-cli/tests/lang/csharp/basic.stdout index a85450790..9eac2aa3c 100644 --- a/qlty-cli/tests/lang/csharp/basic.stdout +++ b/qlty-cli/tests/lang/csharp/basic.stdout @@ -2,7 +2,7 @@ "metadata": { "buildId": "[..]", "result": "ANALYSIS_RESULT_SUCCESS", - "filesAnalyzed": 42, + "filesAnalyzed": 43, "startTime": "[..]", "finishTime": "[..]", "commitMessage": "initial/n", @@ -872,6 +872,26 @@ "cyclomatic": 2, "lcom4": 1 }, + { + "buildId": "[..]", + "analyzedAt": "[..]", + "name": "GetterSetterDeclaration.cs", + "fullyQualifiedName": "fields/GetterSetterDeclaration.cs", + "path": "fields/GetterSetterDeclaration.cs", + "kind": "COMPONENT_TYPE_FILE", + "language": "LANGUAGE_C_SHARP", + "files": 1, + "classes": 1, + "functions": 1, + "fields": 2, + "lines": 16, + "codeLines": 14, + "commentLines": 0, + "blankLines": 2, + "complexity": 0, + "cyclomatic": 1, + "lcom4": 0 + }, { "buildId": "[..]", "analyzedAt": "[..]", @@ -1237,16 +1257,16 @@ "fullyQualifiedName": "fields", "path": "fields", "kind": "COMPONENT_TYPE_DIRECTORY", - "files": 9, - "classes": 10, - "functions": 12, - "fields": 13, - "lines": 138, - "codeLines": 112, + "files": 10, + "classes": 11, + "functions": 13, + "fields": 15, + "lines": 154, + "codeLines": 126, "commentLines": 4, - "blankLines": 22, + "blankLines": 24, "complexity": 0, - "cyclomatic": 10, + "cyclomatic": 11, "lcom4": 1 }, { From c4216d7314bfddc09292198e144952c916ee38e1 Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Wed, 8 Jan 2025 11:30:39 -0800 Subject: [PATCH 52/53] More fully fleshed C# node types --- qlty-analysis/src/lang/csharp.rs | 39 +++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/qlty-analysis/src/lang/csharp.rs b/qlty-analysis/src/lang/csharp.rs index 7490197cd..d16bec251 100644 --- a/qlty-analysis/src/lang/csharp.rs +++ b/qlty-analysis/src/lang/csharp.rs @@ -55,8 +55,11 @@ impl CSharp { pub const FIELD_ACCESS: &'static str = "member_access_expression"; pub const FOR: &'static str = "for_statement"; pub const FOREACH: &'static str = "foreach_statement"; + pub const GOTO: &'static str = "goto_statement"; + pub const INTERPOLATED_STRING: &'static str = "interpolated_string_expression"; pub const METHOD_DECLARATION: &'static str = "method_declaration"; pub const METHOD_INVOCATION: &'static str = "invocation_expression"; + pub const PROPERTY_DECLARATION: &'static str = "property_declaration"; pub const IDENTIFIER: &'static str = "identifier"; pub const IF: &'static str = "if_statement"; pub const LAMBDA: &'static str = "lambda_expression"; @@ -150,7 +153,7 @@ impl Language for CSharp { } fn jump_nodes(&self) -> Vec<&str> { - vec![Self::BREAK, Self::CONTINUE] + vec![Self::BREAK, Self::CONTINUE, Self::GOTO] } fn return_nodes(&self) -> Vec<&str> { @@ -166,7 +169,7 @@ impl Language for CSharp { } fn field_nodes(&self) -> Vec<&str> { - vec![Self::FIELD_DECLARATION] + vec![Self::FIELD_DECLARATION, Self::PROPERTY_DECLARATION] } fn call_nodes(&self) -> Vec<&str> { @@ -186,7 +189,7 @@ impl Language for CSharp { } fn string_nodes(&self) -> Vec<&str> { - vec![Self::STRING] + vec![Self::STRING, Self::INTERPOLATED_STRING] } fn is_jump_label(&self, node: &Node) -> bool { @@ -254,6 +257,36 @@ fn get_node_source_or_default(node: Option, source_file: &File) -> String mod test { use super::*; use tree_sitter::Tree; + use std::collections::HashSet; + + #[test] + fn mutually_exclusive() { + let lang = CSharp::default(); + let mut kinds: Vec<&str> = vec![]; + + kinds.extend(lang.if_nodes()); + kinds.extend(lang.conditional_assignment_nodes()); + kinds.extend(lang.switch_nodes()); + kinds.extend(lang.case_nodes()); + kinds.extend(lang.ternary_nodes()); + kinds.extend(lang.loop_nodes()); + kinds.extend(lang.except_nodes()); + kinds.extend(lang.try_expression_nodes()); + kinds.extend(lang.jump_nodes()); + kinds.extend(lang.return_nodes()); + kinds.extend(lang.binary_nodes()); + kinds.extend(lang.field_nodes()); + kinds.extend(lang.call_nodes()); + kinds.extend(lang.function_nodes()); + kinds.extend(lang.closure_nodes()); + kinds.extend(lang.comment_nodes()); + kinds.extend(lang.string_nodes()); + kinds.extend(lang.boolean_operator_nodes()); + kinds.extend(lang.block_nodes()); + + let unique: HashSet<_> = kinds.iter().cloned().collect(); + assert_eq!(unique.len(), kinds.len()); + } #[test] fn field_identifier_read() { From 05c65b626c9ac11c1ffe23c0df3737aee32d081e Mon Sep 17 00:00:00 2001 From: Noah Davis <11672+noahd1@users.noreply.github.com> Date: Wed, 8 Jan 2025 11:30:42 -0800 Subject: [PATCH 53/53] qlty fmt --- qlty-analysis/src/lang/csharp.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qlty-analysis/src/lang/csharp.rs b/qlty-analysis/src/lang/csharp.rs index d16bec251..b4389a3d8 100644 --- a/qlty-analysis/src/lang/csharp.rs +++ b/qlty-analysis/src/lang/csharp.rs @@ -256,8 +256,8 @@ fn get_node_source_or_default(node: Option, source_file: &File) -> String #[cfg(test)] mod test { use super::*; - use tree_sitter::Tree; use std::collections::HashSet; + use tree_sitter::Tree; #[test] fn mutually_exclusive() {