diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 3cafdd09f..862f9ff25 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1727,6 +1727,9 @@ bool Tokenizer::tokenize(std::istream &code, // remove unnecessary member qualification.. removeUnnecessaryQualification(); + // Add std:: in front of std classes, when using namespace std; was given + simplifyNamespaceStd(); + // remove Microsoft MFC.. simplifyMicrosoftMFC(); @@ -2698,7 +2701,7 @@ void Tokenizer::setVarId() (tok->isName() && tok->str().at(tok->str().length()-1U) == ':')) { // No variable declarations in sizeof - if (Token::Match(tok->previous(), "sizeof (")) { + if (Token::simpleMatch(tok->previous(), "sizeof (")) { continue; } @@ -5889,7 +5892,7 @@ bool Tokenizer::simplifyKnownVariablesGetData(unsigned int varid, Token **_tok2, Token *tok2 = *_tok2; Token *tok3 = *_tok3; - if (Token::Match(tok2->tokAt(-2), "for (")) { + if (Token::simpleMatch(tok2->tokAt(-2), "for (")) { // only specific for loops is handled if (!Token::Match(tok2, "%varid% = %num% ; %varid% <|<= %num% ; ++| %varid% ++| ) {", varid)) return false; @@ -8551,6 +8554,73 @@ void Tokenizer::simplifyBuiltinExpect() } +// Add std:: in front of std classes, when using namespace std; was given +void Tokenizer::simplifyNamespaceStd() +{ + if (!isCPP()) + return; + + static const char* stdTypes_[] = { // Types and objects in std namespace that are neither functions nor templates + "string", "wstring", + "iostream", "ostream", "ofstream", "ostringstream", "istream", "ifstream", "istringstream", "fstream", "stringstream", + "stringbuf", "streambuf", "ios", "filebuf", "ios_base", + "exception", "bad_exception", + "logic_error", "domain_error", "invalid_argument_", "length_error", "out_of_rage", "runtime_error", "range_error", "overflow_error", "underflow_error", + "locale", + "cout", "cerr", "clog", "cin", + "fpos", "streamoff", "streampos", "streamsize" + }; + static const std::set stdTypes(stdTypes_, stdTypes_+sizeof(stdTypes_)/sizeof(*stdTypes_)); + static const char* stdTemplates_[] = { + "basic_string", "bitset", "deque", "list", "map", "multimap", "priority_queue", "queue", "set", "stack", "vector", "pair", + "iterator", "iterator_traits" + }; + static const std::set stdTemplates(stdTemplates_, stdTemplates_+sizeof(stdTemplates_)/sizeof(*stdTemplates_)); + static const char* stdFunctions_[] = { + "getline", + "for_each", "find", "find_if", "find_end", "find_first_of", "adjacent_find", "count", "count_if", "mismatch", "equal", "search", "search_n", + "copy", "copy_backward", "swap", "swap_ranges", "iter_swap", "transform", "replace", "replace_if", "replace_copy", "replace_copy_if", "fill", "fill_n", "generate", "generate_n", "remove", + "remove_if", "remove_copy", "remove_copy_if", "unique", "unique_copy", "reverse", "reverse_copy", "rotate", "rotate_copy", "random_shuffle", "partition", "stable_partition", + "sort", "stable_sort", "partial_sort", "partial_sort_copy", "nth_element", "lower_bound", "upper_bound", "equal_range", "binary_search", "merge", "inplace_merge", "includes", + "set_union", "set_intersection", "set_difference", "set_symmetric_difference", "push_heap", "pop_heap", "make_heap", "sort_heap", + "min", "max", "min_element", "max_element", "lexicographical_compare", "next_permutation", "prev_permutation", + "advance", "back_inserter", "distance", "front_inserter", "inserter", + "make_pair" + }; + static const std::set stdFunctions(stdFunctions_, stdFunctions_+sizeof(stdFunctions_)/sizeof(*stdFunctions_)); + + for (Token* tok = const_cast(Token::findsimplematch(list.front(), "using namespace std ;")); tok; tok = tok->next()) { + bool insert = false; + if (Token::Match(tok, "%var% (") && !Token::Match(tok->previous(), ".|::") && stdFunctions.find(tok->str()) != stdFunctions.end()) + insert = true; + else if (Token::Match(tok, "%var% <") && !Token::Match(tok->previous(), ".|::") && stdTemplates.find(tok->str()) != stdTemplates.end()) + insert = true; + else if (tok->isName() && !Token::Match(tok->next(), "(|<") && !Token::Match(tok->previous(), ".|::") && stdTypes.find(tok->str()) != stdTypes.end()) + insert = true; + + if (insert) { + tok->previous()->insertToken("std"); + tok->previous()->linenr(tok->linenr()); // For stylistic reasons we put the std:: in the same line as the following token + tok->previous()->fileIndex(tok->fileIndex()); + tok->previous()->insertToken("::"); + } + + else if (_settings->standards.cpp11 && Token::Match(tok, "!!:: tr1 ::")) + tok->next()->str("std"); + } + + for (Token* tok = list.front(); tok; tok = tok->next()) { + if (_settings->standards.cpp11 && Token::Match(tok, "std :: tr1 ::")) + Token::eraseTokens(tok, tok->tokAt(3)); + + else if (Token::Match(tok, "using namespace std ;")) { + Token::eraseTokens(tok, tok->tokAt(4)); + tok->deleteThis(); + } + } +} + + // Remove Microsoft MFC 'DECLARE_MESSAGE_MAP()' void Tokenizer::simplifyMicrosoftMFC() { diff --git a/lib/tokenize.h b/lib/tokenize.h index 26fe340e9..2cb0bc424 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -608,6 +608,11 @@ public: */ void unnecessaryQualificationError(const Token *tok, const std::string &qualification) const; + /** + * Add std:: in front of std classes, when using namespace std; was given + */ + void simplifyNamespaceStd(); + /** * Remove Microsoft MFC 'DECLARE_MESSAGE_MAP()' */ diff --git a/test/testsimplifytokens.cpp b/test/testsimplifytokens.cpp index 466a1c7eb..9e6641033 100644 --- a/test/testsimplifytokens.cpp +++ b/test/testsimplifytokens.cpp @@ -2316,7 +2316,7 @@ private: { const char code[] = "using namespace std; namespace a{ namespace b{ void f(){} } }"; - const std::string expected("using namespace std ; namespace a { namespace b { void f ( ) { } } }"); + const std::string expected("namespace a { namespace b { void f ( ) { } } }"); ASSERT_EQUALS(expected, tok(code)); } diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 2b9d87646..ef4683787 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -387,6 +387,8 @@ private: TEST_CASE(bitfields12); // ticket #3485 (segmentation fault) TEST_CASE(bitfields13); // ticket #3502 (segmentation fault) + TEST_CASE(simplifyNamespaceStd); + TEST_CASE(microsoftMFC); TEST_CASE(microsoftMemory); @@ -433,12 +435,13 @@ private: TEST_CASE(platformUnix64); } - std::string tokenizeAndStringify(const char code[], bool simplify = false, bool expand = true, Settings::PlatformType platform = Settings::Unspecified, const char* filename = "test.cpp") { + std::string tokenizeAndStringify(const char code[], bool simplify = false, bool expand = true, Settings::PlatformType platform = Settings::Unspecified, const char* filename = "test.cpp", bool cpp11 = false) { errout.str(""); Settings settings; settings.debugwarnings = true; settings.platform(platform); + settings.standards.cpp11 = cpp11; // tokenize.. Tokenizer tokenizer(&settings, this); @@ -6180,6 +6183,48 @@ private: ASSERT_EQUALS("x y ;", tokenizeAndStringify("struct{x y:};\n",false)); } + void simplifyNamespaceStd() { + static const char code1[] = "map m;"; // namespace std is not used + ASSERT_EQUALS("map < foo , bar > m ;", tokenizeAndStringify(code1, false)); + + static const char code2[] = "using namespace std;\n" + "map m;"; + ASSERT_EQUALS("std :: map < foo , bar > m ;", tokenizeAndStringify(code2, false)); + + static const char code3[] = "using namespace std;\n" + "string s;"; + ASSERT_EQUALS("std :: string s ;", tokenizeAndStringify(code3, false)); + + static const char code4[] = "using namespace std;\n" + "void foo() {swap(a, b); }"; + ASSERT_EQUALS("void foo ( ) { std :: swap ( a , b ) ; }", tokenizeAndStringify(code4, false)); + + static const char code5[] = "using namespace std;\n" + "void foo() {map(a, b); }"; // Thats obviously not std::map<> + ASSERT_EQUALS("void foo ( ) { map ( a , b ) ; }", tokenizeAndStringify(code5, false)); + + static const char code6[] = "using namespace std;\n" + "string s;"; // Thats obviously not std::string + ASSERT_EQUALS("string < wchar_t > s ;", tokenizeAndStringify(code6, false)); + + static const char code7[] = "using namespace std;\n" + "swap s;"; // Thats obviously not std::swap + ASSERT_EQUALS("swap s ;", tokenizeAndStringify(code7, false)); + + static const char code8[] = "using namespace std;\n" + "std::string s;"; + ASSERT_EQUALS("std :: string s ;", tokenizeAndStringify(code8, false)); + + static const char code9[] = "using namespace std;\n" + "tr1::function f;"; + ASSERT_EQUALS("tr1 :: function < void ( int ) > f ;", tokenizeAndStringify(code9, false, true, Settings::Unspecified, "test.cpp", false)); + ASSERT_EQUALS("std :: function < void ( int ) > f ;", tokenizeAndStringify(code9, false, true, Settings::Unspecified, "test.cpp", true)); + + static const char code10[] = "std::tr1::function f;"; + ASSERT_EQUALS("std :: tr1 :: function < void ( int ) > f ;", tokenizeAndStringify(code10, false, true, Settings::Unspecified, "test.cpp", false)); + ASSERT_EQUALS("std :: function < void ( int ) > f ;", tokenizeAndStringify(code10, false, true, Settings::Unspecified, "test.cpp", true)); + } + void microsoftMFC() { const char code1[] = "class MyDialog : public CDialog { DECLARE_MESSAGE_MAP() private: CString text; };"; ASSERT_EQUALS("class MyDialog : public CDialog { private: CString text ; } ;", tokenizeAndStringify(code1,false,true,Settings::Win32A));