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 {