From b7ec110ea387335a52ab829394f4b339480f848d Mon Sep 17 00:00:00 2001 From: Dulma Churchill Date: Wed, 17 Aug 2016 09:41:22 -0700 Subject: [PATCH] Adding new mode linters Summary: Adding a new mode linters. Now if the analyzer is linters, we do the linters and don't translate, then, if the analyzer is Infer, we do the translation and the backend and not the linters checks, and the default is that we do capture, backend and lint checks. Made the tests separated, which saves time and also shows that the linters mode works. Reviewed By: jvillard Differential Revision: D3723472 fbshipit-source-id: 9d828d8 --- infer/lib/python/inferlib/config.py | 2 + infer/src/backend/config.ml | 10 +- infer/src/backend/config.mli | 3 +- infer/src/clang/cFrontend.ml | 6 +- infer/src/clang/cFrontend_checkers_main.ml | 4 +- infer/src/clang/cFrontend_errors.ml | 4 +- .../AutoreleaseExample.dot | 7 -- .../objc/linters/AssignPointerTest.java | 7 +- .../objc/linters/AtomicPropertyTest.java | 2 +- .../endtoend/objc/linters/NSNumber2Test.java | 2 +- .../endtoend/objc/linters/NSNumberTest.java | 2 +- .../objc/linters/RegisteredObserver.java | 5 +- .../objc/linters/RegisteredObserver2.java | 5 +- .../objc/linters/RegisteredObserver3.java | 5 +- .../objc/linters/RegisteredObserver4.java | 5 +- .../objc/linters/StrongDelegateTest.java | 2 +- ...utableLocalVariableInNonComponentTest.java | 2 +- .../MutableLocalVariableTest.java | 2 +- .../linters/BlockCaptureCXXRefTest.java | 2 +- .../objcpp/linters/GlobalVarTest.java | 2 +- infer/tests/utils/InferRunner.java | 92 ++++++++++++------- 21 files changed, 93 insertions(+), 78 deletions(-) diff --git a/infer/lib/python/inferlib/config.py b/infer/lib/python/inferlib/config.py index 8d1402e5f..3acf55d1a 100644 --- a/infer/lib/python/inferlib/config.py +++ b/infer/lib/python/inferlib/config.py @@ -73,6 +73,7 @@ ANALYZER_CAPTURE = 'capture' ANALYZER_COMPILE = 'compile' ANALYZER_TRACING = 'tracing' ANALYZER_CRASHCONTEXT = 'crashcontext' +ANALYZER_LINTERS = 'linters' ANALYZERS = [ ANALYZER_CAPTURE, @@ -81,5 +82,6 @@ ANALYZERS = [ ANALYZER_CRASHCONTEXT, ANALYZER_ERADICATE, ANALYZER_INFER, + ANALYZER_LINTERS, ANALYZER_TRACING, ] diff --git a/infer/src/backend/config.ml b/infer/src/backend/config.ml index 9cc3456e8..417e034b1 100644 --- a/infer/src/backend/config.ml +++ b/infer/src/backend/config.ml @@ -18,12 +18,12 @@ module F = Format type analyzer = Capture | Compile | Infer | Eradicate | Checkers | Tracing - | Crashcontext + | Crashcontext | Linters let string_to_analyzer = [("capture", Capture); ("compile", Compile); ("infer", Infer); ("eradicate", Eradicate); ("checkers", Checkers); - ("tracing", Tracing); ("crashcontext", Crashcontext)] + ("tracing", Tracing); ("crashcontext", Crashcontext); ("linters", Linters)] type clang_lang = C | CPP | OBJC | OBJCPP @@ -130,7 +130,6 @@ let inferconfig_file = ".inferconfig" let ivar_attributes = "ivar_attributes" let lint_issues_dir_name = "lint_issues" -let linters_mode_enabled = false (** letters used in the analysis output *) let log_analysis_file = "F" @@ -517,14 +516,15 @@ and analyzer = let () = match Infer with (* NOTE: if compilation fails here, it means you have added a new analyzer without updating the documentation of this option *) - | Capture | Compile | Infer | Eradicate | Checkers | Tracing | Crashcontext -> () in + | Capture | Compile | Infer | Eradicate | Checkers | Tracing | Crashcontext | Linters -> () in CLOpt.mk_symbol_opt ~deprecated:["analyzer"] ~long:"analyzer" ~short:"a" ~exes:CLOpt.[Toplevel] "Specify which analyzer to run (only one at a time is supported):\n\ - infer, eradicate, checkers: run the specified analysis\n\ - capture: run capture phase only (no analysis)\n\ - compile: run compilation command without interfering (Java only)\n\ - - crashcontext, tracing: experimental (see --crashcontext and --tracing)" + - crashcontext, tracing: experimental (see --crashcontext and --tracing)\n\ + - linters: run linters based on the ast only (Objective-C and Objective-C++ only)" ~symbols:string_to_analyzer and android_harness = diff --git a/infer/src/backend/config.mli b/infer/src/backend/config.mli index bdd902d28..c84b495b3 100644 --- a/infer/src/backend/config.mli +++ b/infer/src/backend/config.mli @@ -16,7 +16,7 @@ open! Utils (** Various kind of analyzers *) type analyzer = Capture | Compile | Infer | Eradicate | Checkers | Tracing - | Crashcontext + | Crashcontext | Linters (** Association list of analyzers and their names *) val string_to_analyzer : (string * analyzer) list @@ -81,7 +81,6 @@ val incremental_procs : bool val initial_analysis_time : float val ivar_attributes : string val lint_issues_dir_name : string -val linters_mode_enabled : bool val load_average : float option val log_analysis_crash : string val log_analysis_file : string diff --git a/infer/src/clang/cFrontend.ml b/infer/src/clang/cFrontend.ml index a1f80949f..542bbbd15 100644 --- a/infer/src/clang/cFrontend.ml +++ b/infer/src/clang/cFrontend.ml @@ -27,7 +27,7 @@ let compute_icfg tenv ast = Printing.log_out "\n Start creating icfg\n"; let cg = Cg.create () in let cfg = Cfg.Node.create_cfg () in - if not Config.linters_mode_enabled then + if Config.analyzer <> Some Config.Linters then IList.iter (CFrontend_declImpl.translate_one_declaration tenv cg cfg `DeclTraversal) decl_list; Printing.log_out "\n Finished creating icfg\n"; @@ -61,7 +61,9 @@ let do_source_file source_file ast = let call_graph, cfg = compute_icfg tenv ast in Printing.log_out "\n End building call/cfg graph for '%s'.\n" (DB.source_file_to_string source_file); - CFrontend_checkers_main.do_frontend_checks cfg call_graph source_file ast; + (* TODO (t12740727): Move this call to cMain once the transition to linters mode is finished *) + if Config.analyzer <> Some Config.Infer then + CFrontend_checkers_main.do_frontend_checks cfg call_graph source_file ast; (* This part below is a boilerplate in every frontends. *) (* This could be moved in the cfg_infer module *) let source_dir = DB.source_dir_from_source_file !DB.current_source in diff --git a/infer/src/clang/cFrontend_checkers_main.ml b/infer/src/clang/cFrontend_checkers_main.ml index a5c8e6a7e..d29fb2606 100644 --- a/infer/src/clang/cFrontend_checkers_main.ml +++ b/infer/src/clang/cFrontend_checkers_main.ml @@ -17,6 +17,7 @@ let rec do_frontend_checks_stmt (context:CLintersContext.context) cfg cg method_ | _ -> ()); do_frontend_checks_stmt context' cfg cg method_decl stmt in IList.iter (do_all_checks_on_stmts) stmts + and do_frontend_checks_decl context cfg cg decl = let open Clang_ast_t in let info = Clang_ast_proj.get_decl_tuple decl in @@ -61,5 +62,6 @@ let do_frontend_checks cfg cg source_file ast = | Clang_ast_t.TranslationUnitDecl(_, decl_list, _, _) -> let context = context_with_ck_set CLintersContext.empty decl_list in IList.iter (do_frontend_checks_decl context cfg cg) decl_list; - if Config.linters_mode_enabled then store_issues source_file + (* TODO (t12740727): Remove condition once the transition to linters mode is finished *) + if Config.analyzer = Some Config.Linters then store_issues source_file | _ -> assert false (* NOTE: Assumes that an AST alsways starts with a TranslationUnitDecl *) diff --git a/infer/src/clang/cFrontend_errors.ml b/infer/src/clang/cFrontend_errors.ml index 1ba8c56b2..eebd2c6fa 100644 --- a/infer/src/clang/cFrontend_errors.ml +++ b/infer/src/clang/cFrontend_errors.ml @@ -80,9 +80,9 @@ let get_err_log cfg cg method_decl_opt loc = let procname = match method_decl_opt with | Some method_decl -> General_utils.procname_of_decl method_decl | None -> General_utils.get_procname_for_frontend_checks loc in - if Config.linters_mode_enabled then + if Config.analyzer = Some Config.Linters then LintIssues.get_err_log procname - else + else (* TODO (t12740727): Remove this branch once the transition to linters mode is finished *) let pdesc = CMethod_trans.get_method_for_frontend_checks cfg cg loc in Cfg.Procdesc.get_err_log pdesc diff --git a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/AutoreleaseExample.dot b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/AutoreleaseExample.dot index 69f7656c3..e86008cdd 100644 --- a/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/AutoreleaseExample.dot +++ b/infer/tests/codetoanalyze/objc/errors/memory_leaks_benchmark/AutoreleaseExample.dot @@ -1,12 +1,5 @@ /* @generated */ digraph iCFG { -37 [label="37: Exit frontend_checks_260aba1187e75a8c3340e4b361681569 \n " color=yellow style=filled] - - -36 [label="36: Start frontend_checks_260aba1187e75a8c3340e4b361681569\nFormals: \nLocals: \n " color=yellow style=filled] - - - 36 -> 37 ; 35 [label="35: DeclStmt \n n$4=_fun___objc_alloc_no_fail(sizeof(class NSAutoreleasePool ):unsigned long ) [line 60]\n n$5=_fun_NSObject_init(n$4:class NSAutoreleasePool *) virtual [line 60]\n *&pool:class NSAutoreleasePool *=n$5 [line 60]\n " shape="box"] diff --git a/infer/tests/endtoend/objc/linters/AssignPointerTest.java b/infer/tests/endtoend/objc/linters/AssignPointerTest.java index 5718b5844..b6c47927f 100644 --- a/infer/tests/endtoend/objc/linters/AssignPointerTest.java +++ b/infer/tests/endtoend/objc/linters/AssignPointerTest.java @@ -40,12 +40,9 @@ public class AssignPointerTest { @BeforeClass public static void runInfer() throws InterruptedException, IOException { - inferCmd = InferRunner.createiOSInferCommandWithMLBuckets( + inferCmd = InferRunner.createObjCLintersCommand( folder, - FILE, - "cf", - true); - + FILE); } @Test diff --git a/infer/tests/endtoend/objc/linters/AtomicPropertyTest.java b/infer/tests/endtoend/objc/linters/AtomicPropertyTest.java index 388522caf..0b18dd7d2 100644 --- a/infer/tests/endtoend/objc/linters/AtomicPropertyTest.java +++ b/infer/tests/endtoend/objc/linters/AtomicPropertyTest.java @@ -40,7 +40,7 @@ public class AtomicPropertyTest { @BeforeClass public static void runInfer() throws InterruptedException, IOException { - inferCmd = InferRunner.createObjCInferCommand( + inferCmd = InferRunner.createObjCLintersCommand( folder, FILE); } diff --git a/infer/tests/endtoend/objc/linters/NSNumber2Test.java b/infer/tests/endtoend/objc/linters/NSNumber2Test.java index 274c559b7..3abafd8e2 100644 --- a/infer/tests/endtoend/objc/linters/NSNumber2Test.java +++ b/infer/tests/endtoend/objc/linters/NSNumber2Test.java @@ -39,7 +39,7 @@ public class NSNumber2Test { @BeforeClass public static void runInfer() throws InterruptedException, IOException { - inferCmd = InferRunner.createObjCInferCommand( + inferCmd = InferRunner.createObjCLintersCommand( folder, NSNUMBER_FILE); } diff --git a/infer/tests/endtoend/objc/linters/NSNumberTest.java b/infer/tests/endtoend/objc/linters/NSNumberTest.java index 593fb1dfc..cd23dca47 100644 --- a/infer/tests/endtoend/objc/linters/NSNumberTest.java +++ b/infer/tests/endtoend/objc/linters/NSNumberTest.java @@ -39,7 +39,7 @@ public class NSNumberTest { @BeforeClass public static void runInfer() throws InterruptedException, IOException { - inferCmd = InferRunner.createObjCInferCommand( + inferCmd = InferRunner.createObjCLintersCommand( folder, NSNUMBER_FILE); } diff --git a/infer/tests/endtoend/objc/linters/RegisteredObserver.java b/infer/tests/endtoend/objc/linters/RegisteredObserver.java index 6148d1cb7..1490fb8ec 100644 --- a/infer/tests/endtoend/objc/linters/RegisteredObserver.java +++ b/infer/tests/endtoend/objc/linters/RegisteredObserver.java @@ -39,10 +39,9 @@ public class RegisteredObserver { @BeforeClass public static void runInfer() throws InterruptedException, IOException { - inferCmd = InferRunner.createObjCInferCommandSimple( + inferCmd = InferRunner.createObjCLintersCommandSimple( folder, - VCFile, - "cf"); + VCFile); } @Test diff --git a/infer/tests/endtoend/objc/linters/RegisteredObserver2.java b/infer/tests/endtoend/objc/linters/RegisteredObserver2.java index b06559959..30de415b0 100644 --- a/infer/tests/endtoend/objc/linters/RegisteredObserver2.java +++ b/infer/tests/endtoend/objc/linters/RegisteredObserver2.java @@ -39,10 +39,9 @@ public class RegisteredObserver2 { @BeforeClass public static void runInfer() throws InterruptedException, IOException { - inferCmd = InferRunner.createObjCInferCommandSimple( + inferCmd = InferRunner.createObjCLintersCommandSimple( folder, - VCFile2, - "cf"); + VCFile2); } @Test diff --git a/infer/tests/endtoend/objc/linters/RegisteredObserver3.java b/infer/tests/endtoend/objc/linters/RegisteredObserver3.java index 09268f159..2b63ff2ba 100644 --- a/infer/tests/endtoend/objc/linters/RegisteredObserver3.java +++ b/infer/tests/endtoend/objc/linters/RegisteredObserver3.java @@ -40,10 +40,9 @@ public class RegisteredObserver3 { @BeforeClass public static void runInfer() throws InterruptedException, IOException { - inferCmd = InferRunner.createObjCInferCommandSimple( + inferCmd = InferRunner.createObjCLintersCommandSimple( folder, - VCFile3, - "cf"); + VCFile3); } @Test diff --git a/infer/tests/endtoend/objc/linters/RegisteredObserver4.java b/infer/tests/endtoend/objc/linters/RegisteredObserver4.java index cbd96e708..7da454e55 100644 --- a/infer/tests/endtoend/objc/linters/RegisteredObserver4.java +++ b/infer/tests/endtoend/objc/linters/RegisteredObserver4.java @@ -39,10 +39,9 @@ public class RegisteredObserver4 { @BeforeClass public static void runInfer() throws InterruptedException, IOException { - inferCmd = InferRunner.createObjCInferCommandSimple( + inferCmd = InferRunner.createObjCLintersCommandSimple( folder, - VCFile, - "cf"); + VCFile); } @Test diff --git a/infer/tests/endtoend/objc/linters/StrongDelegateTest.java b/infer/tests/endtoend/objc/linters/StrongDelegateTest.java index ef0e60fe1..b919db1e5 100644 --- a/infer/tests/endtoend/objc/linters/StrongDelegateTest.java +++ b/infer/tests/endtoend/objc/linters/StrongDelegateTest.java @@ -40,7 +40,7 @@ public class StrongDelegateTest { @BeforeClass public static void runInfer() throws InterruptedException, IOException { - inferCmdFraction = InferRunner.createObjCInferCommand( + inferCmdFraction = InferRunner.createObjCLintersCommand( folder, FILE); } diff --git a/infer/tests/endtoend/objcpp/componentkit/MutableLocalVariableInNonComponentTest.java b/infer/tests/endtoend/objcpp/componentkit/MutableLocalVariableInNonComponentTest.java index 73f8fd986..52d831344 100644 --- a/infer/tests/endtoend/objcpp/componentkit/MutableLocalVariableInNonComponentTest.java +++ b/infer/tests/endtoend/objcpp/componentkit/MutableLocalVariableInNonComponentTest.java @@ -35,7 +35,7 @@ package endtoend.objcpp.componentkit; @BeforeClass public static void runInfer() throws InterruptedException, IOException { - inferCmd = InferRunner.createObjCPPInferCommand( + inferCmd = InferRunner.createObjCPPLintersCommand( folder, FILE); } diff --git a/infer/tests/endtoend/objcpp/componentkit/MutableLocalVariableTest.java b/infer/tests/endtoend/objcpp/componentkit/MutableLocalVariableTest.java index 4f35aad42..ad14b2af5 100644 --- a/infer/tests/endtoend/objcpp/componentkit/MutableLocalVariableTest.java +++ b/infer/tests/endtoend/objcpp/componentkit/MutableLocalVariableTest.java @@ -38,7 +38,7 @@ public class MutableLocalVariableTest { @BeforeClass public static void runInfer() throws InterruptedException, IOException { - inferCmd = InferRunner.createObjCPPInferCommand( + inferCmd = InferRunner.createObjCPPLintersCommand( folder, FILE); } diff --git a/infer/tests/endtoend/objcpp/linters/BlockCaptureCXXRefTest.java b/infer/tests/endtoend/objcpp/linters/BlockCaptureCXXRefTest.java index 0568db506..d2bf9490b 100644 --- a/infer/tests/endtoend/objcpp/linters/BlockCaptureCXXRefTest.java +++ b/infer/tests/endtoend/objcpp/linters/BlockCaptureCXXRefTest.java @@ -40,7 +40,7 @@ public class BlockCaptureCXXRefTest { @BeforeClass public static void runInfer() throws InterruptedException, IOException { - inferCmd = InferRunner.createObjCPPInferCommand(folder, FILE); + inferCmd = InferRunner.createObjCPPLintersCommand(folder, FILE); } @Test diff --git a/infer/tests/endtoend/objcpp/linters/GlobalVarTest.java b/infer/tests/endtoend/objcpp/linters/GlobalVarTest.java index c8e4d0988..12840b276 100644 --- a/infer/tests/endtoend/objcpp/linters/GlobalVarTest.java +++ b/infer/tests/endtoend/objcpp/linters/GlobalVarTest.java @@ -41,7 +41,7 @@ public class GlobalVarTest { @BeforeClass public static void runInfer() throws InterruptedException, IOException { - inferCmdFraction = InferRunner.createObjCPPInferCommand( + inferCmdFraction = InferRunner.createObjCPPLintersCommand( folder, FILE); } diff --git a/infer/tests/utils/InferRunner.java b/infer/tests/utils/InferRunner.java index 63dd4ad7e..681de87c4 100644 --- a/infer/tests/utils/InferRunner.java +++ b/infer/tests/utils/InferRunner.java @@ -278,17 +278,14 @@ public class InferRunner { TemporaryFolder folder, String sourceFile, Language lang, - boolean analyze, + String analyzer, @Nullable String isysroot, @Nullable String ml_buckets, boolean arc, ImmutableList extraInferOptions) { ImmutableList.Builder inferOptionsBuilder = new ImmutableList.Builder() .addAll(extraInferOptions); - - if (!analyze) { - inferOptionsBuilder.add("--analyzer").add("capture"); - } + inferOptionsBuilder.add("--analyzer").add(analyzer); inferOptionsBuilder .add("--ml_buckets") @@ -311,7 +308,7 @@ public class InferRunner { folder, sourceFile, Language.C, - false, + "capture", null, null, false, @@ -332,7 +329,7 @@ public class InferRunner { folder, sourceFile, Language.CPP, - false, + "capture", null, null, false, @@ -353,7 +350,7 @@ public class InferRunner { folder, sourceFile, Language.ObjC, - false, + "capture", getXcodeRoot() + IPHONESIMULATOR_ISYSROOT_SUFFIX, null, false, @@ -374,7 +371,7 @@ public class InferRunner { folder, sourceFile, Language.ObjC, - false, + "capture", getXcodeRoot() + IPHONESIMULATOR_ISYSROOT_SUFFIX, null, true, @@ -395,7 +392,7 @@ public class InferRunner { folder, sourceFile, Language.ObjCPP, - false, + "capture", getXcodeRoot() + IPHONESIMULATOR_ISYSROOT_SUFFIX, null, false, @@ -416,7 +413,7 @@ public class InferRunner { folder, sourceFile, Language.C, - true, + "infer", null, null, false, @@ -441,7 +438,7 @@ public class InferRunner { folder, sourceFile, Language.CPP, - true, + "infer", null, null, false, @@ -471,7 +468,7 @@ public class InferRunner { folder, sourceFile, Language.CPP, - true, + "infer", null, ml_bucket, false, @@ -485,28 +482,13 @@ public class InferRunner { folder, sourceFile, Language.ObjC, - true, + "infer", getXcodeRoot() + IPHONESIMULATOR_ISYSROOT_SUFFIX, null, false, ImmutableList.of()); } - public static ImmutableList createObjCInferCommandSimple( - TemporaryFolder folder, - String sourceFile, - String ml_bucket) throws IOException, InterruptedException { - return createClangInferCommand( - folder, - sourceFile, - Language.ObjC, - true, - null, - ml_bucket, - false, - ImmutableList.of()); - } - public static ImmutableList createObjCInferCommandWithMLBuckets( TemporaryFolder folder, String sourceFile, @@ -516,7 +498,7 @@ public class InferRunner { folder, sourceFile, Language.ObjC, - true, + "infer", getXcodeRoot() + IPHONESIMULATOR_ISYSROOT_SUFFIX, ml_bucket, arc, @@ -530,7 +512,7 @@ public class InferRunner { folder, sourceFile, Language.ObjCPP, - true, + "infer", getXcodeRoot() + IPHONESIMULATOR_ISYSROOT_SUFFIX, null, false, @@ -544,7 +526,7 @@ public class InferRunner { folder, sourceFile, Language.ObjC, - false, + "infer", getXcodeRoot() + IPHONESIMULATOR_ISYSROOT_SUFFIX, null, false, @@ -558,7 +540,7 @@ public class InferRunner { folder, sourceFile, Language.ObjC, - true, + "infer", getXcodeRoot() + IPHONESIMULATOR_ISYSROOT_SUFFIX, null, false, @@ -574,13 +556,55 @@ public class InferRunner { folder, sourceFile, Language.ObjC, - true, + "infer", getXcodeRoot() + IPHONESIMULATOR_ISYSROOT_SUFFIX, bucket, arc, ImmutableList.of()); } + public static ImmutableList createLintersCommand( + TemporaryFolder folder, + String sourceFile, + Language lang) throws IOException, InterruptedException { + return createClangInferCommand( + folder, + sourceFile, + lang, + "linters", + getXcodeRoot() + IPHONESIMULATOR_ISYSROOT_SUFFIX, + null, + true, + ImmutableList.of()); + } + + public static ImmutableList createObjCLintersCommand( + TemporaryFolder folder, + String sourceFile) throws IOException, InterruptedException { + return createLintersCommand(folder, sourceFile, Language.ObjC); + } + + public static ImmutableList createObjCLintersCommandSimple( + TemporaryFolder folder, + String sourceFile) throws IOException, InterruptedException { + return createClangInferCommand( + folder, + sourceFile, + Language.ObjC, + "linters", + null, + null, + true, + ImmutableList.of()); + } + + public static ImmutableList createObjCPPLintersCommand( + TemporaryFolder folder, + String sourceFile) throws IOException, InterruptedException { + return createLintersCommand(folder, sourceFile, Language.ObjCPP); + } + + @Nullable public static File runInferFrontend(ImmutableList inferCmd) throws IOException, InterruptedException, InferException {