diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index f01e4e764014..06570a4b4a90 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -676,46 +676,40 @@ static CallInlinePolicy mayInlineCallKind(const CallEvent &Call, return CIP_Allowed; } -/// Returns true if the given C++ class is a container. -/// -/// Our heuristic for this is whether it contains a method named 'begin()' or a -/// nested type named 'iterator'. -static bool isContainerClass(const ASTContext &Ctx, const CXXRecordDecl *RD) { - // Don't record any path information. - CXXBasePaths Paths(false, false, false); +/// Returns true if the given C++ class contains a member with the given name. +static bool hasMember(const ASTContext &Ctx, const CXXRecordDecl *RD, + StringRef Name) { + const IdentifierInfo &II = Ctx.Idents.get(Name); + DeclarationName DeclName = Ctx.DeclarationNames.getIdentifier(&II); + if (!RD->lookup(DeclName).empty()) + return true; - const IdentifierInfo &BeginII = Ctx.Idents.get("begin"); - DeclarationName BeginName = Ctx.DeclarationNames.getIdentifier(&BeginII); - DeclContext::lookup_const_result BeginDecls = RD->lookup(BeginName); - if (!BeginDecls.empty()) - return true; + CXXBasePaths Paths(false, false, false); if (RD->lookupInBases(&CXXRecordDecl::FindOrdinaryMember, - BeginName.getAsOpaquePtr(), - Paths)) - return true; - - const IdentifierInfo &IterII = Ctx.Idents.get("iterator"); - DeclarationName IteratorName = Ctx.DeclarationNames.getIdentifier(&IterII); - DeclContext::lookup_const_result IterDecls = RD->lookup(IteratorName); - if (!IterDecls.empty()) - return true; - if (RD->lookupInBases(&CXXRecordDecl::FindOrdinaryMember, - IteratorName.getAsOpaquePtr(), + DeclName.getAsOpaquePtr(), Paths)) return true; return false; } +/// Returns true if the given C++ class is a container or iterator. +/// +/// Our heuristic for this is whether it contains a method named 'begin()' or a +/// nested type named 'iterator' or 'iterator_category'. +static bool isContainerClass(const ASTContext &Ctx, const CXXRecordDecl *RD) { + return hasMember(Ctx, RD, "begin") || + hasMember(Ctx, RD, "iterator") || + hasMember(Ctx, RD, "iterator_category"); +} + /// Returns true if the given function refers to a constructor or destructor of -/// a C++ container. +/// a C++ container or iterator. /// /// We generally do a poor job modeling most containers right now, and would -/// prefer not to inline their methods. +/// prefer not to inline their setup and teardown. static bool isContainerCtorOrDtor(const ASTContext &Ctx, const FunctionDecl *FD) { - // Heuristic: a type is a container if it contains a "begin()" method - // or a type named "iterator". if (!(isa(FD) || isa(FD))) return false; diff --git a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h index eee0e31a6f80..6e434a04b23d 100644 --- a/clang/test/Analysis/Inputs/system-header-simulator-cxx.h +++ b/clang/test/Analysis/Inputs/system-header-simulator-cxx.h @@ -80,6 +80,12 @@ namespace std { *OI++ = *II++; return OI; } + + struct input_iterator_tag { }; + struct output_iterator_tag { }; + struct forward_iterator_tag : public input_iterator_tag { }; + struct bidirectional_iterator_tag : public forward_iterator_tag { }; + struct random_access_iterator_tag : public bidirectional_iterator_tag { }; } void* operator new(std::size_t, const std::nothrow_t&) throw(); diff --git a/clang/test/Analysis/inlining/containers.cpp b/clang/test/Analysis/inlining/containers.cpp index 4500dff6dcf2..73b2957ad6de 100644 --- a/clang/test/Analysis/inlining/containers.cpp +++ b/clang/test/Analysis/inlining/containers.cpp @@ -78,7 +78,9 @@ void testWrappers(BeginOnlySet &w1, IteratorStructOnlySet &w2, } -#else +#else // HEADER + +#include "../Inputs/system-header-simulator-cxx.h" class MySet { int *storage; @@ -152,8 +154,13 @@ class BeginOnlySet { public: struct IterImpl { MySet::iterator impl; + typedef std::forward_iterator_tag iterator_category; + IterImpl(MySet::iterator i) : impl(i) { - clang_analyzer_checkInlined(true); // expected-warning {{TRUE}} + clang_analyzer_checkInlined(true); +#if INLINE + // expected-warning@-2 {{TRUE}} +#endif } }; @@ -231,4 +238,4 @@ public: } }; -#endif +#endif // HEADER