1use serde::ser::{SerializeStruct, Serializer};
2use serde::Serialize;
3use std::fmt;
4
5use crate::checker::Checker;
6use crate::node::Node;
7use crate::*;
8
9#[derive(Debug, Clone)]
22pub struct Stats {
23 assignments: f64,
24 assignments_sum: f64,
25 assignments_min: f64,
26 assignments_max: f64,
27 branches: f64,
28 branches_sum: f64,
29 branches_min: f64,
30 branches_max: f64,
31 conditions: f64,
32 conditions_sum: f64,
33 conditions_min: f64,
34 conditions_max: f64,
35 space_count: usize,
36 declaration: Vec<DeclKind>,
37}
38
39#[derive(Debug, Clone)]
40pub enum DeclKind {
41 Var,
42 Const,
43}
44
45impl Default for Stats {
46 fn default() -> Self {
47 Self {
48 assignments: 0.,
49 assignments_sum: 0.,
50 assignments_min: f64::MAX,
51 assignments_max: 0.,
52 branches: 0.,
53 branches_sum: 0.,
54 branches_min: f64::MAX,
55 branches_max: 0.,
56 conditions: 0.,
57 conditions_sum: 0.,
58 conditions_min: f64::MAX,
59 conditions_max: 0.,
60 space_count: 1,
61 declaration: Vec::new(),
62 }
63 }
64}
65
66impl Serialize for Stats {
67 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
68 where
69 S: Serializer,
70 {
71 let mut st = serializer.serialize_struct("abc", 13)?;
72 st.serialize_field("assignments", &self.assignments_sum())?;
73 st.serialize_field("branches", &self.branches_sum())?;
74 st.serialize_field("conditions", &self.conditions_sum())?;
75 st.serialize_field("magnitude", &self.magnitude_sum())?;
76 st.serialize_field("assignments_average", &self.assignments_average())?;
77 st.serialize_field("branches_average", &self.branches_average())?;
78 st.serialize_field("conditions_average", &self.conditions_average())?;
79 st.serialize_field("assignments_min", &self.assignments_min())?;
80 st.serialize_field("assignments_max", &self.assignments_max())?;
81 st.serialize_field("branches_min", &self.branches_min())?;
82 st.serialize_field("branches_max", &self.branches_max())?;
83 st.serialize_field("conditions_min", &self.conditions_min())?;
84 st.serialize_field("conditions_max", &self.conditions_max())?;
85 st.end()
86 }
87}
88
89impl fmt::Display for Stats {
90 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
91 write!(
92 f,
93 "assignments: {}, branches: {}, conditions: {}, magnitude: {}, \
94 assignments_average: {}, branches_average: {}, conditions_average: {}, \
95 assignments_min: {}, assignments_max: {}, \
96 branches_min: {}, branches_max: {}, \
97 conditions_min: {}, conditions_max: {}",
98 self.assignments_sum(),
99 self.branches_sum(),
100 self.conditions_sum(),
101 self.magnitude_sum(),
102 self.assignments_average(),
103 self.branches_average(),
104 self.conditions_average(),
105 self.assignments_min(),
106 self.assignments_max(),
107 self.branches_min(),
108 self.branches_max(),
109 self.conditions_min(),
110 self.conditions_max()
111 )
112 }
113}
114
115impl Stats {
116 pub fn merge(&mut self, other: &Stats) {
118 self.assignments_min = self.assignments_min.min(other.assignments_min);
120 self.assignments_max = self.assignments_max.max(other.assignments_max);
121 self.branches_min = self.branches_min.min(other.branches_min);
122 self.branches_max = self.branches_max.max(other.branches_max);
123 self.conditions_min = self.conditions_min.min(other.conditions_min);
124 self.conditions_max = self.conditions_max.max(other.conditions_max);
125
126 self.assignments_sum += other.assignments_sum;
127 self.branches_sum += other.branches_sum;
128 self.conditions_sum += other.conditions_sum;
129
130 self.space_count += other.space_count;
131 }
132
133 pub fn assignments(&self) -> f64 {
135 self.assignments
136 }
137
138 pub fn assignments_sum(&self) -> f64 {
140 self.assignments_sum
141 }
142
143 pub fn assignments_average(&self) -> f64 {
148 self.assignments_sum() / self.space_count as f64
149 }
150
151 pub fn assignments_min(&self) -> f64 {
153 self.assignments_min
154 }
155
156 pub fn assignments_max(&self) -> f64 {
158 self.assignments_max
159 }
160
161 pub fn branches(&self) -> f64 {
163 self.branches
164 }
165
166 pub fn branches_sum(&self) -> f64 {
168 self.branches_sum
169 }
170
171 pub fn branches_average(&self) -> f64 {
176 self.branches_sum() / self.space_count as f64
177 }
178
179 pub fn branches_min(&self) -> f64 {
181 self.branches_min
182 }
183
184 pub fn branches_max(&self) -> f64 {
186 self.branches_max
187 }
188
189 pub fn conditions(&self) -> f64 {
191 self.conditions
192 }
193
194 pub fn conditions_sum(&self) -> f64 {
196 self.conditions_sum
197 }
198
199 pub fn conditions_average(&self) -> f64 {
204 self.conditions_sum() / self.space_count as f64
205 }
206
207 pub fn conditions_min(&self) -> f64 {
209 self.conditions_min
210 }
211
212 pub fn conditions_max(&self) -> f64 {
214 self.conditions_max
215 }
216
217 pub fn magnitude(&self) -> f64 {
219 (self.assignments.powi(2) + self.branches.powi(2) + self.conditions.powi(2)).sqrt()
220 }
221
222 pub fn magnitude_sum(&self) -> f64 {
224 (self.assignments_sum.powi(2) + self.branches_sum.powi(2) + self.conditions_sum.powi(2))
225 .sqrt()
226 }
227
228 #[inline(always)]
229 pub(crate) fn compute_sum(&mut self) {
230 self.assignments_sum += self.assignments;
231 self.branches_sum += self.branches;
232 self.conditions_sum += self.conditions;
233 }
234
235 #[inline(always)]
236 pub(crate) fn compute_minmax(&mut self) {
237 self.assignments_min = self.assignments_min.min(self.assignments);
238 self.assignments_max = self.assignments_max.max(self.assignments);
239 self.branches_min = self.branches_min.min(self.branches);
240 self.branches_max = self.branches_max.max(self.branches);
241 self.conditions_min = self.conditions_min.min(self.conditions);
242 self.conditions_max = self.conditions_max.max(self.conditions);
243 self.compute_sum();
244 }
245}
246
247#[doc(hidden)]
248pub trait Abc
249where
250 Self: Checker,
251{
252 fn compute(_node: &Node, _stats: &mut Stats) {}
253}
254
255fn java_inspect_container(container_node: &Node, conditions: &mut f64) {
258 use Java::*;
259
260 let mut node = container_node.object();
261 let mut node_kind = node.kind_id().into();
262
263 let mut has_boolean_content = match node.parent().unwrap().kind_id().into() {
265 BinaryExpression | IfStatement | WhileStatement | DoStatement | ForStatement => true,
266 TernaryExpression => node.prev_sibling().map_or(true, |prev_node| {
267 !matches!(prev_node.kind_id().into(), QMARK | COLON)
268 }),
269 _ => false,
270 };
271
272 loop {
274 let is_parenthesised_exp = matches!(node_kind, ParenthesizedExpression);
277 let is_not_operator = matches!(node_kind, UnaryExpression)
278 && matches!(node.child(0).unwrap().kind_id().into(), BANG);
279
280 if !is_parenthesised_exp && !is_not_operator {
283 break;
284 }
285
286 if !has_boolean_content && is_not_operator {
290 has_boolean_content = true;
291 }
292
293 node = node.child(1).unwrap();
298 node_kind = node.kind_id().into();
299
300 if matches!(node_kind, MethodInvocation | Identifier | True | False) {
302 if has_boolean_content {
303 *conditions += 1.;
304 }
305 break;
306 }
307 }
308}
309
310fn java_count_unary_conditions(list_node: &Node, conditions: &mut f64) {
312 use Java::*;
313
314 let list_kind = list_node.object().kind_id().into();
315 let mut cursor = list_node.object().walk();
316
317 if cursor.goto_first_child() {
319 loop {
320 let node = cursor.node();
322 let node_kind = node.kind_id().into();
323
324 if matches!(node_kind, MethodInvocation | Identifier | True | False)
326 && matches!(list_kind, BinaryExpression)
327 && !matches!(list_kind, ArgumentList)
328 {
329 *conditions += 1.;
330 } else {
331 java_inspect_container(&Node::new(node), conditions);
333 }
334
335 if !cursor.goto_next_sibling() {
338 break;
339 }
340 }
341 }
342}
343
344impl Abc for PythonCode {}
345impl Abc for MozjsCode {}
346impl Abc for JavascriptCode {}
347impl Abc for TypescriptCode {}
348impl Abc for TsxCode {}
349impl Abc for RustCode {}
350impl Abc for CppCode {}
351impl Abc for PreprocCode {}
352impl Abc for CcommentCode {}
353
354impl Abc for JavaCode {
359 fn compute(node: &Node, stats: &mut Stats) {
360 use Java::*;
361
362 match node.object().kind_id().into() {
363 STAREQ | SLASHEQ | PERCENTEQ | DASHEQ | PLUSEQ | LTLTEQ | GTGTEQ | AMPEQ | PIPEEQ
364 | CARETEQ | GTGTGTEQ | PLUSPLUS | DASHDASH => {
365 stats.assignments += 1.;
366 }
367 FieldDeclaration | LocalVariableDeclaration => {
368 stats.declaration.push(DeclKind::Var);
369 }
370 Final => {
371 if let Some(DeclKind::Var) = stats.declaration.last() {
372 stats.declaration.push(DeclKind::Const);
373 }
374 }
375 SEMI => {
376 if let Some(DeclKind::Const | DeclKind::Var) = stats.declaration.last() {
377 stats.declaration.clear();
378 }
379 }
380 EQ => {
381 stats
383 .declaration
384 .last()
385 .map(|decl| {
386 if matches!(decl, DeclKind::Var) {
387 stats.assignments += 1.;
388 }
389 })
390 .unwrap_or_else(|| {
391 stats.assignments += 1.;
392 });
393 }
394 MethodInvocation | New => {
395 stats.branches += 1.;
396 }
397 GTEQ | LTEQ | EQEQ | BANGEQ | Else | Case | Default | QMARK | Try | Catch => {
398 stats.conditions += 1.;
399 }
400 GT | LT => {
401 if let Some(parent) = node.object().parent() {
403 if !matches!(parent.kind_id().into(), TypeArguments) {
404 stats.conditions += 1.;
405 }
406 }
407 }
408 AMPAMP | PIPEPIPE => {
410 if let Some(parent) = node.object().parent() {
411 java_count_unary_conditions(&Node::new(parent), &mut stats.conditions);
412 }
413 }
414 ArgumentList => {
416 java_count_unary_conditions(node, &mut stats.conditions);
417 }
418 VariableDeclarator | AssignmentExpression => {
420 if let Some(right_operand) = node.object().child(2) {
422 if matches!(
423 right_operand.kind_id().into(),
424 ParenthesizedExpression | UnaryExpression
425 ) {
426 java_inspect_container(&Node::new(right_operand), &mut stats.conditions);
427 }
428 }
429 }
430 IfStatement | WhileStatement => {
432 if let Some(condition) = node.object().child(1) {
434 if matches!(condition.kind_id().into(), ParenthesizedExpression) {
435 java_inspect_container(&Node::new(condition), &mut stats.conditions);
436 }
437 }
438 }
439 DoStatement => {
441 if let Some(condition) = node.object().child(3) {
443 if matches!(condition.kind_id().into(), ParenthesizedExpression) {
444 java_inspect_container(&Node::new(condition), &mut stats.conditions);
445 }
446 }
447 }
448 ForStatement => {
450 if let Some(condition) = node.object().child(3) {
454 match condition.kind_id().into() {
455 SEMI => {
456 if let Some(cond) = node.object().child(4) {
460 match cond.kind_id().into() {
461 MethodInvocation | Identifier | True | False | SEMI
462 | RPAREN => {
463 stats.conditions += 1.;
464 }
465 ParenthesizedExpression | UnaryExpression => {
466 java_inspect_container(
467 &Node::new(cond),
468 &mut stats.conditions,
469 );
470 }
471 _ => {}
472 }
473 }
474 }
475 MethodInvocation | Identifier | True | False => {
476 stats.conditions += 1.;
477 }
478 ParenthesizedExpression | UnaryExpression => {
479 java_inspect_container(&Node::new(condition), &mut stats.conditions);
480 }
481 _ => {}
482 }
483 }
484 }
485 ReturnStatement => {
487 if let Some(value) = node.object().child(1) {
489 if matches!(
490 value.kind_id().into(),
491 ParenthesizedExpression | UnaryExpression
492 ) {
493 java_inspect_container(&Node::new(value), &mut stats.conditions)
494 }
495 }
496 }
497 LambdaExpression => {
499 if let Some(value) = node.object().child(2) {
501 if matches!(
502 value.kind_id().into(),
503 ParenthesizedExpression | UnaryExpression
504 ) {
505 java_inspect_container(&Node::new(value), &mut stats.conditions)
506 }
507 }
508 }
509 TernaryExpression => {
511 if let Some(condition) = node.object().child(0) {
513 match condition.kind_id().into() {
514 MethodInvocation | Identifier | True | False => {
515 stats.conditions += 1.;
516 }
517 ParenthesizedExpression | UnaryExpression => {
518 java_inspect_container(&Node::new(condition), &mut stats.conditions);
519 }
520 _ => {}
521 }
522 }
523 if let Some(expression) = node.object().child(2) {
525 if matches!(
526 expression.kind_id().into(),
527 ParenthesizedExpression | UnaryExpression
528 ) {
529 java_inspect_container(&Node::new(expression), &mut stats.conditions);
530 }
531 }
532 if let Some(expression) = node.object().child(4) {
534 if matches!(
535 expression.kind_id().into(),
536 ParenthesizedExpression | UnaryExpression
537 ) {
538 java_inspect_container(&Node::new(expression), &mut stats.conditions);
539 }
540 }
541 }
542 _ => {}
543 }
544 }
545}
546
547#[cfg(test)]
548mod tests {
549 use std::path::PathBuf;
550
551 use super::*;
552
553 #[test]
555 fn java_constant_declarations() {
556 check_metrics!(
557 "class A {
558 private final int X1 = 0, Y1 = 0;
559 public final float PI = 3.14f;
560 final static String HELLO = \"Hello,\";
561 protected String world = \" world!\"; // +1a
562 public float e = 2.718f; // +1a
563 private int x2 = 1, y2 = 2; // +2a
564
565 void m() {
566 final int Z1 = 0, Z2 = 0, Z3 = 0;
567 final float T = 0.0f;
568 int z1 = 1, z2 = 2, z3 = 3; // +3a
569 float t = 60.0f; // +1a
570 }
571 }",
572 "foo.java",
573 JavaParser,
574 abc,
575 [
576 (assignments_sum, 8.0),
577 (branches_sum, 0.0),
578 (conditions_sum, 0.0),
579 (magnitude_sum, 8.0), (assignments_average, 2.666_666_666_666_666_6), (branches_average, 0.0),
582 (conditions_average, 0.0),
583 (assignments_min, 0.0),
584 (branches_min, 0.0),
585 (conditions_min, 0.0),
586 (assignments_max, 4.0),
587 (branches_max, 0.0),
588 (conditions_max, 0.0)
589 ]
590 );
591 }
592
593 #[test]
600 fn java_declarations_with_conditions() {
601 check_metrics!(
602 "
603 boolean a = (1 > 2); // +1a +1c
604 boolean b = 3 > 4; // +1a +1c
605 boolean c = (1 > 2) && 3 > 4; // +1a +2c
606 boolean d = b && (x > 5) || c; // +1a +3c
607 boolean e = !d; // +1a +1c
608 boolean f = ((!false)); // +1a +1c
609 boolean g = !(!(true)); // +1a +1c
610 boolean h = true; // +1a
611 boolean i = (false); // +1a
612 boolean j = (((((true))))); // +1a
613 boolean k = (((((m()))))); // +1a +1b
614 boolean l = (((((!m()))))); // +1a +1b +1c
615 boolean m = (!(!((m())))); // +1a +1b +1c
616 List<String> n = null; // +1a (< and > used for generic types are not counted as conditions)
617 ",
618 "foo.java",
619 JavaParser,
620 abc,
621 [
622 (assignments_sum, 14.0),
623 (branches_sum, 3.0),
624 (conditions_sum, 12.0),
625 (magnitude_sum, 18.681_541_692_269_406), (assignments_average, 14.0), (branches_average, 3.0),
628 (conditions_average, 12.0),
629 (assignments_min, 14.0),
630 (branches_min, 3.0),
631 (conditions_min, 12.0),
632 (assignments_max, 14.0),
633 (branches_max, 3.0),
634 (conditions_max, 12.0)
635 ]
636 );
637 }
638
639 #[test]
641 fn java_assignments_with_conditions() {
642 check_metrics!(
643 "
644 a = 2 < 1; // +1a +1c
645 b = (4 >= 3) && 2 <= 1; // +1a +2c
646 c = a || (x != 10) && b; // +1a +3c
647 d = !false; // +1a +1c
648 e = (!false); // +1a +1c
649 f = !(false); // +1a +1c
650 g = (!(((true)))); // +1a +1c
651 h = ((true)); // +1a
652 i = !m(); // +1a +1b +1c
653 j = !((m())); // +1a +1b +1c
654 k = (!(m())); // +1a +1b +1c
655 l = ((!(m()))); // +1a +1b +1c
656 m = !B.<Integer>m(2); // +1a +1b +1c
657 n = !((B.<Integer>m(4))); // +1a +1b +1c
658 ",
659 "foo.java",
660 JavaParser,
661 abc,
662 [
663 (assignments_sum, 14.0),
664 (branches_sum, 6.0),
665 (conditions_sum, 16.0),
666 (magnitude_sum, 22.090_722_034_374_522), (assignments_average, 14.0), (branches_average, 6.0),
669 (conditions_average, 16.0),
670 (assignments_min, 14.0),
671 (branches_min, 6.0),
672 (conditions_min, 16.0),
673 (assignments_max, 14.0),
674 (branches_max, 6.0),
675 (conditions_max, 16.0)
676 ]
677 );
678 }
679
680 #[test]
682 fn java_methods_arguments_with_conditions() {
683 check_metrics!(
684 "
685 m1(a); // +1b
686 m2(a, b); // +1b
687 m3(true, (false), (((true)))); // +1b
688 m3(m1(false), m1(true), m1(false)); // +4b
689 m1(!a); // +1b +1c
690 m2((((a))), (!b)); // +1b +1c
691 m3(!(a), b, !!!c); // +1b +2c
692 m3(a, !b, m2(!a, !m2(!b, !m1(!c)))); // +4b +6c
693 ",
694 "foo.java",
695 JavaParser,
696 abc,
697 [
698 (assignments_sum, 0.0),
699 (branches_sum, 14.0),
700 (conditions_sum, 10.0),
701 (magnitude_sum, 17.204_650_534_085_253), (assignments_average, 0.0), (branches_average, 14.0),
704 (conditions_average, 10.0),
705 (assignments_min, 0.0),
706 (branches_min, 14.0),
707 (conditions_min, 10.0),
708 (assignments_max, 0.0),
709 (branches_max, 14.0),
710 (conditions_max, 10.0)
711 ]
712 );
713 }
714
715 #[test]
719 fn java_if_single_conditions() {
720 check_metrics!(
721 "
722 if ( a < 0 ) {} // +1c
723 if ( ((a != 0)) ) {} // +1c
724 if ( !(a > 0) ) {} // +1c
725 if ( !(((a == 0))) ) {} // +1c
726 if ( b.m1() ) {} // +1b +1c
727 if ( !b.m1() ) {} // +1b +1c
728 if ( !!b.m2() ) {} // +1b +1c
729 if ( (!(b.m1())) ) {} // +1b +1c
730 if ( (!(!b.m1())) ) {} // +1b +1c
731 if ( ((b.m2())) ) {} // +1b +1c
732 if ( ((b.m().m1())) ) {} // +2b +1c
733 if ( c ) {} // +1c
734 if ( !c ) {} // +1c
735 if ( !!!!!!!!!!c ) {} // +1c
736 if ( (((c))) ) {} // +1c
737 if ( (((!c))) ) {} // +1c
738 if ( ((!(c))) ) {} // +1c
739 if ( true ) {} // +1c
740 if ( !true ) {} // +1c
741 if ( ((false)) ) {} // +1c
742 if ( !(!(false)) ) {} // +1c
743 if ( !!!false ) {} // +1c
744 ",
745 "foo.java",
746 JavaParser,
747 abc,
748 [
749 (assignments_sum, 0.0),
750 (branches_sum, 8.0),
751 (conditions_sum, 22.0),
752 (magnitude_sum, 23.409_399_821_439_25), (assignments_average, 0.0), (branches_average, 8.0),
755 (conditions_average, 22.0),
756 (assignments_min, 0.0),
757 (branches_min, 8.0),
758 (conditions_min, 22.0),
759 (assignments_max, 0.0),
760 (branches_max, 8.0),
761 (conditions_max, 22.0)
762 ]
763 );
764 }
765
766 #[test]
767 fn java_if_multiple_conditions() {
768 check_metrics!(
769 "
770 if ( a || b || c || d ) {} // +4c
771 if ( a || b && c && d ) {} // +4c
772 if ( x < y && a == b ) {} // +2c
773 if ( ((z < (x + y))) ) {} // +1c
774 if ( a || ((((b))) && c) ) {} // +3c
775 if ( a && ((((a == b))) && c) ) {} // +3c
776 if ( a || ((((a == b))) || ((c))) ) {} // +3c
777 if ( x < y && B.m() ) {} // +1b +2c
778 if ( x < y && !(((B.m()))) ) {} // +1b +2c
779 if ( !(x < y) && !B.m() ) {} // +1b +2c
780 if ( !!!(!!!(a)) && B.m() || // +1b +2c
781 !B.m() && (((x > 4))) ) {} // +1b +2c
782 ",
783 "foo.java",
784 JavaParser,
785 abc,
786 [
787 (assignments_sum, 0.0),
788 (branches_sum, 5.0),
789 (conditions_sum, 30.0),
790 (magnitude_sum, 30.413_812_651_491_1), (assignments_average, 0.0), (branches_average, 5.0),
793 (conditions_average, 30.0),
794 (assignments_min, 0.0),
795 (branches_min, 5.0),
796 (conditions_min, 30.0),
797 (assignments_max, 0.0),
798 (branches_max, 5.0),
799 (conditions_max, 30.0)
800 ]
801 );
802 }
803
804 #[test]
805 fn java_while_and_do_while_conditions() {
806 check_metrics!(
807 "
808 while ( (!(!(!(a)))) ) {} // +1c
809 while ( b || 1 > 2 ) {} // +2c
810 while ( x.m() && (((c))) ) {} // +1b +2c
811 do {} while ( !!!(((!!!a))) ); // +1c
812 do {} while ( a || (b && c) ); // +3c
813 do {} while ( !x.m() && 1 > 2 || !true ); // +1b +3c
814 ",
815 "foo.java",
816 JavaParser,
817 abc,
818 [
819 (assignments_sum, 0.0),
820 (branches_sum, 2.0),
821 (conditions_sum, 12.0),
822 (magnitude_sum, 12.165_525_060_596_439), (assignments_average, 0.0), (branches_average, 2.0),
825 (conditions_average, 12.0),
826 (assignments_min, 0.0),
827 (branches_min, 2.0),
828 (conditions_min, 12.0),
829 (assignments_max, 0.0),
830 (branches_max, 2.0),
831 (conditions_max, 12.0)
832 ]
833 );
834 }
835
836 #[test]
843 fn java_return_with_conditions() {
844 check_metrics!(
845 "class A {
846 boolean m1() {
847 return !(z >= 0); // +1c
848 }
849 boolean m2() {
850 return (((!x))); // +1c
851 }
852 boolean m3() {
853 return x && y; // +2c
854 }
855 boolean m4() {
856 return y || (z < 0); // +2c
857 }
858 boolean m5() {
859 return x || y ? // +3c (two unary conditions and one ?)
860 true : false;
861 }
862 }",
863 "foo.java",
864 JavaParser,
865 abc,
866 [
867 (assignments_sum, 0.0),
868 (branches_sum, 0.0),
869 (conditions_sum, 9.0),
870 (magnitude_sum, 9.0), (assignments_average, 0.0), (branches_average, 0.0),
873 (conditions_average, 1.285_714_285_714_285_8),
874 (assignments_min, 0.0),
875 (branches_min, 0.0),
876 (conditions_min, 0.0),
877 (assignments_max, 0.0),
878 (branches_max, 0.0),
879 (conditions_max, 3.0)
880 ]
881 );
882 }
883
884 #[test]
887 fn java_return_without_conditions() {
888 check_metrics!(
889 "class A {
890 boolean m1() {
891 return x;
892 }
893 boolean m2() {
894 return (x);
895 }
896 boolean m3() {
897 return y.m(); // +1b
898 }
899 boolean m4() {
900 return false;
901 }
902 void m5() {
903 return;
904 }
905 }",
906 "foo.java",
907 JavaParser,
908 abc,
909 [
910 (assignments_sum, 0.0),
911 (branches_sum, 1.0),
912 (conditions_sum, 0.0),
913 (magnitude_sum, 1.0), (assignments_average, 0.0), (branches_average, 0.142_857_142_857_142_85),
916 (conditions_average, 0.0),
917 (assignments_min, 0.0),
918 (branches_min, 0.0),
919 (conditions_min, 0.0),
920 (assignments_max, 0.0),
921 (branches_max, 1.0),
922 (conditions_max, 0.0)
923 ]
924 );
925 }
926
927 #[test]
930 fn java_lambda_expressions_return_with_conditions() {
931 check_metrics!(
932 "
933 Predicate<Boolean> p1 = a -> a; // +1a
934 Predicate<Boolean> p2 = b -> true; // +1a
935 Predicate<Boolean> p3 = c -> m(); // +1a
936 Predicate<Integer> p4 = d -> d > 10; // +1a +1c
937 Predicate<Boolean> p5 = (e) -> !e; // +1a +1c
938 Predicate<Boolean> p6 = (f) -> !((!f)); // +1a +1c
939 Predicate<Boolean> p7 = (g) -> !g && true; // +1a +2c
940 BiPredicate<Boolean, Boolean> bp1 = (h, i) -> !h && !i; // +1a +2c
941 BiPredicate<Boolean, Boolean> bp2 = (j, k) -> {
942 return j || k; // +1a +2c
943 };
944 ",
945 "foo.java",
946 JavaParser,
947 abc,
948 [
949 (assignments_sum, 9.0),
950 (branches_sum, 1.0),
951 (conditions_sum, 9.0),
952 (magnitude_sum, 12.767_145_334_803_704), (assignments_average, 9.0), (branches_average, 1.0),
955 (conditions_average, 9.0),
956 (assignments_min, 9.0),
957 (branches_min, 1.0),
958 (conditions_min, 9.0),
959 (assignments_max, 9.0),
960 (branches_max, 1.0),
961 (conditions_max, 9.0)
962 ]
963 );
964 }
965
966 #[test]
967 fn java_for_with_variable_declaration() {
968 check_metrics!(
969 "
970 for ( int i1 = 0; !(!(!(!a))); i1++ ) {} // +2a +1c
971 for ( int i2 = 0; !B.m(); i2++ ) {} // +2a +1b +1c
972 for ( int i3 = 0; a || false; i3++ ) {} // +2a +2c
973 for ( int i4 = 0; a && B.m() ? true : false; i4++ ) {} // +2a +1b +3c
974 for ( int i5 = 0; true; i5++ ) {} // +2a +1c
975 ",
976 "foo.java",
977 JavaParser,
978 abc,
979 [
980 (assignments_sum, 10.0),
981 (branches_sum, 2.0),
982 (conditions_sum, 8.0),
983 (magnitude_sum, 12.961_481_396_815_72), (assignments_average, 10.0), (branches_average, 2.0),
986 (conditions_average, 8.0),
987 (assignments_min, 10.0),
988 (branches_min, 2.0),
989 (conditions_min, 8.0),
990 (assignments_max, 10.0),
991 (branches_max, 2.0),
992 (conditions_max, 8.0)
993 ]
994 );
995 }
996
997 #[test]
998 fn java_for_without_variable_declaration() {
999 check_metrics!(
1000 "class A{
1001 void m1() {
1002 for (i = 0; x < y; i++) {} // +2a +1c
1003 for (i = 0; ((x < y)); i++) {} // +2a +1c
1004 for (i = 0; !(!(x < y)); i++) {} // +2a +1c
1005 for (i = 0; true; i++) {} // +2a +1c
1006 }
1007 void m2() {
1008 for ( ; true; ) {} // +1c
1009 }
1010 void m3() {
1011 for ( ; ; ) {} // +1c (one implicit unary condition set to true)
1012 }
1013 }",
1014 "foo.java",
1015 JavaParser,
1016 abc,
1017 [
1018 (assignments_sum, 8.0),
1019 (branches_sum, 0.0),
1020 (conditions_sum, 6.0),
1021 (magnitude_sum, 10.0), (assignments_average, 1.6), (branches_average, 0.0),
1024 (conditions_average, 1.2),
1025 (assignments_min, 0.0),
1026 (branches_min, 0.0),
1027 (conditions_min, 0.0),
1028 (assignments_max, 8.0),
1029 (branches_max, 0.0),
1030 (conditions_max, 4.0)
1031 ]
1032 );
1033 }
1034
1035 #[test]
1038 fn java_ternary_conditions() {
1039 check_metrics!(
1040 "
1041 a = true; // +1a
1042 b = a ? true : false; // +1a +2c
1043 c = ((((a)))) ? !false : !b; // +1a +4c
1044 d = !this.m() ? !!a : (false); // +1a +1b +3c
1045 e = !(a) && b ? ((c)) : !d; // +1a +4c
1046 if ( this.m() ? a : !this.m() ) {} // +2b +3c
1047 if ( x > 0 ? !(false) : this.m() ) {} // +1b +3c
1048 if ( x > 0 && x != 3 ? !(a) : (!(b)) ) {} // +5c
1049 ",
1050 "foo.java",
1051 JavaParser,
1052 abc,
1053 [
1054 (assignments_sum, 5.0),
1055 (branches_sum, 4.0),
1056 (conditions_sum, 24.0),
1057 (magnitude_sum, 24.839_484_696_748_443), (assignments_average, 5.0), (branches_average, 4.0),
1060 (conditions_average, 24.0),
1061 (assignments_min, 5.0),
1062 (branches_min, 4.0),
1063 (conditions_min, 24.0),
1064 (assignments_max, 5.0),
1065 (branches_max, 4.0),
1066 (conditions_max, 24.0)
1067 ]
1068 );
1069 }
1070}