diff options
-rw-r--r-- | lib/StaticAnalyzer/Core/RegionStore.cpp | 24 | ||||
-rw-r--r-- | test/Analysis/derived-to-base.cpp | 50 |
2 files changed, 61 insertions, 13 deletions
diff --git a/lib/StaticAnalyzer/Core/RegionStore.cpp b/lib/StaticAnalyzer/Core/RegionStore.cpp index 05d1bd0dcf..bc4e4bbf60 100644 --- a/lib/StaticAnalyzer/Core/RegionStore.cpp +++ b/lib/StaticAnalyzer/Core/RegionStore.cpp @@ -17,6 +17,7 @@ #include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/CXXInheritance.h" #include "clang/Analysis/Analyses/LiveVariables.h" #include "clang/Analysis/AnalysisContext.h" #include "clang/Basic/TargetInfo.h" @@ -960,19 +961,16 @@ SVal RegionStoreManager::evalDynamicCast(SVal base, QualType derivedType, if (!derivedType->isVoidType()) { // Static upcasts are marked as DerivedToBase casts by Sema, so this will // only happen when multiple or virtual inheritance is involved. - // FIXME: We should build the correct stack of CXXBaseObjectRegions here, - // instead of just punting. - if (SRDecl->isDerivedFrom(DerivedDecl)) - return UnknownVal(); - - // If super region is not a parent of derived class, the cast definitely - // fails. - // FIXME: This and the above test each require walking the entire - // inheritance hierarchy, and this will happen for each - // CXXBaseObjectRegion wrapper. We should probably be combining the two. - if (DerivedDecl->isProvablyNotDerivedFrom(SRDecl)) { - Failed = true; - return UnknownVal(); + CXXBasePaths Paths(/*FindAmbiguities=*/false, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (SRDecl->isDerivedFrom(DerivedDecl, Paths)) { + SVal Result = loc::MemRegionVal(TSR); + const CXXBasePath &Path = *Paths.begin(); + for (CXXBasePath::const_iterator I = Path.begin(), E = Path.end(); + I != E; ++I) { + Result = evalDerivedToBase(Result, I->Base->getType()); + } + return Result; } } diff --git a/test/Analysis/derived-to-base.cpp b/test/Analysis/derived-to-base.cpp index b065bc25a3..f8336785de 100644 --- a/test/Analysis/derived-to-base.cpp +++ b/test/Analysis/derived-to-base.cpp @@ -85,3 +85,53 @@ namespace VirtualBaseClasses { clang_analyzer_eval(d.getX() == 42); // expected-warning{{TRUE}} } } + + +namespace DynamicVirtualUpcast { + class A { + public: + virtual ~A(); + }; + + class B : virtual public A {}; + class C : virtual public B {}; + class D : virtual public C {}; + + bool testCast(A *a) { + return dynamic_cast<B*>(a) && dynamic_cast<C*>(a); + } + + void test() { + D d; + clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}} + } +} + +namespace DynamicMultipleInheritanceUpcast { + class B { + public: + virtual ~B(); + }; + class C { + public: + virtual ~C(); + }; + class D : public B, public C {}; + + bool testCast(B *a) { + return dynamic_cast<C*>(a); + } + + void test() { + D d; + clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}} + } + + + class DV : virtual public B, virtual public C {}; + + void testVirtual() { + DV d; + clang_analyzer_eval(testCast(&d)); // expected-warning{{TRUE}} + } +} |