//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "CheckerRegistration.h" #include "clang/StaticAnalyzer/Core/Checker.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ProgramStateTrait.h" #include "clang/StaticAnalyzer/Frontend/AnalysisConsumer.h" #include "clang/StaticAnalyzer/Frontend/CheckerRegistry.h" #include "gtest/gtest.h" using namespace clang; using namespace ento; // Some dummy trait that we can mutate back and forth to force a new State. REGISTER_TRAIT_WITH_PROGRAMSTATE(Flag, bool) namespace { class FlipFlagOnCheckLocation : public Checker { public: // We make sure we alter the State every time we model a checkLocation event. void checkLocation(SVal l, bool isLoad, const Stmt *S, CheckerContext &C) const { ProgramStateRef State = C.getState(); State = State->set(!State->get()); C.addTransition(State); } }; void addFlagFlipperChecker(AnalysisASTConsumer &AnalysisConsumer, AnalyzerOptions &AnOpts) { AnOpts.CheckersAndPackages = {{"test.FlipFlagOnCheckLocation", true}}; AnalysisConsumer.AddCheckerRegistrationFn([](CheckerRegistry &Registry) { Registry.addChecker("test.FlipFlagOnCheckLocation", "MockDescription"); }); } TEST(ObjCTest, CheckLocationEventsShouldMaterializeInObjCForCollectionStmts) { // Previously, the `ExprEngine::hasMoreIteration` may fired an assertion // because we forgot to handle correctly the resulting nodes of the // check::Location callback for the ObjCForCollectionStmts. // This caused inconsistencies in the graph and triggering the assertion. // See #124477 for more details. std::string Diags; EXPECT_TRUE(runCheckerOnCodeWithArgs( R"( @class NSArray, NSDictionary, NSString; extern void NSLog(NSString *format, ...) __attribute__((format(__NSString__, 1, 2))); void entrypoint(NSArray *bowl) { for (NSString *fruit in bowl) { // no-crash NSLog(@"Fruit: %@", fruit); } })", {"-x", "objective-c"}, Diags)); } } // namespace