1*3605d9a4SNicolas van Kempen // RUN: %check_clang_tidy -std=c++11-or-later %s readability-container-contains %t 289a1d03eSRichard 389a1d03eSRichard // Some *very* simplified versions of `map` etc. 489a1d03eSRichard namespace std { 589a1d03eSRichard 689a1d03eSRichard template <class Key, class T> 789a1d03eSRichard struct map { 8*3605d9a4SNicolas van Kempen struct iterator { 9*3605d9a4SNicolas van Kempen bool operator==(const iterator &Other) const; 10*3605d9a4SNicolas van Kempen bool operator!=(const iterator &Other) const; 11*3605d9a4SNicolas van Kempen }; 12*3605d9a4SNicolas van Kempen 1389a1d03eSRichard unsigned count(const Key &K) const; 1489a1d03eSRichard bool contains(const Key &K) const; 15*3605d9a4SNicolas van Kempen iterator find(const Key &K); 16*3605d9a4SNicolas van Kempen iterator end(); 1789a1d03eSRichard }; 1889a1d03eSRichard 1989a1d03eSRichard template <class Key> 2089a1d03eSRichard struct set { 2189a1d03eSRichard unsigned count(const Key &K) const; 2289a1d03eSRichard bool contains(const Key &K) const; 2389a1d03eSRichard }; 2489a1d03eSRichard 2589a1d03eSRichard template <class Key> 2689a1d03eSRichard struct unordered_set { 2789a1d03eSRichard unsigned count(const Key &K) const; 2889a1d03eSRichard bool contains(const Key &K) const; 2989a1d03eSRichard }; 3089a1d03eSRichard 3189a1d03eSRichard template <class Key, class T> 3289a1d03eSRichard struct multimap { 3389a1d03eSRichard unsigned count(const Key &K) const; 3489a1d03eSRichard bool contains(const Key &K) const; 3589a1d03eSRichard }; 3689a1d03eSRichard 3789a1d03eSRichard } // namespace std 3889a1d03eSRichard 3989a1d03eSRichard // Check that we detect various common ways to check for membership 4089a1d03eSRichard int testDifferentCheckTypes(std::map<int, int> &MyMap) { 4189a1d03eSRichard if (MyMap.count(0)) 4289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use 'contains' to check for membership [readability-container-contains] 4389a1d03eSRichard // CHECK-FIXES: if (MyMap.contains(0)) 4489a1d03eSRichard return 1; 4589a1d03eSRichard bool C1 = MyMap.count(1); 4689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use 'contains' to check for membership [readability-container-contains] 4789a1d03eSRichard // CHECK-FIXES: bool C1 = MyMap.contains(1); 4889a1d03eSRichard auto C2 = static_cast<bool>(MyMap.count(1)); 4989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:37: warning: use 'contains' to check for membership [readability-container-contains] 5089a1d03eSRichard // CHECK-FIXES: auto C2 = static_cast<bool>(MyMap.contains(1)); 5189a1d03eSRichard auto C3 = MyMap.count(2) != 0; 5289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use 'contains' to check for membership [readability-container-contains] 5389a1d03eSRichard // CHECK-FIXES: auto C3 = MyMap.contains(2); 5489a1d03eSRichard auto C4 = MyMap.count(3) > 0; 5589a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use 'contains' to check for membership [readability-container-contains] 5689a1d03eSRichard // CHECK-FIXES: auto C4 = MyMap.contains(3); 5789a1d03eSRichard auto C5 = MyMap.count(4) >= 1; 5889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use 'contains' to check for membership [readability-container-contains] 5989a1d03eSRichard // CHECK-FIXES: auto C5 = MyMap.contains(4); 6089a1d03eSRichard auto C6 = MyMap.find(5) != MyMap.end(); 6189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use 'contains' to check for membership [readability-container-contains] 6289a1d03eSRichard // CHECK-FIXES: auto C6 = MyMap.contains(5); 6389a1d03eSRichard return C1 + C2 + C3 + C4 + C5 + C6; 6489a1d03eSRichard } 6589a1d03eSRichard 6689a1d03eSRichard // Check that we detect various common ways to check for non-membership 6789a1d03eSRichard int testNegativeChecks(std::map<int, int> &MyMap) { 6889a1d03eSRichard bool C1 = !MyMap.count(-1); 6989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use 'contains' to check for membership [readability-container-contains] 7089a1d03eSRichard // CHECK-FIXES: bool C1 = !MyMap.contains(-1); 7189a1d03eSRichard auto C2 = MyMap.count(-2) == 0; 7289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use 'contains' to check for membership [readability-container-contains] 7389a1d03eSRichard // CHECK-FIXES: auto C2 = !MyMap.contains(-2); 7489a1d03eSRichard auto C3 = MyMap.count(-3) <= 0; 7589a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use 'contains' to check for membership [readability-container-contains] 7689a1d03eSRichard // CHECK-FIXES: auto C3 = !MyMap.contains(-3); 7789a1d03eSRichard auto C4 = MyMap.count(-4) < 1; 7889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use 'contains' to check for membership [readability-container-contains] 7989a1d03eSRichard // CHECK-FIXES: auto C4 = !MyMap.contains(-4); 8089a1d03eSRichard auto C5 = MyMap.find(-5) == MyMap.end(); 8189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use 'contains' to check for membership [readability-container-contains] 8289a1d03eSRichard // CHECK-FIXES: auto C5 = !MyMap.contains(-5); 8389a1d03eSRichard return C1 + C2 + C3 + C4 + C5; 8489a1d03eSRichard } 8589a1d03eSRichard 8689a1d03eSRichard // Check for various types 8789a1d03eSRichard int testDifferentTypes(std::map<int, int> &M, std::unordered_set<int> &US, std::set<int> &S, std::multimap<int, int> &MM) { 8889a1d03eSRichard bool C1 = M.count(1001); 8989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use 'contains' to check for membership [readability-container-contains] 9089a1d03eSRichard // CHECK-FIXES: bool C1 = M.contains(1001); 9189a1d03eSRichard bool C2 = US.count(1002); 9289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use 'contains' to check for membership [readability-container-contains] 9389a1d03eSRichard // CHECK-FIXES: bool C2 = US.contains(1002); 9489a1d03eSRichard bool C3 = S.count(1003); 9589a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: use 'contains' to check for membership [readability-container-contains] 9689a1d03eSRichard // CHECK-FIXES: bool C3 = S.contains(1003); 9789a1d03eSRichard bool C4 = MM.count(1004); 9889a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: use 'contains' to check for membership [readability-container-contains] 9989a1d03eSRichard // CHECK-FIXES: bool C4 = MM.contains(1004); 10089a1d03eSRichard return C1 + C2 + C3 + C4; 10189a1d03eSRichard } 10289a1d03eSRichard 10389a1d03eSRichard // The check detects all kind of `const`, reference, rvalue-reference and value types. 10489a1d03eSRichard int testQualifiedTypes(std::map<int, int> ValueM, std::map<int, int> &RefM, const std::map<int, int> &ConstRefM, std::map<int, int> &&RValueM) { 10589a1d03eSRichard bool C1 = ValueM.count(2001); 10689a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: use 'contains' to check for membership [readability-container-contains] 10789a1d03eSRichard // CHECK-FIXES: bool C1 = ValueM.contains(2001); 10889a1d03eSRichard bool C2 = RefM.count(2002); 10989a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:18: warning: use 'contains' to check for membership [readability-container-contains] 11089a1d03eSRichard // CHECK-FIXES: bool C2 = RefM.contains(2002); 11189a1d03eSRichard bool C3 = ConstRefM.count(2003); 11289a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: use 'contains' to check for membership [readability-container-contains] 11389a1d03eSRichard // CHECK-FIXES: bool C3 = ConstRefM.contains(2003); 11489a1d03eSRichard bool C4 = RValueM.count(2004); 11589a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: use 'contains' to check for membership [readability-container-contains] 11689a1d03eSRichard // CHECK-FIXES: bool C4 = RValueM.contains(2004); 11789a1d03eSRichard return C1 + C2 + C3 + C4; 11889a1d03eSRichard } 11989a1d03eSRichard 12089a1d03eSRichard // This is effectively a membership check, as the result is implicitly casted 12189a1d03eSRichard // to `bool`. 12289a1d03eSRichard bool returnContains(std::map<int, int> &M) { 12389a1d03eSRichard return M.count(42); 12489a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: use 'contains' to check for membership [readability-container-contains] 12589a1d03eSRichard // CHECK-FIXES: return M.contains(42); 12689a1d03eSRichard } 12789a1d03eSRichard 12889a1d03eSRichard // This returns the actual count and should not be rewritten 12989a1d03eSRichard int actualCount(std::multimap<int, int> &M) { 13089a1d03eSRichard return M.count(21); 13189a1d03eSRichard // NO-WARNING. 13289a1d03eSRichard // CHECK-FIXES: return M.count(21); 13389a1d03eSRichard } 13489a1d03eSRichard 13589a1d03eSRichard // Check that we are not confused by aliases 13689a1d03eSRichard namespace s2 = std; 13789a1d03eSRichard using MyMapT = s2::map<int, int>; 13889a1d03eSRichard int typeAliases(MyMapT &MyMap) { 13989a1d03eSRichard bool C1 = MyMap.count(99); 14089a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use 'contains' to check for membership [readability-container-contains] 14189a1d03eSRichard // CHECK-FIXES: bool C1 = MyMap.contains(99); 14289a1d03eSRichard return C1; 14389a1d03eSRichard } 14489a1d03eSRichard 14589a1d03eSRichard // Check that the tests also trigger for a local variable and not only for 14689a1d03eSRichard // function arguments. 14789a1d03eSRichard bool localVar() { 14889a1d03eSRichard using namespace std; 14989a1d03eSRichard map<int, int> LocalM; 15089a1d03eSRichard return LocalM.count(42); 15189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:17: warning: use 'contains' to check for membership [readability-container-contains] 15289a1d03eSRichard // CHECK-FIXES: return LocalM.contains(42); 15389a1d03eSRichard } 15489a1d03eSRichard 15589a1d03eSRichard // Check various usages of an actual `count` which isn't rewritten 15689a1d03eSRichard int nonRewrittenCount(std::multimap<int, int> &MyMap) { 15789a1d03eSRichard // This is an actual test if we have at least 2 usages. Shouldn't be rewritten. 15889a1d03eSRichard bool C1 = MyMap.count(1) >= 2; 15989a1d03eSRichard // NO-WARNING. 16089a1d03eSRichard // CHECK-FIXES: bool C1 = MyMap.count(1) >= 2; 16189a1d03eSRichard 16289a1d03eSRichard // "< 0" makes little sense and is always `false`. Still, let's ensure we 16389a1d03eSRichard // don't accidentally rewrite it to 'contains'. 16489a1d03eSRichard bool C2 = MyMap.count(2) < 0; 16589a1d03eSRichard // NO-WARNING. 16689a1d03eSRichard // CHECK-FIXES: bool C2 = MyMap.count(2) < 0; 16789a1d03eSRichard 16889a1d03eSRichard // The `count` is used in some more complicated formula. 16989a1d03eSRichard bool C3 = MyMap.count(1) + MyMap.count(2) * 2 + MyMap.count(3) / 3 >= 20; 17089a1d03eSRichard // NO-WARNING. 17189a1d03eSRichard // CHECK-FIXES: bool C3 = MyMap.count(1) + MyMap.count(2) * 2 + MyMap.count(3) / 3 >= 20; 17289a1d03eSRichard 17389a1d03eSRichard // This could theoretically be rewritten into a 'contains' after removig the 17489a1d03eSRichard // `4` on both sides of the comparison. For the time being, we don't detect 17589a1d03eSRichard // this case. 17689a1d03eSRichard bool C4 = MyMap.count(1) + 4 > 4; 17789a1d03eSRichard // NO-WARNING. 17889a1d03eSRichard // CHECK-FIXES: bool C4 = MyMap.count(1) + 4 > 4; 17989a1d03eSRichard 18089a1d03eSRichard return C1 + C2 + C3 + C4; 18189a1d03eSRichard } 18289a1d03eSRichard 1838ac84a95SThomas Schenker // Check different integer literal suffixes 1848ac84a95SThomas Schenker int testDifferentIntegerLiteralSuffixes(std::map<int, int> &MyMap) { 1858ac84a95SThomas Schenker 1868ac84a95SThomas Schenker auto C1 = MyMap.count(2) != 0U; 1878ac84a95SThomas Schenker // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use 'contains' to check for membership [readability-container-contains] 1888ac84a95SThomas Schenker // CHECK-FIXES: auto C1 = MyMap.contains(2); 1898ac84a95SThomas Schenker auto C2 = MyMap.count(2) != 0UL; 1908ac84a95SThomas Schenker // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use 'contains' to check for membership [readability-container-contains] 1918ac84a95SThomas Schenker // CHECK-FIXES: auto C2 = MyMap.contains(2); 1928ac84a95SThomas Schenker auto C3 = 0U != MyMap.count(2); 1938ac84a95SThomas Schenker // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use 'contains' to check for membership [readability-container-contains] 1948ac84a95SThomas Schenker // CHECK-FIXES: auto C3 = MyMap.contains(2); 1958ac84a95SThomas Schenker auto C4 = 0UL != MyMap.count(2); 1968ac84a95SThomas Schenker // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: use 'contains' to check for membership [readability-container-contains] 1978ac84a95SThomas Schenker // CHECK-FIXES: auto C4 = MyMap.contains(2); 1988ac84a95SThomas Schenker auto C5 = MyMap.count(2) < 1U; 1998ac84a95SThomas Schenker // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use 'contains' to check for membership [readability-container-contains] 2008ac84a95SThomas Schenker // CHECK-FIXES: auto C5 = !MyMap.contains(2); 2018ac84a95SThomas Schenker auto C6 = MyMap.count(2) < 1UL; 2028ac84a95SThomas Schenker // CHECK-MESSAGES: :[[@LINE-1]]:19: warning: use 'contains' to check for membership [readability-container-contains] 2038ac84a95SThomas Schenker // CHECK-FIXES: auto C6 = !MyMap.contains(2); 2048ac84a95SThomas Schenker auto C7 = 1U > MyMap.count(2); 2058ac84a95SThomas Schenker // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: use 'contains' to check for membership [readability-container-contains] 2068ac84a95SThomas Schenker // CHECK-FIXES: auto C7 = !MyMap.contains(2); 2078ac84a95SThomas Schenker auto C8 = 1UL > MyMap.count(2); 2088ac84a95SThomas Schenker // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: use 'contains' to check for membership [readability-container-contains] 2098ac84a95SThomas Schenker // CHECK-FIXES: auto C8 = !MyMap.contains(2); 2108ac84a95SThomas Schenker 2118ac84a95SThomas Schenker return C1 + C2 + C3 + C4 + C5 + C6 + C7 + C8; 2128ac84a95SThomas Schenker } 2138ac84a95SThomas Schenker 21489a1d03eSRichard // We don't want to rewrite if the `contains` call is from a macro expansion 21589a1d03eSRichard int testMacroExpansion(std::unordered_set<int> &MySet) { 21689a1d03eSRichard #define COUNT_ONES(SET) SET.count(1) 21789a1d03eSRichard // Rewriting the macro would break the code 21889a1d03eSRichard // CHECK-FIXES: #define COUNT_ONES(SET) SET.count(1) 21989a1d03eSRichard // We still want to warn the user even if we don't offer a fixit 22089a1d03eSRichard if (COUNT_ONES(MySet)) { 22189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: use 'contains' to check for membership [readability-container-contains] 22289a1d03eSRichard // CHECK-MESSAGES: note: expanded from macro 'COUNT_ONES' 22389a1d03eSRichard return COUNT_ONES(MySet); 22489a1d03eSRichard } 22589a1d03eSRichard #undef COUNT_ONES 22689a1d03eSRichard #define COUNT_ONES count(1) 22789a1d03eSRichard // Rewriting the macro would break the code 22889a1d03eSRichard // CHECK-FIXES: #define COUNT_ONES count(1) 22989a1d03eSRichard // We still want to warn the user even if we don't offer a fixit 23089a1d03eSRichard if (MySet.COUNT_ONES) { 23189a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:13: warning: use 'contains' to check for membership [readability-container-contains] 23289a1d03eSRichard // CHECK-MESSAGES: note: expanded from macro 'COUNT_ONES' 23389a1d03eSRichard return MySet.COUNT_ONES; 23489a1d03eSRichard } 23589a1d03eSRichard #undef COUNT_ONES 23689a1d03eSRichard #define MY_SET MySet 23789a1d03eSRichard // CHECK-FIXES: #define MY_SET MySet 23889a1d03eSRichard // We still want to rewrite one of the two calls to `count` 23989a1d03eSRichard if (MY_SET.count(1)) { 24089a1d03eSRichard // CHECK-MESSAGES: :[[@LINE-1]]:14: warning: use 'contains' to check for membership [readability-container-contains] 24189a1d03eSRichard // CHECK-FIXES: if (MY_SET.contains(1)) { 24289a1d03eSRichard return MY_SET.count(1); 24389a1d03eSRichard } 24489a1d03eSRichard #undef MY_SET 24589a1d03eSRichard return 0; 24689a1d03eSRichard } 24789a1d03eSRichard 2481be4c971SNicolas van Kempen // The following map has the same interface as `std::map`. 24989a1d03eSRichard template <class Key, class T> 25089a1d03eSRichard struct CustomMap { 25189a1d03eSRichard unsigned count(const Key &K) const; 25289a1d03eSRichard bool contains(const Key &K) const; 25389a1d03eSRichard void *find(const Key &K); 25489a1d03eSRichard void *end(); 25589a1d03eSRichard }; 25689a1d03eSRichard 2571be4c971SNicolas van Kempen void testDifferentCheckTypes(CustomMap<int, int> &MyMap) { 2581be4c971SNicolas van Kempen if (MyMap.count(0)) {}; 2591be4c971SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 2601be4c971SNicolas van Kempen // CHECK-FIXES: if (MyMap.contains(0)) {}; 2611be4c971SNicolas van Kempen 2621be4c971SNicolas van Kempen MyMap.find(0) != MyMap.end(); 2631be4c971SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 2641be4c971SNicolas van Kempen // CHECK-FIXES: MyMap.contains(0); 2651be4c971SNicolas van Kempen } 2661be4c971SNicolas van Kempen 2671be4c971SNicolas van Kempen struct MySubmap : public CustomMap<int, int> {}; 2681be4c971SNicolas van Kempen 2691be4c971SNicolas van Kempen void testSubclass(MySubmap& MyMap) { 2701be4c971SNicolas van Kempen if (MyMap.count(0)) {}; 2711be4c971SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 2721be4c971SNicolas van Kempen // CHECK-FIXES: if (MyMap.contains(0)) {}; 2731be4c971SNicolas van Kempen } 2741be4c971SNicolas van Kempen 2751be4c971SNicolas van Kempen using UsingMap = CustomMap<int, int>; 2761be4c971SNicolas van Kempen struct MySubmap2 : public UsingMap {}; 2771be4c971SNicolas van Kempen using UsingMap2 = MySubmap2; 2781be4c971SNicolas van Kempen 2791be4c971SNicolas van Kempen void testUsing(UsingMap2& MyMap) { 2801be4c971SNicolas van Kempen if (MyMap.count(0)) {}; 2811be4c971SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 2821be4c971SNicolas van Kempen // CHECK-FIXES: if (MyMap.contains(0)) {}; 2831be4c971SNicolas van Kempen } 2841be4c971SNicolas van Kempen 2851be4c971SNicolas van Kempen template <class Key, class T> 2861be4c971SNicolas van Kempen struct CustomMapContainsDeleted { 2871be4c971SNicolas van Kempen unsigned count(const Key &K) const; 2881be4c971SNicolas van Kempen bool contains(const Key &K) const = delete; 2891be4c971SNicolas van Kempen void *find(const Key &K); 2901be4c971SNicolas van Kempen void *end(); 2911be4c971SNicolas van Kempen }; 2921be4c971SNicolas van Kempen 2931be4c971SNicolas van Kempen struct SubmapContainsDeleted : public CustomMapContainsDeleted<int, int> {}; 2941be4c971SNicolas van Kempen 2951be4c971SNicolas van Kempen void testContainsDeleted(CustomMapContainsDeleted<int, int> &MyMap, 2961be4c971SNicolas van Kempen SubmapContainsDeleted &MyMap2) { 2971be4c971SNicolas van Kempen // No warning if the `contains` method is deleted. 2981be4c971SNicolas van Kempen if (MyMap.count(0)) {}; 2991be4c971SNicolas van Kempen if (MyMap2.count(0)) {}; 3001be4c971SNicolas van Kempen } 3011be4c971SNicolas van Kempen 3021be4c971SNicolas van Kempen template <class Key, class T> 3031be4c971SNicolas van Kempen struct CustomMapPrivateContains { 3041be4c971SNicolas van Kempen unsigned count(const Key &K) const; 3051be4c971SNicolas van Kempen void *find(const Key &K); 3061be4c971SNicolas van Kempen void *end(); 3071be4c971SNicolas van Kempen 3081be4c971SNicolas van Kempen private: 3091be4c971SNicolas van Kempen bool contains(const Key &K) const; 3101be4c971SNicolas van Kempen }; 3111be4c971SNicolas van Kempen 3121be4c971SNicolas van Kempen struct SubmapPrivateContains : public CustomMapPrivateContains<int, int> {}; 3131be4c971SNicolas van Kempen 3141be4c971SNicolas van Kempen void testPrivateContains(CustomMapPrivateContains<int, int> &MyMap, 3151be4c971SNicolas van Kempen SubmapPrivateContains &MyMap2) { 3161be4c971SNicolas van Kempen // No warning if the `contains` method is not public. 3171be4c971SNicolas van Kempen if (MyMap.count(0)) {}; 3181be4c971SNicolas van Kempen if (MyMap2.count(0)) {}; 3191be4c971SNicolas van Kempen } 3201be4c971SNicolas van Kempen 3211be4c971SNicolas van Kempen struct MyString {}; 3221be4c971SNicolas van Kempen 3231be4c971SNicolas van Kempen struct WeirdNonMatchingContains { 3241be4c971SNicolas van Kempen unsigned count(char) const; 3251be4c971SNicolas van Kempen bool contains(const MyString&) const; 3261be4c971SNicolas van Kempen }; 3271be4c971SNicolas van Kempen 3281be4c971SNicolas van Kempen void testWeirdNonMatchingContains(WeirdNonMatchingContains &MyMap) { 3291be4c971SNicolas van Kempen // No warning if there is no `contains` method with the right type. 3301be4c971SNicolas van Kempen if (MyMap.count('a')) {}; 3311be4c971SNicolas van Kempen } 3321be4c971SNicolas van Kempen 3331be4c971SNicolas van Kempen template <class T> 3341be4c971SNicolas van Kempen struct SmallPtrSet { 3351be4c971SNicolas van Kempen using ConstPtrType = const T*; 3361be4c971SNicolas van Kempen unsigned count(ConstPtrType Ptr) const; 3371be4c971SNicolas van Kempen bool contains(ConstPtrType Ptr) const; 3381be4c971SNicolas van Kempen }; 3391be4c971SNicolas van Kempen 3401be4c971SNicolas van Kempen template <class T> 3411be4c971SNicolas van Kempen struct SmallPtrPtrSet { 3421be4c971SNicolas van Kempen using ConstPtrType = const T**; 3431be4c971SNicolas van Kempen unsigned count(ConstPtrType Ptr) const; 3441be4c971SNicolas van Kempen bool contains(ConstPtrType Ptr) const; 3451be4c971SNicolas van Kempen }; 3461be4c971SNicolas van Kempen 3471be4c971SNicolas van Kempen template <class T> 3481be4c971SNicolas van Kempen struct SmallPtrPtrPtrSet { 3491be4c971SNicolas van Kempen using ConstPtrType = const T***; 3501be4c971SNicolas van Kempen unsigned count(ConstPtrType Ptr) const; 3511be4c971SNicolas van Kempen bool contains(ConstPtrType Ptr) const; 3521be4c971SNicolas van Kempen }; 3531be4c971SNicolas van Kempen 3541be4c971SNicolas van Kempen void testSmallPtrSet(const int ***Ptr, 3551be4c971SNicolas van Kempen SmallPtrSet<int> &MySet, 3561be4c971SNicolas van Kempen SmallPtrPtrSet<int> &MySet2, 3571be4c971SNicolas van Kempen SmallPtrPtrPtrSet<int> &MySet3) { 3581be4c971SNicolas van Kempen if (MySet.count(**Ptr)) {}; 3591be4c971SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 3601be4c971SNicolas van Kempen // CHECK-FIXES: if (MySet.contains(**Ptr)) {}; 3611be4c971SNicolas van Kempen if (MySet2.count(*Ptr)) {}; 3621be4c971SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 3631be4c971SNicolas van Kempen // CHECK-FIXES: if (MySet2.contains(*Ptr)) {}; 3641be4c971SNicolas van Kempen if (MySet3.count(Ptr)) {}; 3651be4c971SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 3661be4c971SNicolas van Kempen // CHECK-FIXES: if (MySet3.contains(Ptr)) {}; 3671be4c971SNicolas van Kempen } 3681be4c971SNicolas van Kempen 3691be4c971SNicolas van Kempen struct X {}; 3701be4c971SNicolas van Kempen struct Y : public X {}; 3711be4c971SNicolas van Kempen 3721be4c971SNicolas van Kempen void testSubclassEntry(SmallPtrSet<X>& Set, Y* Entry) { 3731be4c971SNicolas van Kempen if (Set.count(Entry)) {} 3741be4c971SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 3751be4c971SNicolas van Kempen // CHECK-FIXES: if (Set.contains(Entry)) {} 3761be4c971SNicolas van Kempen } 3771be4c971SNicolas van Kempen 3781be4c971SNicolas van Kempen struct WeirdPointerApi { 3791be4c971SNicolas van Kempen unsigned count(int** Ptr) const; 3801be4c971SNicolas van Kempen bool contains(int* Ptr) const; 3811be4c971SNicolas van Kempen }; 3821be4c971SNicolas van Kempen 3831be4c971SNicolas van Kempen void testWeirdApi(WeirdPointerApi& Set, int* E) { 3841be4c971SNicolas van Kempen if (Set.count(&E)) {} 3851be4c971SNicolas van Kempen } 3861be4c971SNicolas van Kempen 3871be4c971SNicolas van Kempen void testIntUnsigned(std::set<int>& S, unsigned U) { 3881be4c971SNicolas van Kempen if (S.count(U)) {} 3891be4c971SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 3901be4c971SNicolas van Kempen // CHECK-FIXES: if (S.contains(U)) {} 3911be4c971SNicolas van Kempen } 3921be4c971SNicolas van Kempen 3931be4c971SNicolas van Kempen template <class T> 3941be4c971SNicolas van Kempen struct CustomSetConvertible { 3951be4c971SNicolas van Kempen unsigned count(const T &K) const; 3961be4c971SNicolas van Kempen bool contains(const T &K) const; 3971be4c971SNicolas van Kempen }; 3981be4c971SNicolas van Kempen 3991be4c971SNicolas van Kempen struct A {}; 4001be4c971SNicolas van Kempen struct B { B() = default; B(const A&) {} }; 4011be4c971SNicolas van Kempen struct C { operator A() const; }; 4021be4c971SNicolas van Kempen 4031be4c971SNicolas van Kempen void testConvertibleTypes() { 4041be4c971SNicolas van Kempen CustomSetConvertible<B> MyMap; 4051be4c971SNicolas van Kempen if (MyMap.count(A())) {}; 4061be4c971SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 4071be4c971SNicolas van Kempen // CHECK-FIXES: if (MyMap.contains(A())) {}; 4081be4c971SNicolas van Kempen 4091be4c971SNicolas van Kempen CustomSetConvertible<A> MyMap2; 4101be4c971SNicolas van Kempen if (MyMap2.count(C())) {}; 4111be4c971SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 4121be4c971SNicolas van Kempen // CHECK-FIXES: if (MyMap2.contains(C())) {}; 4131be4c971SNicolas van Kempen 4141be4c971SNicolas van Kempen if (MyMap2.count(C()) != 0) {}; 4151be4c971SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 4161be4c971SNicolas van Kempen // CHECK-FIXES: if (MyMap2.contains(C())) {}; 4171be4c971SNicolas van Kempen } 4181be4c971SNicolas van Kempen 4191be4c971SNicolas van Kempen template<class U> 4201be4c971SNicolas van Kempen using Box = const U& ; 4211be4c971SNicolas van Kempen 4221be4c971SNicolas van Kempen template <class T> 4231be4c971SNicolas van Kempen struct CustomBoxedSet { 4241be4c971SNicolas van Kempen unsigned count(Box<T> K) const; 4251be4c971SNicolas van Kempen bool contains(Box<T> K) const; 4261be4c971SNicolas van Kempen }; 4271be4c971SNicolas van Kempen 4281be4c971SNicolas van Kempen void testBox() { 4291be4c971SNicolas van Kempen CustomBoxedSet<int> Set; 4301be4c971SNicolas van Kempen if (Set.count(0)) {}; 4311be4c971SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 4321be4c971SNicolas van Kempen // CHECK-FIXES: if (Set.contains(0)) {}; 43389a1d03eSRichard } 43414c76321SNicolas van Kempen 43514c76321SNicolas van Kempen void testOperandPermutations(std::map<int, int>& Map) { 43614c76321SNicolas van Kempen if (Map.count(0) != 0) {}; 43714c76321SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 43814c76321SNicolas van Kempen // CHECK-FIXES: if (Map.contains(0)) {}; 43914c76321SNicolas van Kempen if (0 != Map.count(0)) {}; 44014c76321SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 44114c76321SNicolas van Kempen // CHECK-FIXES: if (Map.contains(0)) {}; 44214c76321SNicolas van Kempen if (Map.count(0) == 0) {}; 44314c76321SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 44414c76321SNicolas van Kempen // CHECK-FIXES: if (!Map.contains(0)) {}; 44514c76321SNicolas van Kempen if (0 == Map.count(0)) {}; 44614c76321SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 44714c76321SNicolas van Kempen // CHECK-FIXES: if (!Map.contains(0)) {}; 44814c76321SNicolas van Kempen if (Map.find(0) != Map.end()) {}; 44914c76321SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 45014c76321SNicolas van Kempen // CHECK-FIXES: if (Map.contains(0)) {}; 45114c76321SNicolas van Kempen if (Map.end() != Map.find(0)) {}; 45214c76321SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 45314c76321SNicolas van Kempen // CHECK-FIXES: if (Map.contains(0)) {}; 45414c76321SNicolas van Kempen if (Map.find(0) == Map.end()) {}; 45514c76321SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 45614c76321SNicolas van Kempen // CHECK-FIXES: if (!Map.contains(0)) {}; 45714c76321SNicolas van Kempen if (Map.end() == Map.find(0)) {}; 45814c76321SNicolas van Kempen // CHECK-MESSAGES: :[[@LINE-1]]:{{[0-9]+}}: warning: use 'contains' to check for membership [readability-container-contains] 45914c76321SNicolas van Kempen // CHECK-FIXES: if (!Map.contains(0)) {}; 46014c76321SNicolas van Kempen } 461