[componentkit] Compute line count for main file

Reviewed By: dulmarod

Differential Revision: D4160362

fbshipit-source-id: 649ab49
master
Ryan Rhee 8 years ago committed by Facebook Github Bot
parent 31e6f19ab2
commit ccb51912e1

@ -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_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"
let component_with_unconventional_superclass = "COMPONENT_WITH_UNCONVENTIONAL_SUPERCLASS" let component_with_unconventional_superclass = "COMPONENT_WITH_UNCONVENTIONAL_SUPERCLASS"

@ -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_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
val component_with_unconventional_superclass : t val component_with_unconventional_superclass : t

@ -17,6 +17,11 @@ module L = Logging
(** {2 Source Files} *) (** {2 Source Files} *)
let count_newlines (path: string): int =
let open Core.Std in
let f file = In_channel.fold_lines file ~init:0 ~f:(fun i _ -> i + 1) in
In_channel.with_file path ~f
type source_file = type source_file =
| Absolute of string | Absolute of string
| Relative of string | Relative of string
@ -74,6 +79,10 @@ let source_file_to_abs_path fname =
| Relative path -> Filename.concat Config.project_root path | Relative path -> Filename.concat Config.project_root path
| Absolute path -> path | Absolute path -> path
let source_file_line_count source_file =
let abs_path = source_file_to_abs_path source_file in
count_newlines abs_path
let inode_equal sf1 sf2 = let inode_equal sf1 sf2 =
let stat1 = Unix.stat (source_file_to_abs_path sf1) in let stat1 = Unix.stat (source_file_to_abs_path sf1) in
let stat2 = Unix.stat (source_file_to_abs_path sf2) in let stat2 = Unix.stat (source_file_to_abs_path sf2) in

@ -89,6 +89,9 @@ module SourceFileSet : Set.S with type elt = source_file
(** comparison of source files *) (** comparison of source files *)
val source_file_compare : source_file -> source_file -> int val source_file_compare : source_file -> source_file -> int
(** compute line count of a source file *)
val source_file_line_count : source_file -> int
(** equality of source files *) (** equality of source files *)
val source_file_equal : source_file -> source_file -> bool val source_file_equal : source_file -> source_file -> bool

@ -266,3 +266,8 @@ let mem_assoc equal a l =
(** Like List.assoc but without builtin equality *) (** Like List.assoc but without builtin equality *)
let assoc equal a l = let assoc equal a l =
snd (find (fun x -> equal a (fst x)) l) snd (find (fun x -> equal a (fst x)) l)
let range i j =
let rec aux n acc =
if n < i then acc else aux (n-1) (n :: acc) in
aux j []

@ -119,3 +119,8 @@ val find_map_opt : ('a -> 'b option) -> 'a list -> 'b option
val find_mapi_opt : (int -> 'a -> 'b option) -> 'a list -> 'b option val find_mapi_opt : (int -> 'a -> 'b option) -> 'a list -> 'b option
val to_string : ('a -> string) -> 'a list -> string val to_string : ('a -> string) -> 'a list -> string
(** Creates an list, inclusive. E.g. `range 2 4` -> [2, 3, 4].
Not tail-recursive.*)
val range : int -> int -> int list

@ -305,3 +305,27 @@ let component_initializer_with_side_effects_advice
| CTL.Stmt (CallExpr (_, called_func_stmt :: _, _)) -> | CTL.Stmt (CallExpr (_, called_func_stmt :: _, _)) ->
_component_initializer_with_side_effects_advice context called_func_stmt _component_initializer_with_side_effects_advice context called_func_stmt
| _ -> CTL.False, None (* only to be called in CallExpr *) | _ -> CTL.False, None (* only to be called in CallExpr *)
(** Returns one issue per line of code, with the column set to 0.
This still needs to be in infer b/c only files that have a valid component
kit class impl should be analyzed. *)
let component_file_line_count_info (context: CLintersContext.context) dec =
let condition = Config.compute_analytics && context.is_ck_translation_unit in
match dec with
| Clang_ast_t.TranslationUnitDecl _ when condition ->
let source_file =
context.translation_unit_context.CFrontend_config.source_file in
let line_count = DB.source_file_line_count source_file in
IList.map (fun i -> {
CIssue.issue = CIssue.Component_file_line_count;
CIssue.description = "Line count analytics";
CIssue.suggestion = None;
CIssue.loc = {
Location.line = i;
Location.col = 0;
Location.file = source_file
}
}
) (IList.range 1 line_count)
| _ -> []

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

@ -134,6 +134,7 @@ let do_frontend_checks trans_unit_ctx ast =
| Clang_ast_t.TranslationUnitDecl(_, decl_list, _, _) -> | Clang_ast_t.TranslationUnitDecl(_, decl_list, _, _) ->
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);
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

@ -27,6 +27,9 @@ let stmt_checkers_list = [CFrontend_checkers.ctl_direct_atomic_property_access_
CFrontend_checkers.ctl_bad_pointer_comparison_warning; CFrontend_checkers.ctl_bad_pointer_comparison_warning;
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 *)
let translation_unit_checkers_list = [ComponentKit.component_file_line_count_info;]
@ -76,3 +79,12 @@ let run_frontend_checkers_on_an (context: CLintersContext.context) an =
| _ -> context in | _ -> context in
invoke_set_of_checkers_an an context'; invoke_set_of_checkers_an an context';
context' context'
let run_translation_unit_checker (context: CLintersContext.context) dec =
IList.iter (fun checker ->
let issue_desc_list = checker context dec in
IList.iter (fun issue_desc ->
let key = Ast_utils.generate_key_decl dec in
log_frontend_issue context.CLintersContext.translation_unit_context
context.CLintersContext.current_method key issue_desc
) issue_desc_list) translation_unit_checkers_list

@ -15,3 +15,9 @@ open! Utils
(* Run frontend checkers on an AST node *) (* Run frontend checkers on an AST node *)
val run_frontend_checkers_on_an : val run_frontend_checkers_on_an :
CLintersContext.context -> CTL.ast_node -> CLintersContext.context CLintersContext.context -> CTL.ast_node -> CLintersContext.context
(** Same as run_frontend_checkers_on_an except special-cased on the translation
unit. Translation unit level checkers may return multiple issues, which is
why special-casing is necessary here. *)
val run_translation_unit_checker :
CLintersContext.context -> Clang_ast_t.decl -> unit

@ -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_line_count
| Component_initializer_with_side_effects | Component_initializer_with_side_effects
| Component_with_multiple_factory_methods | Component_with_multiple_factory_methods
| Component_with_unconventional_superclass | Component_with_unconventional_superclass
@ -30,6 +31,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_line_count ->
Localise.component_file_line_count
| Component_initializer_with_side_effects -> | Component_initializer_with_side_effects ->
Localise.component_initializer_with_side_effects Localise.component_initializer_with_side_effects
| Component_with_multiple_factory_methods -> | Component_with_multiple_factory_methods ->
@ -64,6 +67,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_line_count -> Exceptions.Kinfo
type issue_desc = { type issue_desc = {

@ -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_line_count
| Component_initializer_with_side_effects | Component_initializer_with_side_effects
| Component_with_multiple_factory_methods | Component_with_multiple_factory_methods
| Component_with_unconventional_superclass | Component_with_unconventional_superclass

@ -1 +1,77 @@
[] [
{
"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",
"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"
}
]
Loading…
Cancel
Save