Fixed Token::isKeyword: Actually set this flag to a reasonable value in all code paths

This commit is contained in:
PKEuS 2020-05-17 17:25:33 +02:00
parent c9d8f607df
commit f6788c0472
6 changed files with 109 additions and 69 deletions

View File

@ -81,6 +81,8 @@ void Token::update_property_info()
else if (std::isalpha((unsigned char)mStr[0]) || mStr[0] == '_' || mStr[0] == '$') { // Name else if (std::isalpha((unsigned char)mStr[0]) || mStr[0] == '_' || mStr[0] == '$') { // Name
if (mImpl->mVarId) if (mImpl->mVarId)
tokType(eVariable); tokType(eVariable);
else if (mTokensFrontBack && mTokensFrontBack->list && mTokensFrontBack->list->isKeyword(mStr))
tokType(eKeyword);
else if (mTokType != eVariable && mTokType != eFunction && mTokType != eType && mTokType != eKeyword) else if (mTokType != eVariable && mTokType != eFunction && mTokType != eType && mTokType != eKeyword)
tokType(eName); tokType(eName);
} else if (std::isdigit((unsigned char)mStr[0]) || (mStr.length() > 1 && mStr[0] == '-' && std::isdigit((unsigned char)mStr[1]))) } else if (std::isdigit((unsigned char)mStr[0]) || (mStr.length() > 1 && mStr[0] == '-' && std::isdigit((unsigned char)mStr[1])))
@ -401,7 +403,7 @@ static int multiComparePercent(const Token *tok, const char*& haystack, nonneg i
// Type (%type%) // Type (%type%)
{ {
haystack += 5; haystack += 5;
if (tok->isName() && tok->varId() == 0 && !tok->isKeyword()) if (tok->isName() && tok->varId() == 0 && (tok->str() != "delete" || !tok->isKeyword())) // HACK: this is legacy behaviour, it should return false for all keywords, ecxcept types
return 1; return 1;
} }
break; break;
@ -1022,7 +1024,7 @@ void Token::insertToken(const std::string &tokenStr, const std::string &original
if (mImpl->mScopeInfo) { if (mImpl->mScopeInfo) {
// If the brace is immediately closed there is no point opening a new scope for it // If the brace is immediately closed there is no point opening a new scope for it
if (tokenStr == "{") { if (newToken->str() == "{") {
std::string nextScopeNameAddition; std::string nextScopeNameAddition;
// This might be the opening of a member function // This might be the opening of a member function
Token *tok1 = newToken; Token *tok1 = newToken;
@ -1079,7 +1081,7 @@ void Token::insertToken(const std::string &tokenStr, const std::string &original
nextScopeNameAddition = ""; nextScopeNameAddition = "";
newToken->scopeInfo(newScopeInfo); newToken->scopeInfo(newScopeInfo);
} else if (tokenStr == "}") { } else if (newToken->str() == "}") {
Token* matchingTok = newToken->previous(); Token* matchingTok = newToken->previous();
int depth = 0; int depth = 0;
while (matchingTok && (depth != 0 || !Token::simpleMatch(matchingTok, "{"))) { while (matchingTok && (depth != 0 || !Token::simpleMatch(matchingTok, "{"))) {
@ -1096,7 +1098,7 @@ void Token::insertToken(const std::string &tokenStr, const std::string &original
} else { } else {
newToken->mImpl->mScopeInfo = mImpl->mScopeInfo; newToken->mImpl->mScopeInfo = mImpl->mScopeInfo;
} }
if (tokenStr == ";") { if (newToken->str() == ";") {
const Token* statementStart; const Token* statementStart;
for (statementStart = newToken; statementStart->previous() && !Token::Match(statementStart->previous(), ";|{"); statementStart = statementStart->previous()); for (statementStart = newToken; statementStart->previous() && !Token::Match(statementStart->previous(), ";|{"); statementStart = statementStart->previous());
if (Token::Match(statementStart, "using namespace %name% ::|;")) { if (Token::Match(statementStart, "using namespace %name% ::|;")) {

View File

@ -42,6 +42,7 @@ class Settings;
class Type; class Type;
class ValueType; class ValueType;
class Variable; class Variable;
class TokenList;
/** /**
* @brief This struct stores pointers to the front and back tokens of the list this token is in. * @brief This struct stores pointers to the front and back tokens of the list this token is in.
@ -49,6 +50,7 @@ class Variable;
struct TokensFrontBack { struct TokensFrontBack {
Token *front; Token *front;
Token *back; Token *back;
const TokenList* list;
}; };
struct ScopeInfo2 { struct ScopeInfo2 {

View File

@ -9319,7 +9319,7 @@ void Tokenizer::reportUnknownMacros()
for (const Token *tok = tokens(); tok; tok = tok->next()) { for (const Token *tok = tokens(); tok; tok = tok->next()) {
if (Token::Match(tok, "%name% %num%")) { if (Token::Match(tok, "%name% %num%")) {
// A keyword is not an unknown macro // A keyword is not an unknown macro
if (list.isKeyword(tok->str())) if (tok->isKeyword())
continue; continue;
if (Token::Match(tok->previous(), "%op%|(")) if (Token::Match(tok->previous(), "%op%|("))
@ -9372,7 +9372,7 @@ void Tokenizer::reportUnknownMacros()
if (Token::Match(tok, "%name% (") && tok->isUpperCaseName() && Token::simpleMatch(tok->linkAt(1), ") (") && Token::simpleMatch(tok->linkAt(1)->linkAt(1), ") {")) { if (Token::Match(tok, "%name% (") && tok->isUpperCaseName() && Token::simpleMatch(tok->linkAt(1), ") (") && Token::simpleMatch(tok->linkAt(1)->linkAt(1), ") {")) {
// A keyword is not an unknown macro // A keyword is not an unknown macro
if (list.isKeyword(tok->str())) if (tok->isKeyword())
continue; continue;
const Token *bodyStart = tok->linkAt(1)->linkAt(1)->tokAt(2); const Token *bodyStart = tok->linkAt(1)->linkAt(1)->tokAt(2);
@ -9392,7 +9392,7 @@ void Tokenizer::reportUnknownMacros()
// String concatenation with unknown macros // String concatenation with unknown macros
for (const Token *tok = tokens(); tok; tok = tok->next()) { for (const Token *tok = tokens(); tok; tok = tok->next()) {
if (Token::Match(tok, "%str% %name% (") && Token::Match(tok->linkAt(2), ") %str%")) { if (Token::Match(tok, "%str% %name% (") && Token::Match(tok->linkAt(2), ") %str%")) {
if (list.isKeyword(tok->next()->str())) if (tok->next()->isKeyword())
continue; continue;
unknownMacroError(tok->next()); unknownMacroError(tok->next());
} }
@ -9585,8 +9585,6 @@ void Tokenizer::findGarbageCode() const
if (tok->str() != ">" && !Token::simpleMatch(tok->previous(), "operator")) if (tok->str() != ">" && !Token::simpleMatch(tok->previous(), "operator"))
syntaxError(tok, tok->str() + " " + tok->next()->str()); syntaxError(tok, tok->str() + " " + tok->next()->str());
} }
if (Token::Match(tok, "( %any% )") && tok->next()->isKeyword() && !Token::simpleMatch(tok->next(), "void"))
syntaxError(tok);
if (Token::Match(tok, "%num%|%bool%|%char%|%str% %num%|%bool%|%char%|%str%") && !Token::Match(tok, "%str% %str%")) if (Token::Match(tok, "%num%|%bool%|%char%|%str% %num%|%bool%|%char%|%str%") && !Token::Match(tok, "%str% %str%"))
syntaxError(tok); syntaxError(tok);
if (Token::Match(tok, "%assign% typename|class %assign%")) if (Token::Match(tok, "%assign% typename|class %assign%"))

View File

@ -44,29 +44,30 @@ TokenList::TokenList(const Settings* settings) :
mIsC(false), mIsC(false),
mIsCpp(false) mIsCpp(false)
{ {
mTokensFrontBack.list = this;
mKeywords.insert("auto"); mKeywords.insert("auto");
mKeywords.insert("break"); mKeywords.insert("break");
mKeywords.insert("case"); mKeywords.insert("case");
mKeywords.insert("char"); //mKeywords.insert("char"); // type
mKeywords.insert("const"); mKeywords.insert("const");
mKeywords.insert("continue"); mKeywords.insert("continue");
mKeywords.insert("default"); mKeywords.insert("default");
mKeywords.insert("do"); mKeywords.insert("do");
mKeywords.insert("double"); //mKeywords.insert("double"); // type
mKeywords.insert("else"); mKeywords.insert("else");
mKeywords.insert("enum"); mKeywords.insert("enum");
mKeywords.insert("extern"); mKeywords.insert("extern");
mKeywords.insert("float"); //mKeywords.insert("float"); // type
mKeywords.insert("for"); mKeywords.insert("for");
mKeywords.insert("goto"); mKeywords.insert("goto");
mKeywords.insert("if"); mKeywords.insert("if");
mKeywords.insert("inline"); mKeywords.insert("inline");
mKeywords.insert("int"); //mKeywords.insert("int"); // type
mKeywords.insert("long"); //mKeywords.insert("long"); // type
mKeywords.insert("register"); mKeywords.insert("register");
mKeywords.insert("restrict"); mKeywords.insert("restrict");
mKeywords.insert("return"); mKeywords.insert("return");
mKeywords.insert("short"); //mKeywords.insert("short"); // type
mKeywords.insert("signed"); mKeywords.insert("signed");
mKeywords.insert("sizeof"); mKeywords.insert("sizeof");
mKeywords.insert("static"); mKeywords.insert("static");
@ -106,6 +107,50 @@ void TokenList::deallocateTokens()
mFiles.clear(); mFiles.clear();
} }
void TokenList::determineCppC()
{
if (!mSettings) {
mIsC = Path::isC(getSourceFilePath());
mIsCpp = Path::isCPP(getSourceFilePath());
} else {
mIsC = mSettings->enforcedLang == Settings::C || (mSettings->enforcedLang == Settings::None && Path::isC(getSourceFilePath()));
mIsCpp = mSettings->enforcedLang == Settings::CPP || (mSettings->enforcedLang == Settings::None && Path::isCPP(getSourceFilePath()));
}
if (mIsCpp) {
//mKeywords.insert("bool"); // type
mKeywords.insert("catch");
mKeywords.insert("delete");
mKeywords.insert("class");
mKeywords.insert("const_cast");
mKeywords.insert("delete");
mKeywords.insert("dynamic_cast");
mKeywords.insert("explicit");
mKeywords.insert("export");
//mKeywords.insert("false"); // literal
mKeywords.insert("friend");
mKeywords.insert("mutable");
mKeywords.insert("namespace");
mKeywords.insert("new");
mKeywords.insert("operator");
mKeywords.insert("private");
mKeywords.insert("protected");
mKeywords.insert("public");
mKeywords.insert("reinterpret_cast");
mKeywords.insert("static_cast");
mKeywords.insert("template");
mKeywords.insert("this");
mKeywords.insert("throw");
//mKeywords.insert("true"); // literal
mKeywords.insert("try");
mKeywords.insert("typeid");
mKeywords.insert("typename");
mKeywords.insert("using");
mKeywords.insert("virtual");
//mKeywords.insert("wchar_t"); // type
}
}
int TokenList::appendFileIfNew(const std::string &fileName) int TokenList::appendFileIfNew(const std::string &fileName)
{ {
// Has this file been tokenized already? // Has this file been tokenized already?
@ -118,45 +163,7 @@ int TokenList::appendFileIfNew(const std::string &fileName)
// Update mIsC and mIsCpp properties // Update mIsC and mIsCpp properties
if (mFiles.size() == 1) { // Update only useful if first file added to _files if (mFiles.size() == 1) { // Update only useful if first file added to _files
if (!mSettings) { determineCppC();
mIsC = Path::isC(getSourceFilePath());
mIsCpp = Path::isCPP(getSourceFilePath());
} else {
mIsC = mSettings->enforcedLang == Settings::C || (mSettings->enforcedLang == Settings::None && Path::isC(getSourceFilePath()));
mIsCpp = mSettings->enforcedLang == Settings::CPP || (mSettings->enforcedLang == Settings::None && Path::isCPP(getSourceFilePath()));
}
if (mIsCpp) {
mKeywords.insert("catch");
mKeywords.insert("delete");
mKeywords.insert("class");
mKeywords.insert("const_cast");
mKeywords.insert("delete");
mKeywords.insert("dynamic_cast");
mKeywords.insert("explicit");
mKeywords.insert("export");
mKeywords.insert("false");
mKeywords.insert("friend");
mKeywords.insert("mutable");
mKeywords.insert("namespace");
mKeywords.insert("new");
mKeywords.insert("operator");
mKeywords.insert("private");
mKeywords.insert("protected");
mKeywords.insert("public");
mKeywords.insert("reinterpret_cast");
mKeywords.insert("static_cast");
mKeywords.insert("template");
mKeywords.insert("this");
mKeywords.insert("throw");
mKeywords.insert("true");
mKeywords.insert("try");
mKeywords.insert("typeid");
mKeywords.insert("typename");
mKeywords.insert("using");
mKeywords.insert("virtual");
mKeywords.insert("wchar_t");
}
} }
return mFiles.size() - 1; return mFiles.size() - 1;
} }
@ -207,8 +214,6 @@ void TokenList::addtoken(std::string str, const nonneg int lineno, const nonneg
mTokensFrontBack.back->str(str); mTokensFrontBack.back->str(str);
} }
if (isKeyword(str))
mTokensFrontBack.back->isKeyword(true);
mTokensFrontBack.back->linenr(lineno); mTokensFrontBack.back->linenr(lineno);
mTokensFrontBack.back->fileIndex(fileno); mTokensFrontBack.back->fileIndex(fileno);
} }
@ -226,8 +231,6 @@ void TokenList::addtoken(std::string str, const Token *locationTok)
mTokensFrontBack.back->str(str); mTokensFrontBack.back->str(str);
} }
if (isCPP() && str == "delete")
mTokensFrontBack.back->isKeyword(true);
mTokensFrontBack.back->linenr(locationTok->linenr()); mTokensFrontBack.back->linenr(locationTok->linenr());
mTokensFrontBack.back->column(locationTok->column()); mTokensFrontBack.back->column(locationTok->column());
mTokensFrontBack.back->fileIndex(locationTok->fileIndex()); mTokensFrontBack.back->fileIndex(locationTok->fileIndex());
@ -391,15 +394,7 @@ void TokenList::createTokens(simplecpp::TokenList&& tokenList)
else else
mFiles.clear(); mFiles.clear();
mIsC = mIsCpp = false; determineCppC();
if (!mFiles.empty()) {
mIsC = Path::isC(getSourceFilePath());
mIsCpp = Path::isCPP(getSourceFilePath());
}
if (mSettings && mSettings->enforcedLang != Settings::None) {
mIsC = (mSettings->enforcedLang == Settings::C);
mIsCpp = (mSettings->enforcedLang == Settings::CPP);
}
for (const simplecpp::Token *tok = tokenList.cfront(); tok;) { for (const simplecpp::Token *tok = tokenList.cfront(); tok;) {
@ -417,8 +412,6 @@ void TokenList::createTokens(simplecpp::TokenList&& tokenList)
mTokensFrontBack.back->str(str); mTokensFrontBack.back->str(str);
} }
if (isCPP() && mTokensFrontBack.back->str() == "delete")
mTokensFrontBack.back->isKeyword(true);
mTokensFrontBack.back->fileIndex(tok->location.fileIndex); mTokensFrontBack.back->fileIndex(tok->location.fileIndex);
mTokensFrontBack.back->linenr(tok->location.line); mTokensFrontBack.back->linenr(tok->location.line);
mTokensFrontBack.back->column(tok->location.col); mTokensFrontBack.back->column(tok->location.col);

View File

@ -197,6 +197,8 @@ private:
/** Disable assignment operator, no implementation */ /** Disable assignment operator, no implementation */
TokenList &operator=(const TokenList &); TokenList &operator=(const TokenList &);
void determineCppC();
/** Token list */ /** Token list */
TokensFrontBack mTokensFrontBack; TokensFrontBack mTokensFrontBack;

View File

@ -35,6 +35,7 @@ private:
TEST_CASE(testaddtoken1); TEST_CASE(testaddtoken1);
TEST_CASE(testaddtoken2); TEST_CASE(testaddtoken2);
TEST_CASE(inc); TEST_CASE(inc);
TEST_CASE(isKeyword);
} }
// inspired by #5895 // inspired by #5895
@ -65,6 +66,48 @@ private:
ASSERT(Token::simpleMatch(tokenlist.front(), "a + + 1 ; 1 + + b ;")); ASSERT(Token::simpleMatch(tokenlist.front(), "a + + 1 ; 1 + + b ;"));
} }
void isKeyword() {
const char code[] = "for a int delete true";
{
TokenList tokenlist(&settings);
std::istringstream istr(code);
tokenlist.createTokens(istr, "a.c");
ASSERT_EQUALS(true, tokenlist.front()->isKeyword());
ASSERT_EQUALS(true, tokenlist.front()->isControlFlowKeyword());
ASSERT_EQUALS(false, tokenlist.front()->next()->isKeyword());
ASSERT_EQUALS(false, tokenlist.front()->next()->isControlFlowKeyword());
ASSERT_EQUALS(false, tokenlist.front()->tokAt(2)->isKeyword());
ASSERT_EQUALS(true, tokenlist.front()->tokAt(2)->tokType() == Token::eType);
ASSERT_EQUALS(false, tokenlist.front()->tokAt(2)->isControlFlowKeyword());
ASSERT_EQUALS(false, tokenlist.front()->tokAt(3)->isKeyword());
ASSERT_EQUALS(false, tokenlist.front()->tokAt(3)->isControlFlowKeyword());
ASSERT_EQUALS(false, tokenlist.front()->tokAt(4)->isKeyword());
ASSERT_EQUALS(true, tokenlist.front()->tokAt(4)->isLiteral());
ASSERT_EQUALS(false, tokenlist.front()->tokAt(4)->isControlFlowKeyword());
}
{
TokenList tokenlist(&settings);
std::istringstream istr(code);
tokenlist.createTokens(istr, "a.cpp");
ASSERT_EQUALS(true, tokenlist.front()->isKeyword());
ASSERT_EQUALS(true, tokenlist.front()->isControlFlowKeyword());
ASSERT_EQUALS(false, tokenlist.front()->next()->isKeyword());
ASSERT_EQUALS(false, tokenlist.front()->next()->isControlFlowKeyword());
ASSERT_EQUALS(false, tokenlist.front()->tokAt(2)->isKeyword());
ASSERT_EQUALS(true, tokenlist.front()->tokAt(2)->tokType() == Token::eType);
ASSERT_EQUALS(false, tokenlist.front()->tokAt(2)->isControlFlowKeyword());
ASSERT_EQUALS(true, tokenlist.front()->tokAt(3)->isKeyword());
ASSERT_EQUALS(false, tokenlist.front()->tokAt(3)->isControlFlowKeyword());
ASSERT_EQUALS(false, tokenlist.front()->tokAt(4)->isKeyword());
ASSERT_EQUALS(true, tokenlist.front()->tokAt(4)->isLiteral());
ASSERT_EQUALS(false, tokenlist.front()->tokAt(4)->isControlFlowKeyword());
}
}
}; };
REGISTER_TEST(TestTokenList) REGISTER_TEST(TestTokenList)