|
|
|
(*
|
|
|
|
* Copyright (c) 2016 - present Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD style license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*)
|
|
|
|
|
|
|
|
open! Utils
|
|
|
|
open CFrontend_utils
|
|
|
|
|
|
|
|
let rec do_frontend_checks_stmt (context:CLintersContext.context) stmt =
|
|
|
|
let open Clang_ast_t in
|
|
|
|
let context' = CFrontend_errors.run_frontend_checkers_on_stmt context stmt in
|
|
|
|
let do_all_checks_on_stmts stmt =
|
|
|
|
(match stmt with
|
|
|
|
| DeclStmt (_, _, decl_list) ->
|
|
|
|
IList.iter (do_frontend_checks_decl context') decl_list
|
|
|
|
| BlockExpr (_, _, _, decl) ->
|
|
|
|
IList.iter (do_frontend_checks_decl context') [decl]
|
|
|
|
| _ -> ());
|
|
|
|
do_frontend_checks_stmt context' stmt in
|
|
|
|
let stmts = Ast_utils.get_stmts_from_stmt stmt in
|
|
|
|
IList.iter (do_all_checks_on_stmts) stmts
|
|
|
|
|
|
|
|
and do_frontend_checks_decl context decl =
|
|
|
|
let open Clang_ast_t in
|
|
|
|
let info = Clang_ast_proj.get_decl_tuple decl in
|
|
|
|
CLocation.update_curr_file context.CLintersContext.translation_unit_context info;
|
|
|
|
let context' =
|
|
|
|
(match decl with
|
|
|
|
| FunctionDecl(_, _, _, fdi)
|
|
|
|
| CXXMethodDecl (_, _, _, fdi, _)
|
|
|
|
| CXXConstructorDecl (_, _, _, fdi, _)
|
|
|
|
| CXXConversionDecl (_, _, _, fdi, _)
|
|
|
|
| CXXDestructorDecl (_, _, _, fdi, _) ->
|
|
|
|
let context' = {context with CLintersContext.current_method = Some decl } in
|
|
|
|
(match fdi.Clang_ast_t.fdi_body with
|
|
|
|
| Some stmt ->
|
|
|
|
do_frontend_checks_stmt context' stmt
|
|
|
|
| None -> ());
|
|
|
|
context'
|
|
|
|
| ObjCMethodDecl (_, _, mdi) ->
|
|
|
|
let context' = {context with CLintersContext.current_method = Some decl } in
|
|
|
|
(match mdi.Clang_ast_t.omdi_body with
|
|
|
|
| Some stmt ->
|
|
|
|
do_frontend_checks_stmt context' stmt
|
|
|
|
| None -> ());
|
|
|
|
context'
|
|
|
|
| BlockDecl (_, block_decl_info) ->
|
|
|
|
let context' = {context with CLintersContext.current_method = Some decl } in
|
|
|
|
(match block_decl_info.Clang_ast_t.bdi_body with
|
|
|
|
| Some stmt ->
|
|
|
|
do_frontend_checks_stmt context' stmt
|
|
|
|
| None -> ());
|
|
|
|
context'
|
|
|
|
| _ -> context) in
|
|
|
|
let context'' = CFrontend_errors.run_frontend_checkers_on_decl context' decl in
|
|
|
|
let context_with_orig_current_method =
|
|
|
|
{context'' with CLintersContext.current_method = context.CLintersContext.current_method } in
|
|
|
|
match Clang_ast_proj.get_decl_context_tuple decl with
|
|
|
|
| Some (decls, _) -> IList.iter (do_frontend_checks_decl context_with_orig_current_method) decls
|
|
|
|
| None -> ()
|
|
|
|
|
|
|
|
let context_with_ck_set context decl_list =
|
|
|
|
let is_ck = context.CLintersContext.is_ck_translation_unit
|
|
|
|
|| ComponentKit.contains_ck_impl decl_list in
|
|
|
|
if is_ck then
|
|
|
|
{ context with CLintersContext.is_ck_translation_unit = true }
|
|
|
|
else
|
|
|
|
context
|
|
|
|
|
|
|
|
let store_issues source_file =
|
|
|
|
let abbrev_source_file = DB.source_file_encoding source_file in
|
|
|
|
let lint_issues_dir = Config.results_dir // Config.lint_issues_dir_name in
|
|
|
|
create_dir lint_issues_dir;
|
|
|
|
let lint_issues_file =
|
|
|
|
DB.filename_from_string (Filename.concat lint_issues_dir (abbrev_source_file ^ ".issue")) in
|
|
|
|
LintIssues.store_issues lint_issues_file !LintIssues.errLogMap
|
|
|
|
|
|
|
|
let do_frontend_checks trans_unit_ctx ast =
|
|
|
|
try
|
|
|
|
let source_file = trans_unit_ctx.CFrontend_config.source_file in
|
|
|
|
Logging.out "Start linting file %s@\n" (DB.source_file_to_string source_file);
|
|
|
|
match ast with
|
|
|
|
| Clang_ast_t.TranslationUnitDecl(_, decl_list, _, _) ->
|
|
|
|
let context =
|
|
|
|
context_with_ck_set (CLintersContext.empty trans_unit_ctx) decl_list in
|
|
|
|
let is_decl_allowed decl =
|
|
|
|
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
|
|
|
|
let allowed_decls = IList.filter is_decl_allowed decl_list in
|
|
|
|
IList.iter (do_frontend_checks_decl context) allowed_decls;
|
|
|
|
if (LintIssues.exists_issues ()) then
|
|
|
|
store_issues source_file;
|
|
|
|
Logging.out "End linting file %s@\n" (DB.source_file_to_string source_file)
|
|
|
|
| _ -> assert false (* NOTE: Assumes that an AST always starts with a TranslationUnitDecl *)
|
|
|
|
with
|
|
|
|
| Assert_failure (file, line, column) as exn ->
|
|
|
|
Logging.err "Fatal error: exception Assert_failure(%s, %d, %d)@\n%!" file line column;
|
|
|
|
raise exn
|