Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h =================================================================== --- clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -262,6 +262,10 @@ /// calls. bool isCalled(const CallDescription &CD) const; + /// \returns Whether the \p CD describing the same number of arguments and + /// parameters of the current call. + bool isEqualArgsAndParams(const CallDescription &CD) const; + /// Returns true whether the CallEvent is any of the CallDescriptions supplied /// as a parameter. template @@ -1191,6 +1195,7 @@ std::vector QualifiedName; Optional RequiredArgs; Optional RequiredParams; + Optional OOKind; int Flags; // A constructor helper. @@ -1216,10 +1221,11 @@ /// name regardless the number of arguments. CallDescription(int Flags, ArrayRef QualifiedName, Optional RequiredArgs = None, - Optional RequiredParams = None) + Optional RequiredParams = None, + Optional OOKind = None) : QualifiedName(QualifiedName), RequiredArgs(RequiredArgs), RequiredParams(readRequiredParams(RequiredArgs, RequiredParams)), - Flags(Flags) {} + OOKind(OOKind), Flags(Flags) {} /// Construct a CallDescription with default flags. CallDescription(ArrayRef QualifiedName, @@ -1227,6 +1233,12 @@ Optional RequiredParams = None) : CallDescription(0, QualifiedName, RequiredArgs, RequiredParams) {} + /// Construct for CXXOperatorCallExpr using OverloadedOperatorKind. + CallDescription(OverloadedOperatorKind OOKind, + Optional RequiredArgs = None, + Optional RequiredParams = None) + : CallDescription(0, "", RequiredArgs, RequiredParams, OOKind) {} + /// Get the name of the function that this object matches. StringRef getFunctionName() const { return QualifiedName.back(); } }; Index: clang/lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- clang/lib/StaticAnalyzer/Core/CallEvent.cpp +++ clang/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -355,6 +355,11 @@ return PostImplicitCall(D, Loc, getLocationContext(), Tag); } +bool CallEvent::isEqualArgsAndParams(const CallDescription &CD) const { + return (!CD.RequiredArgs || CD.RequiredArgs == getNumArgs()) && + (!CD.RequiredParams || CD.RequiredParams == parameters().size()); +} + bool CallEvent::isCalled(const CallDescription &CD) const { // FIXME: Add ObjC Message support. if (getKind() == CE_ObjCMessage) @@ -371,6 +376,14 @@ return false; } + if (CD.OOKind) { + if (const FunctionDecl *FD = dyn_cast(getDecl())) + if (*CD.OOKind == FD->getOverloadedOperator()) + return isEqualArgsAndParams(CD); + + return false; + } + if (!CD.IsLookupDone) { CD.IsLookupDone = true; CD.II = &getState()->getStateManager().getContext().Idents.get( @@ -416,8 +429,7 @@ return false; } - return (!CD.RequiredArgs || CD.RequiredArgs == getNumArgs()) && - (!CD.RequiredParams || CD.RequiredParams == parameters().size()); + return isEqualArgsAndParams(CD); } SVal CallEvent::getArgSVal(unsigned Index) const { Index: clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp =================================================================== --- clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp +++ clang/unittests/StaticAnalyzer/CallDescriptionTest.cpp @@ -225,6 +225,46 @@ "}")); } +TEST(CallDescriptionMap, CXXOperatorCallExpr) { + EXPECT_TRUE(tooling::runToolOnCode( + std::unique_ptr(new CallDescriptionAction({ + {OO_Plus, false}, + {OO_GreaterGreater, true}, + })), + "namespace std {" + " template class basic_istream{};" + " template " + " basic_istream &operator>>(basic_istream &st, CharT *ch);" + " typedef basic_istream istream;" + " extern istream cin;" + "}" + "void foo() {" + " using namespace std;" + " char buf[13];" + " std::cin >> buf;" + "}")); +} + +TEST(CallDescriptionMap, CXXOperatorCallExprArgumentCount) { + EXPECT_TRUE(tooling::runToolOnCode( + std::unique_ptr(new CallDescriptionAction({ + {{OO_GreaterGreater, 1}, false}, + {{OO_GreaterGreater, 2}, true}, + })), + "namespace std {" + " template class basic_istream{};" + " template " + " basic_istream &operator>>(basic_istream &st, CharT *ch);" + " typedef basic_istream istream;" + " extern istream cin;" + "}" + "void foo() {" + " using namespace std;" + " char buf[13];" + " std::cin >> buf;" + "}")); +} + } // namespace } // namespace ento } // namespace clang