[componentkit] Compute Cyclomatic Complexity

Reviewed By: dulmarod

Differential Revision: D4203455

fbshipit-source-id: 9b19c25
master
Ryan Rhee 8 years ago committed by Facebook Github Bot
parent 7a5e53262a
commit 28b741e62c

@ -42,6 +42,7 @@ let class_cast_exception = "CLASS_CAST_EXCEPTION"
let comparing_floats_for_equality = "COMPARING_FLOAT_FOR_EQUALITY" let comparing_floats_for_equality = "COMPARING_FLOAT_FOR_EQUALITY"
let condition_is_assignment = "CONDITION_IS_ASSIGNMENT" let condition_is_assignment = "CONDITION_IS_ASSIGNMENT"
let component_factory_function = "COMPONENT_FACTORY_FUNCTION" let component_factory_function = "COMPONENT_FACTORY_FUNCTION"
let component_file_cyclomatic_complexity = "COMPONENT_FILE_CYCLOMATIC_COMPLEXITY"
let component_file_line_count = "COMPONENT_FILE_LINE_COUNT" let component_file_line_count = "COMPONENT_FILE_LINE_COUNT"
let component_initializer_with_side_effects = "COMPONENT_INITIALIZER_WITH_SIDE_EFFECTS" let component_initializer_with_side_effects = "COMPONENT_INITIALIZER_WITH_SIDE_EFFECTS"
let component_with_multiple_factory_methods = "COMPONENT_WITH_MULTIPLE_FACTORY_METHODS" let component_with_multiple_factory_methods = "COMPONENT_WITH_MULTIPLE_FACTORY_METHODS"

@ -42,6 +42,7 @@ val condition_always_false : t
val condition_always_true : t val condition_always_true : t
val context_leak : t val context_leak : t
val component_factory_function : t val component_factory_function : t
val component_file_cyclomatic_complexity : t
val component_file_line_count : t val component_file_line_count : t
val component_initializer_with_side_effects : t val component_initializer_with_side_effects : t
val component_with_multiple_factory_methods : t val component_with_multiple_factory_methods : t

@ -329,3 +329,42 @@ let component_file_line_count_info (context: CLintersContext.context) dec =
} }
) (IList.range 1 line_count) ) (IList.range 1 line_count)
| _ -> [] | _ -> []
(** Computes a component file's cyclomatic complexity.
Somewhat borrowed from
https://github.com/oclint/oclint/blob/5889b5ec168185513ba69ce83821ea1cc8e63fbe
/oclint-metrics/lib/CyclomaticComplexityMetric.cpp *)
let component_file_cyclomatic_complexity_info (context: CLintersContext.context) an =
let is_cyclo_stmt stmt = match stmt with
| Clang_ast_t.IfStmt _
| Clang_ast_t.ForStmt _
| Clang_ast_t.ObjCForCollectionStmt _
| Clang_ast_t.CXXForRangeStmt _
| Clang_ast_t.WhileStmt _
| Clang_ast_t.DoStmt _
| Clang_ast_t.CaseStmt _
| Clang_ast_t.ObjCAtCatchStmt _
| Clang_ast_t.CXXCatchStmt _
| Clang_ast_t.ConditionalOperator _ -> true
| Clang_ast_t.BinaryOperator (_, _, _, boi) ->
IList.mem (=) boi.Clang_ast_t.boi_kind [`LAnd; `LOr]
| _ -> false in
let cyclo_loc_opt an = match an with
| CTL.Stmt stmt when (Config.compute_analytics
&& is_cyclo_stmt stmt
&& is_ck_context context an) ->
Some (CFrontend_checkers.location_from_stmt context stmt)
| CTL.Decl (Clang_ast_t.TranslationUnitDecl _ as d)
when Config.compute_analytics && context.is_ck_translation_unit ->
Some (CFrontend_checkers.location_from_decl context d)
| _ -> None in
match cyclo_loc_opt an with
| Some loc ->
CTL.True, Some {
CIssue.issue = CIssue.Component_file_cyclomatic_complexity;
CIssue.description = "Cyclomatic Complexity Incremental Marker";
CIssue.suggestion = None;
CIssue.loc = loc
}
| _ -> CTL.False, None

@ -31,3 +31,6 @@ val component_initializer_with_side_effects_advice :
val component_file_line_count_info : val component_file_line_count_info :
CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc list CLintersContext.context -> Clang_ast_t.decl -> CIssue.issue_desc list
val component_file_cyclomatic_complexity_info :
CLintersContext.context -> CTL.ast_node -> CTL.t * CIssue.issue_desc option

@ -135,6 +135,7 @@ let do_frontend_checks trans_unit_ctx ast =
let context = let context =
context_with_ck_set (CLintersContext.empty trans_unit_ctx) decl_list in context_with_ck_set (CLintersContext.empty trans_unit_ctx) decl_list in
ignore (CFrontend_errors.run_translation_unit_checker context ast); ignore (CFrontend_errors.run_translation_unit_checker context ast);
ignore (CFrontend_errors.run_frontend_checkers_on_an context (CTL.Decl ast));
let is_decl_allowed decl = let is_decl_allowed decl =
let decl_info = Clang_ast_proj.get_decl_tuple decl in let decl_info = Clang_ast_proj.get_decl_tuple decl in
CLocation.should_do_frontend_check trans_unit_ctx decl_info.Clang_ast_t.di_source_range in CLocation.should_do_frontend_check trans_unit_ctx decl_info.Clang_ast_t.di_source_range in

@ -19,12 +19,14 @@ let decl_checkers_list = [CFrontend_checkers.ctl_strong_delegate_warning;
ComponentKit.component_with_unconventional_superclass_advice; ComponentKit.component_with_unconventional_superclass_advice;
ComponentKit.mutable_local_vars_advice; ComponentKit.mutable_local_vars_advice;
ComponentKit.component_factory_function_advice; ComponentKit.component_factory_function_advice;
ComponentKit.component_file_cyclomatic_complexity_info;
ComponentKit.component_with_multiple_factory_methods_advice;] ComponentKit.component_with_multiple_factory_methods_advice;]
(* List of checkers on ivar access *) (* List of checkers on ivar access *)
let stmt_checkers_list = [CFrontend_checkers.ctl_direct_atomic_property_access_warning; let stmt_checkers_list = [CFrontend_checkers.ctl_direct_atomic_property_access_warning;
CFrontend_checkers.ctl_captured_cxx_ref_in_objc_block_warning; CFrontend_checkers.ctl_captured_cxx_ref_in_objc_block_warning;
CFrontend_checkers.ctl_bad_pointer_comparison_warning; CFrontend_checkers.ctl_bad_pointer_comparison_warning;
ComponentKit.component_file_cyclomatic_complexity_info;
ComponentKit.component_initializer_with_side_effects_advice;] ComponentKit.component_initializer_with_side_effects_advice;]
(* List of checkers on translation unit that potentially output multiple issues *) (* List of checkers on translation unit that potentially output multiple issues *)

@ -11,6 +11,7 @@ type issue =
| Assign_pointer_warning | Assign_pointer_warning
| Bad_pointer_comparison | Bad_pointer_comparison
| Component_factory_function | Component_factory_function
| Component_file_cyclomatic_complexity
| Component_file_line_count | Component_file_line_count
| Component_initializer_with_side_effects | Component_initializer_with_side_effects
| Component_with_multiple_factory_methods | Component_with_multiple_factory_methods
@ -31,6 +32,8 @@ let to_string issue =
Localise.bad_pointer_comparison Localise.bad_pointer_comparison
| Component_factory_function -> | Component_factory_function ->
Localise.component_factory_function Localise.component_factory_function
| Component_file_cyclomatic_complexity ->
Localise.component_file_cyclomatic_complexity
| Component_file_line_count -> | Component_file_line_count ->
Localise.component_file_line_count Localise.component_file_line_count
| Component_initializer_with_side_effects -> | Component_initializer_with_side_effects ->
@ -67,6 +70,7 @@ let severity_of_issue issue =
| Component_with_multiple_factory_methods | Component_with_multiple_factory_methods
| Component_with_unconventional_superclass | Component_with_unconventional_superclass
| Mutable_local_variable_in_component_file -> Exceptions.Kadvice | Mutable_local_variable_in_component_file -> Exceptions.Kadvice
| Component_file_cyclomatic_complexity
| Component_file_line_count -> Exceptions.Kinfo | Component_file_line_count -> Exceptions.Kinfo

@ -11,6 +11,7 @@ type issue =
| Assign_pointer_warning | Assign_pointer_warning
| Bad_pointer_comparison | Bad_pointer_comparison
| Component_factory_function | Component_factory_function
| Component_file_cyclomatic_complexity
| Component_file_line_count | Component_file_line_count
| Component_initializer_with_side_effects | Component_initializer_with_side_effects
| Component_with_multiple_factory_methods | Component_with_multiple_factory_methods

@ -12,4 +12,13 @@
@interface SomeClass : CKCompositeComponent @interface SomeClass : CKCompositeComponent
@end @end
@implementation SomeClass @implementation SomeClass
+ (instancetype) new {
if (1 == 3) {
return nil;
} else if (2 == 4) {
return nil;
} else {
return nil;
}
}
@end @end

@ -1,4 +1,64 @@
[ [
{
"bug_type": "COMPONENT_FILE_CYCLOMATIC_COMPLEXITY",
"file": "TestComponentKitAnalytics.mm",
"procedure": "Linters_dummy_method"
},
{
"bug_type": "COMPONENT_FILE_CYCLOMATIC_COMPLEXITY",
"file": "TestComponentKitAnalytics.mm",
"procedure": "SomeClass_new"
},
{
"bug_type": "COMPONENT_FILE_CYCLOMATIC_COMPLEXITY",
"file": "TestComponentKitAnalytics.mm",
"procedure": "SomeClass_new"
},
{
"bug_type": "COMPONENT_FILE_LINE_COUNT",
"file": "TestComponentKitAnalytics.mm",
"procedure": "Linters_dummy_method"
},
{
"bug_type": "COMPONENT_FILE_LINE_COUNT",
"file": "TestComponentKitAnalytics.mm",
"procedure": "Linters_dummy_method"
},
{
"bug_type": "COMPONENT_FILE_LINE_COUNT",
"file": "TestComponentKitAnalytics.mm",
"procedure": "Linters_dummy_method"
},
{
"bug_type": "COMPONENT_FILE_LINE_COUNT",
"file": "TestComponentKitAnalytics.mm",
"procedure": "Linters_dummy_method"
},
{
"bug_type": "COMPONENT_FILE_LINE_COUNT",
"file": "TestComponentKitAnalytics.mm",
"procedure": "Linters_dummy_method"
},
{
"bug_type": "COMPONENT_FILE_LINE_COUNT",
"file": "TestComponentKitAnalytics.mm",
"procedure": "Linters_dummy_method"
},
{
"bug_type": "COMPONENT_FILE_LINE_COUNT",
"file": "TestComponentKitAnalytics.mm",
"procedure": "Linters_dummy_method"
},
{
"bug_type": "COMPONENT_FILE_LINE_COUNT",
"file": "TestComponentKitAnalytics.mm",
"procedure": "Linters_dummy_method"
},
{
"bug_type": "COMPONENT_FILE_LINE_COUNT",
"file": "TestComponentKitAnalytics.mm",
"procedure": "Linters_dummy_method"
},
{ {
"bug_type": "COMPONENT_FILE_LINE_COUNT", "bug_type": "COMPONENT_FILE_LINE_COUNT",
"file": "TestComponentKitAnalytics.mm", "file": "TestComponentKitAnalytics.mm",

Loading…
Cancel
Save