diff --git a/clang/include/clang/Analysis/FlowSensitive/Value.h b/clang/include/clang/Analysis/FlowSensitive/Value.h index 7c02cc6c3505bf..98df8f6539f7b0 100644 --- a/clang/include/clang/Analysis/FlowSensitive/Value.h +++ b/clang/include/clang/Analysis/FlowSensitive/Value.h @@ -201,11 +201,13 @@ class StructValue final : public Value { return Val->getKind() == Kind::Struct; } - /// Returns the child value that is assigned for `D`. - Value &getChild(const ValueDecl &D) const { + /// Returns the child value that is assigned for `D` or null if the child is + /// not initialized. + Value *getChild(const ValueDecl &D) const { auto It = Children.find(&D); - assert(It != Children.end()); - return *It->second; + if (It == Children.end()) + return nullptr; + return It->second; } /// Assigns `Val` as the child value for `D`. diff --git a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp index 691b1257ba4fb7..ec945bac09863c 100644 --- a/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp +++ b/clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp @@ -366,7 +366,8 @@ void Environment::setValue(const StorageLocation &Loc, Value &Val) { assert(Field != nullptr); StorageLocation &FieldLoc = AggregateLoc.getChild(*Field); MemberLocToStruct[&FieldLoc] = std::make_pair(StructVal, Field); - setValue(FieldLoc, StructVal->getChild(*Field)); + if (auto *FieldVal = StructVal->getChild(*Field)) + setValue(FieldLoc, *FieldVal); } } @@ -485,9 +486,9 @@ Value *Environment::createValueUnlessSelfReferential( continue; Visited.insert(FieldType.getCanonicalType()); - FieldValues.insert( - {Field, createValueUnlessSelfReferential( - FieldType, Visited, Depth + 1, CreatedValuesCount)}); + if (auto *FieldValue = createValueUnlessSelfReferential( + FieldType, Visited, Depth + 1, CreatedValuesCount)) + FieldValues.insert({Field, FieldValue}); Visited.erase(FieldType.getCanonicalType()); } diff --git a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp index de11ccbc6fd5cd..51b40f23198788 100644 --- a/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/DataflowEnvironmentTest.cpp @@ -7,7 +7,10 @@ //===----------------------------------------------------------------------===// #include "clang/Analysis/FlowSensitive/DataflowEnvironment.h" +#include "NoopAnalysis.h" +#include "TestingSupport.h" #include "clang/Analysis/FlowSensitive/DataflowAnalysisContext.h" +#include "clang/Analysis/FlowSensitive/Value.h" #include "clang/Analysis/FlowSensitive/WatchedLiteralsSolver.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -17,6 +20,8 @@ namespace { using namespace clang; using namespace dataflow; +using ::testing::ElementsAre; +using ::testing::Pair; class EnvironmentTest : public ::testing::Test { DataflowAnalysisContext Context; @@ -54,4 +59,43 @@ TEST_F(EnvironmentTest, FlowCondition) { EXPECT_FALSE(Env.flowConditionImplies(NotX)); } +TEST_F(EnvironmentTest, CreateValueRecursiveType) { + using namespace ast_matchers; + + std::string Code = R"cc( + struct Recursive { + bool X; + Recursive *R; + }; + )cc"; + + auto Unit = + tooling::buildASTFromCodeWithArgs(Code, {"-fsyntax-only", "-std=c++11"}); + auto &Context = Unit->getASTContext(); + + ASSERT_EQ(Context.getDiagnostics().getClient()->getNumErrors(), 0U); + + auto Results = + match(qualType(hasDeclaration(recordDecl( + hasName("Recursive"), + has(fieldDecl(hasName("R")).bind("field-r"))))) + .bind("target"), + Context); + const QualType *Ty = selectFirst("target", Results); + const FieldDecl *R = selectFirst("field-r", Results); + ASSERT_TRUE(Ty != nullptr && !Ty->isNull()); + ASSERT_TRUE(R != nullptr); + + // Verify that the struct and the field (`R`) with first appearance of the + // type is created successfully. + Value *Val = Env.createValue(*Ty); + ASSERT_NE(Val, nullptr); + StructValue *SVal = clang::dyn_cast(Val); + ASSERT_NE(SVal, nullptr); + Val = SVal->getChild(*R); + ASSERT_NE(Val, nullptr); + PointerValue *PV = clang::dyn_cast(Val); + EXPECT_NE(PV, nullptr); +} + } // namespace diff --git a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp index 563de6e675792e..49aaca9a7588c0 100644 --- a/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp +++ b/clang/unittests/Analysis/FlowSensitive/TransferTest.cpp @@ -181,7 +181,7 @@ TEST_F(TransferTest, StructVarDecl) { cast(&FooLoc->getChild(*BarDecl)); const auto *FooVal = cast(Env.getValue(*FooLoc)); - const auto *BarVal = cast(&FooVal->getChild(*BarDecl)); + const auto *BarVal = cast(FooVal->getChild(*BarDecl)); EXPECT_EQ(Env.getValue(*BarLoc), BarVal); }); } @@ -227,7 +227,7 @@ TEST_F(TransferTest, ClassVarDecl) { cast(&FooLoc->getChild(*BarDecl)); const auto *FooVal = cast(Env.getValue(*FooLoc)); - const auto *BarVal = cast(&FooVal->getChild(*BarDecl)); + const auto *BarVal = cast(FooVal->getChild(*BarDecl)); EXPECT_EQ(Env.getValue(*BarLoc), BarVal); }); } @@ -351,27 +351,27 @@ TEST_F(TransferTest, SelfReferentialReferenceVarDecl) { cast(Env.getValue(FooVal->getPointeeLoc())); const auto *BarVal = - cast(&FooPointeeVal->getChild(*BarDecl)); + cast(FooPointeeVal->getChild(*BarDecl)); const auto *BarPointeeVal = cast(Env.getValue(BarVal->getPointeeLoc())); const auto *FooRefVal = - cast(&BarPointeeVal->getChild(*FooRefDecl)); + cast(BarPointeeVal->getChild(*FooRefDecl)); const StorageLocation &FooRefPointeeLoc = FooRefVal->getPointeeLoc(); EXPECT_THAT(Env.getValue(FooRefPointeeLoc), IsNull()); const auto *FooPtrVal = - cast(&BarPointeeVal->getChild(*FooPtrDecl)); + cast(BarPointeeVal->getChild(*FooPtrDecl)); const StorageLocation &FooPtrPointeeLoc = FooPtrVal->getPointeeLoc(); EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull()); const auto *BazRefVal = - cast(&BarPointeeVal->getChild(*BazRefDecl)); + cast(BarPointeeVal->getChild(*BazRefDecl)); const StorageLocation &BazRefPointeeLoc = BazRefVal->getPointeeLoc(); EXPECT_THAT(Env.getValue(BazRefPointeeLoc), NotNull()); const auto *BazPtrVal = - cast(&BarPointeeVal->getChild(*BazPtrDecl)); + cast(BarPointeeVal->getChild(*BazPtrDecl)); const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc(); EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull()); }); @@ -508,27 +508,27 @@ TEST_F(TransferTest, SelfReferentialPointerVarDecl) { cast(Env.getValue(FooVal->getPointeeLoc())); const auto *BarVal = - cast(&FooPointeeVal->getChild(*BarDecl)); + cast(FooPointeeVal->getChild(*BarDecl)); const auto *BarPointeeVal = cast(Env.getValue(BarVal->getPointeeLoc())); const auto *FooRefVal = - cast(&BarPointeeVal->getChild(*FooRefDecl)); + cast(BarPointeeVal->getChild(*FooRefDecl)); const StorageLocation &FooRefPointeeLoc = FooRefVal->getPointeeLoc(); EXPECT_THAT(Env.getValue(FooRefPointeeLoc), IsNull()); const auto *FooPtrVal = - cast(&BarPointeeVal->getChild(*FooPtrDecl)); + cast(BarPointeeVal->getChild(*FooPtrDecl)); const StorageLocation &FooPtrPointeeLoc = FooPtrVal->getPointeeLoc(); EXPECT_THAT(Env.getValue(FooPtrPointeeLoc), IsNull()); const auto *BazRefVal = - cast(&BarPointeeVal->getChild(*BazRefDecl)); + cast(BarPointeeVal->getChild(*BazRefDecl)); const StorageLocation &BazRefPointeeLoc = BazRefVal->getPointeeLoc(); EXPECT_THAT(Env.getValue(BazRefPointeeLoc), NotNull()); const auto *BazPtrVal = - cast(&BarPointeeVal->getChild(*BazPtrDecl)); + cast(BarPointeeVal->getChild(*BazPtrDecl)); const StorageLocation &BazPtrPointeeLoc = BazPtrVal->getPointeeLoc(); EXPECT_THAT(Env.getValue(BazPtrPointeeLoc), NotNull()); }); @@ -888,7 +888,7 @@ TEST_F(TransferTest, StructParamDecl) { cast(&FooLoc->getChild(*BarDecl)); const auto *FooVal = cast(Env.getValue(*FooLoc)); - const auto *BarVal = cast(&FooVal->getChild(*BarDecl)); + const auto *BarVal = cast(FooVal->getChild(*BarDecl)); EXPECT_EQ(Env.getValue(*BarLoc), BarVal); }); } @@ -1000,7 +1000,7 @@ TEST_F(TransferTest, StructMember) { const auto *FooLoc = cast( Env.getStorageLocation(*FooDecl, SkipPast::None)); const auto *FooVal = cast(Env.getValue(*FooLoc)); - const auto *BarVal = cast(&FooVal->getChild(*BarDecl)); + const auto *BarVal = cast(FooVal->getChild(*BarDecl)); const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); @@ -1048,7 +1048,7 @@ TEST_F(TransferTest, ClassMember) { const auto *FooLoc = cast( Env.getStorageLocation(*FooDecl, SkipPast::None)); const auto *FooVal = cast(Env.getValue(*FooLoc)); - const auto *BarVal = cast(&FooVal->getChild(*BarDecl)); + const auto *BarVal = cast(FooVal->getChild(*BarDecl)); const ValueDecl *BazDecl = findValueDecl(ASTCtx, "Baz"); ASSERT_THAT(BazDecl, NotNull()); @@ -1095,7 +1095,7 @@ TEST_F(TransferTest, ReferenceMember) { const auto *FooLoc = cast( Env.getStorageLocation(*FooDecl, SkipPast::None)); const auto *FooVal = cast(Env.getValue(*FooLoc)); - const auto *BarVal = cast(&FooVal->getChild(*BarDecl)); + const auto *BarVal = cast(FooVal->getChild(*BarDecl)); const auto *BarPointeeVal = cast(Env.getValue(BarVal->getPointeeLoc())); @@ -1173,7 +1173,7 @@ TEST_F(TransferTest, StructThisMember) { const auto *BazLoc = cast(&QuxLoc->getChild(*BazDecl)); - const auto *BazVal = cast(&QuxVal->getChild(*BazDecl)); + const auto *BazVal = cast(QuxVal->getChild(*BazDecl)); EXPECT_EQ(Env.getValue(*BazLoc), BazVal); const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); @@ -1249,7 +1249,7 @@ TEST_F(TransferTest, ClassThisMember) { const auto *BazLoc = cast(&QuxLoc->getChild(*BazDecl)); - const auto *BazVal = cast(&QuxVal->getChild(*BazDecl)); + const auto *BazVal = cast(QuxVal->getChild(*BazDecl)); EXPECT_EQ(Env.getValue(*BazLoc), BazVal); const ValueDecl *QuuxDecl = findValueDecl(ASTCtx, "Quux"); @@ -1399,7 +1399,7 @@ TEST_F(TransferTest, TemporaryObject) { cast(&FooLoc->getChild(*BarDecl)); const auto *FooVal = cast(Env.getValue(*FooLoc)); - const auto *BarVal = cast(&FooVal->getChild(*BarDecl)); + const auto *BarVal = cast(FooVal->getChild(*BarDecl)); EXPECT_EQ(Env.getValue(*BarLoc), BarVal); }); } @@ -1438,7 +1438,7 @@ TEST_F(TransferTest, ElidableConstructor) { cast(&FooLoc->getChild(*BarDecl)); const auto *FooVal = cast(Env.getValue(*FooLoc)); - const auto *BarVal = cast(&FooVal->getChild(*BarDecl)); + const auto *BarVal = cast(FooVal->getChild(*BarDecl)); EXPECT_EQ(Env.getValue(*BarLoc), BarVal); }, LangStandard::lang_cxx14); @@ -1706,7 +1706,7 @@ TEST_F(TransferTest, BindTemporary) { *cast(Env.getValue(*FooDecl, SkipPast::None)); const auto *BarVal = cast(Env.getValue(*BarDecl, SkipPast::None)); - EXPECT_EQ(BarVal, &FooVal.getChild(*BazDecl)); + EXPECT_EQ(BarVal, FooVal.getChild(*BazDecl)); }); } @@ -1982,12 +1982,12 @@ TEST_F(TransferTest, AggregateInitialization) { cast(Env.getValue(*QuuxDecl, SkipPast::None)); ASSERT_THAT(QuuxVal, NotNull()); - const auto *BazVal = cast(&QuuxVal->getChild(*BazDecl)); + const auto *BazVal = cast(QuuxVal->getChild(*BazDecl)); ASSERT_THAT(BazVal, NotNull()); - EXPECT_EQ(&QuuxVal->getChild(*BarDecl), BarArgVal); - EXPECT_EQ(&BazVal->getChild(*FooDecl), FooArgVal); - EXPECT_EQ(&QuuxVal->getChild(*QuxDecl), QuxArgVal); + EXPECT_EQ(QuuxVal->getChild(*BarDecl), BarArgVal); + EXPECT_EQ(BazVal->getChild(*FooDecl), FooArgVal); + EXPECT_EQ(QuuxVal->getChild(*QuxDecl), QuxArgVal); }); } } @@ -2383,7 +2383,7 @@ TEST_F(TransferTest, AssignMemberBeforeCopy) { const auto *A2Val = cast(Env.getValue(*A2Decl, SkipPast::None)); - EXPECT_EQ(&A2Val->getChild(*FooDecl), BarVal); + EXPECT_EQ(A2Val->getChild(*FooDecl), BarVal); }); }