Set correct type and size of string and char literals (#2275)
* Set correct type and size of string and char literals Use that string and char literal tokens store the prefix. This makes it possible to distinghuish between different type of string literals (i.e., utf8 encoded strings, utf16, wide strings, etc) which have different type. When the tokens holding the string and character values have the correct type, it is possible to improve Token::getStrSize() to give the correct result for all string types. Previously, it would return the number of characters in the string, i.e., it would give the wrong size unless the type of the string was char*. Since strings now can have different size (in number of bytes) and length (in number of elements), add a new helper function that returns the number of characters. Checkers have been updated to use the correct functions. Having the size makes it possible to find more problems with prefixed strings, and to reduce false positives, for example in the buffer overflow checker. Also, improve the stringLiteralWrite error message to also print the prefix of the string (if there is one). * Add comment and update string length
This commit is contained in:
parent
00fae7fb42
commit
5c061c1c12
|
@ -203,10 +203,10 @@ static bool getDimensionsEtc(const Token * const arrayToken, const Settings *set
|
|||
return ChildrenToVisit::op1_and_op2;
|
||||
});
|
||||
}
|
||||
} else if (const Token *stringLiteral = array->getValueTokenMinStrSize()) {
|
||||
} else if (const Token *stringLiteral = array->getValueTokenMinStrSize(settings)) {
|
||||
Dimension dim;
|
||||
dim.tok = nullptr;
|
||||
dim.num = Token::getStrSize(stringLiteral);
|
||||
dim.num = Token::getStrArraySize(stringLiteral);
|
||||
dim.known = array->hasKnownValue();
|
||||
dimensions->emplace_back(dim);
|
||||
} else if (array->valueType() && array->valueType()->pointer >= 1 && array->valueType()->isIntegral()) {
|
||||
|
|
|
@ -60,7 +60,7 @@ void CheckString::stringLiteralWrite()
|
|||
for (const Token* tok = scope->bodyStart->next(); tok != scope->bodyEnd; tok = tok->next()) {
|
||||
if (!tok->variable() || !tok->variable()->isPointer())
|
||||
continue;
|
||||
const Token *str = tok->getValueTokenMinStrSize();
|
||||
const Token *str = tok->getValueTokenMinStrSize(mSettings);
|
||||
if (!str)
|
||||
continue;
|
||||
if (Token::Match(tok, "%var% [") && Token::simpleMatch(tok->linkAt(1), "] ="))
|
||||
|
@ -80,10 +80,11 @@ void CheckString::stringLiteralWriteError(const Token *tok, const Token *strValu
|
|||
|
||||
std::string errmsg("Modifying string literal");
|
||||
if (strValue) {
|
||||
std::string s = strValue->strValue();
|
||||
if (s.size() > 15U)
|
||||
s = s.substr(0,13) + "..";
|
||||
errmsg += " \"" + s + "\"";
|
||||
std::string s = strValue->str();
|
||||
// 20 is an arbitrary value, the max string length shown in a warning message
|
||||
if (s.size() > 20U)
|
||||
s = s.substr(0,17) + "..\"";
|
||||
errmsg += " " + s;
|
||||
}
|
||||
errmsg += " directly or indirectly is undefined behaviour.";
|
||||
|
||||
|
|
|
@ -5593,13 +5593,26 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings)
|
|||
setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::BOOL, 0U));
|
||||
} else if (tok->isBoolean()) {
|
||||
setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::BOOL, 0U));
|
||||
} else if (tok->tokType() == Token::eChar) {
|
||||
setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, tok->isLong() ? ValueType::Type::WCHAR_T : ValueType::Type::CHAR, 0U));
|
||||
} else if (tok->tokType() == Token::eString) {
|
||||
ValueType valuetype(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::CHAR, 1U, 1U);
|
||||
if (tok->isLong()) {
|
||||
} else if (tok->tokType() == Token::eChar || tok->tokType() == Token::eString) {
|
||||
nonneg int pointer = tok->tokType() == Token::eChar ? 0U : 1U;
|
||||
nonneg int constness = tok->tokType() == Token::eChar ? 0U : 1U;
|
||||
ValueType valuetype(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::CHAR, pointer, constness);
|
||||
|
||||
if (mIsCpp && mSettings->standards.cpp >= Standards::CPP20 && tok->isUtf8()) {
|
||||
valuetype.originalTypeName = "char8_t";
|
||||
valuetype.fromLibraryType(valuetype.originalTypeName, mSettings);
|
||||
} else if (tok->isUtf16()) {
|
||||
valuetype.originalTypeName = "char16_t";
|
||||
valuetype.fromLibraryType(valuetype.originalTypeName, mSettings);
|
||||
} else if (tok->isUtf32()) {
|
||||
valuetype.originalTypeName = "char32_t";
|
||||
valuetype.fromLibraryType(valuetype.originalTypeName, mSettings);
|
||||
} else if (tok->isLong()) {
|
||||
valuetype.originalTypeName = "wchar_t";
|
||||
valuetype.type = ValueType::Type::WCHAR_T;
|
||||
} else if ((tok->tokType() == Token::eChar) && ((tok->isCChar() && !mIsCpp) || (tok->isCMultiChar()))) {
|
||||
valuetype.type = ValueType::Type::INT;
|
||||
valuetype.sign = ValueType::Sign::SIGNED;
|
||||
}
|
||||
setValueType(tok, valuetype);
|
||||
} else if (tok->str() == "(") {
|
||||
|
|
|
@ -722,7 +722,7 @@ nonneg int Token::getStrLength(const Token *tok)
|
|||
return len;
|
||||
}
|
||||
|
||||
nonneg int Token::getStrSize(const Token *tok)
|
||||
nonneg int Token::getStrArraySize(const Token *tok)
|
||||
{
|
||||
assert(tok != nullptr);
|
||||
assert(tok->tokType() == eString);
|
||||
|
@ -736,6 +736,18 @@ nonneg int Token::getStrSize(const Token *tok)
|
|||
return sizeofstring;
|
||||
}
|
||||
|
||||
nonneg int Token::getStrSize(const Token *tok, const Settings *settings)
|
||||
{
|
||||
assert(tok != nullptr && tok->tokType() == eString);
|
||||
nonneg int sizeofType = 1;
|
||||
if (tok->valueType()) {
|
||||
ValueType vt(*tok->valueType());
|
||||
vt.pointer = 0;
|
||||
sizeofType = ValueFlow::getSizeOf(vt, settings);
|
||||
}
|
||||
return getStrArraySize(tok) * sizeofType;
|
||||
}
|
||||
|
||||
std::string Token::getCharAt(const Token *tok, MathLib::bigint index)
|
||||
{
|
||||
assert(tok != nullptr);
|
||||
|
@ -1713,7 +1725,7 @@ const ValueFlow::Value * Token::getInvalidValue(const Token *ftok, nonneg int ar
|
|||
return ret;
|
||||
}
|
||||
|
||||
const Token *Token::getValueTokenMinStrSize() const
|
||||
const Token *Token::getValueTokenMinStrSize(const Settings *settings) const
|
||||
{
|
||||
if (!mImpl->mValues)
|
||||
return nullptr;
|
||||
|
@ -1722,7 +1734,7 @@ const Token *Token::getValueTokenMinStrSize() const
|
|||
std::list<ValueFlow::Value>::const_iterator it;
|
||||
for (it = mImpl->mValues->begin(); it != mImpl->mValues->end(); ++it) {
|
||||
if (it->isTokValue() && it->tokvalue && it->tokvalue->tokType() == Token::eString) {
|
||||
const int size = getStrSize(it->tokvalue);
|
||||
const int size = getStrSize(it->tokvalue, settings);
|
||||
if (!ret || size < minsize) {
|
||||
minsize = size;
|
||||
ret = it->tokvalue;
|
||||
|
|
40
lib/token.h
40
lib/token.h
|
@ -318,13 +318,23 @@ public:
|
|||
static nonneg int getStrLength(const Token *tok);
|
||||
|
||||
/**
|
||||
* @return sizeof of C-string.
|
||||
* @return array length of C-string.
|
||||
*
|
||||
* Should be called for %%str%% tokens only.
|
||||
*
|
||||
* @param tok token with C-string
|
||||
**/
|
||||
static nonneg int getStrSize(const Token *tok);
|
||||
static nonneg int getStrArraySize(const Token *tok);
|
||||
|
||||
/**
|
||||
* @return sizeof of C-string.
|
||||
*
|
||||
* Should be called for %%str%% tokens only.
|
||||
*
|
||||
* @param tok token with C-string
|
||||
* @param settings Settings
|
||||
**/
|
||||
static nonneg int getStrSize(const Token *tok, const Settings *const);
|
||||
|
||||
/**
|
||||
* @return char of C-string at index (possible escaped "\\n")
|
||||
|
@ -602,6 +612,30 @@ public:
|
|||
mImpl->mBits = b;
|
||||
}
|
||||
|
||||
bool isUtf8() const {
|
||||
return (((mTokType == eString) && isPrefixStringCharLiteral(mStr, '"', "u8")) ||
|
||||
((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', "u8")));
|
||||
}
|
||||
|
||||
bool isUtf16() const {
|
||||
return (((mTokType == eString) && isPrefixStringCharLiteral(mStr, '"', "u")) ||
|
||||
((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', "u")));
|
||||
}
|
||||
|
||||
bool isUtf32() const {
|
||||
return (((mTokType == eString) && isPrefixStringCharLiteral(mStr, '"', "U")) ||
|
||||
((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', "U")));
|
||||
}
|
||||
|
||||
bool isCChar() const {
|
||||
return (((mTokType == eString) && isPrefixStringCharLiteral(mStr, '"', "")) ||
|
||||
((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', "") && mStr.length() == 3));
|
||||
}
|
||||
|
||||
bool isCMultiChar() const {
|
||||
return (((mTokType == eChar) && isPrefixStringCharLiteral(mStr, '\'', "")) &&
|
||||
(mStr.length() > 3));
|
||||
}
|
||||
/**
|
||||
* @brief Is current token a template argument?
|
||||
*
|
||||
|
@ -1042,7 +1076,7 @@ public:
|
|||
}
|
||||
|
||||
const Token *getValueTokenMaxStrLength() const;
|
||||
const Token *getValueTokenMinStrSize() const;
|
||||
const Token *getValueTokenMinStrSize(const Settings *settings) const;
|
||||
|
||||
const Token *getValueTokenDeadPointer() const;
|
||||
|
||||
|
|
|
@ -2679,7 +2679,7 @@ void Tokenizer::arraySize()
|
|||
|
||||
if (addlength || Token::Match(tok, "%var% [ ] = %str% ;")) {
|
||||
tok = tok->next();
|
||||
const int sz = Token::getStrSize(tok->tokAt(3));
|
||||
const int sz = Token::getStrArraySize(tok->tokAt(3));
|
||||
tok->insertToken(MathLib::toString(sz));
|
||||
tok = tok->tokAt(5);
|
||||
}
|
||||
|
|
|
@ -1094,7 +1094,7 @@ static nonneg int getSizeOfType(const Token *typeTok, const Settings *settings)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static size_t getSizeOf(const ValueType &vt, const Settings *settings)
|
||||
size_t ValueFlow::getSizeOf(const ValueType &vt, const Settings *settings)
|
||||
{
|
||||
if (vt.pointer)
|
||||
return settings->sizeof_pointer;
|
||||
|
@ -1154,7 +1154,7 @@ static Token * valueFlowSetConstantValue(Token *tok, const Settings *settings, b
|
|||
}
|
||||
if (Token::simpleMatch(tok, "sizeof ( *")) {
|
||||
const ValueType *vt = tok->tokAt(2)->valueType();
|
||||
const size_t sz = vt ? getSizeOf(*vt, settings) : 0;
|
||||
const size_t sz = vt ? ValueFlow::getSizeOf(*vt, settings) : 0;
|
||||
if (sz > 0) {
|
||||
ValueFlow::Value value(sz);
|
||||
if (!tok2->isTemplateArg() && settings->platformType != cppcheck::Platform::Unspecified)
|
||||
|
@ -1212,7 +1212,7 @@ static Token * valueFlowSetConstantValue(Token *tok, const Settings *settings, b
|
|||
if (var->type()->classScope && var->type()->classScope->enumType)
|
||||
size = getSizeOfType(var->type()->classScope->enumType, settings);
|
||||
} else if (var->valueType()) {
|
||||
size = getSizeOf(*var->valueType(), settings);
|
||||
size = ValueFlow::getSizeOf(*var->valueType(), settings);
|
||||
} else if (!var->type()) {
|
||||
size = getSizeOfType(var->typeStartToken(), settings);
|
||||
}
|
||||
|
@ -1234,7 +1234,7 @@ static Token * valueFlowSetConstantValue(Token *tok, const Settings *settings, b
|
|||
}
|
||||
} else if (!tok2->type()) {
|
||||
const ValueType &vt = ValueType::parseDecl(tok2,settings);
|
||||
const size_t sz = getSizeOf(vt, settings);
|
||||
const size_t sz = ValueFlow::getSizeOf(vt, settings);
|
||||
if (sz > 0) {
|
||||
ValueFlow::Value value(sz);
|
||||
if (!tok2->isTemplateArg() && settings->platformType != cppcheck::Platform::Unspecified)
|
||||
|
@ -4289,7 +4289,7 @@ static std::list<ValueFlow::Value> truncateValues(std::list<ValueFlow::Value> va
|
|||
if (!valueType || !valueType->isIntegral())
|
||||
return values;
|
||||
|
||||
const size_t sz = getSizeOf(*valueType, settings);
|
||||
const size_t sz = ValueFlow::getSizeOf(*valueType, settings);
|
||||
|
||||
for (ValueFlow::Value &value : values) {
|
||||
if (value.isFloatValue()) {
|
||||
|
|
|
@ -34,6 +34,7 @@ class Settings;
|
|||
class SymbolDatabase;
|
||||
class Token;
|
||||
class TokenList;
|
||||
class ValueType;
|
||||
class Variable;
|
||||
|
||||
namespace ValueFlow {
|
||||
|
@ -320,6 +321,8 @@ namespace ValueFlow {
|
|||
void setValues(TokenList *tokenlist, SymbolDatabase* symboldatabase, ErrorLogger *errorLogger, const Settings *settings);
|
||||
|
||||
std::string eitherTheConditionIsRedundant(const Token *condition);
|
||||
|
||||
size_t getSizeOf(const ValueType &vt, const Settings *settings);
|
||||
}
|
||||
|
||||
struct LifetimeToken {
|
||||
|
|
|
@ -3198,6 +3198,7 @@ private:
|
|||
doc.Parse(xmldata, sizeof(xmldata));
|
||||
settings.library.load(doc);
|
||||
settings.addEnabled("warning");
|
||||
settings.sizeof_wchar_t = 4;
|
||||
|
||||
check("void f() {\n"
|
||||
" char c[10];\n"
|
||||
|
@ -3236,10 +3237,28 @@ private:
|
|||
// Ticket #909
|
||||
check("void f(void) {\n"
|
||||
" char str[] = \"abcd\";\n"
|
||||
" mymemset(str, 0, 10);\n"
|
||||
" mymemset(str, 0, 6);\n"
|
||||
"}", settings);
|
||||
ASSERT_EQUALS("[test.cpp:3]: (error) Buffer is accessed out of bounds: str\n", errout.str());
|
||||
|
||||
check("void f(void) {\n"
|
||||
" char str[] = \"abcd\";\n"
|
||||
" mymemset(str, 0, 5);\n"
|
||||
"}", settings);
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
check("void f(void) {\n"
|
||||
" wchar_t str[] = L\"abcd\";\n"
|
||||
" mymemset(str, 0, 21);\n"
|
||||
"}", settings);
|
||||
ASSERT_EQUALS("[test.cpp:3]: (error) Buffer is accessed out of bounds: str\n", errout.str());
|
||||
|
||||
check("void f(void) {\n"
|
||||
" wchar_t str[] = L\"abcd\";\n"
|
||||
" mymemset(str, 0, 20);\n"
|
||||
"}", settings);
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
||||
// ticket #1659 - overflowing variable when using memcpy
|
||||
check("void f(void) { \n"
|
||||
" char c;\n"
|
||||
|
|
|
@ -88,6 +88,12 @@ private:
|
|||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (error) Modifying string literal \"abc\" directly or indirectly is undefined behaviour.\n", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" char *abc = \"A very long string literal\";\n"
|
||||
" abc[0] = 'a';\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (error) Modifying string literal \"A very long stri..\" directly or indirectly is undefined behaviour.\n", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" QString abc = \"abc\";\n"
|
||||
" abc[0] = 'a';\n"
|
||||
|
@ -118,13 +124,13 @@ private:
|
|||
" wchar_t *abc = L\"abc\";\n"
|
||||
" abc[0] = u'a';\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (error) Modifying string literal \"abc\" directly or indirectly is undefined behaviour.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (error) Modifying string literal L\"abc\" directly or indirectly is undefined behaviour.\n", errout.str());
|
||||
|
||||
check("void f() {\n"
|
||||
" char16_t *abc = u\"abc\";\n"
|
||||
" abc[0] = 'a';\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (error) Modifying string literal \"abc\" directly or indirectly is undefined behaviour.\n", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2]: (error) Modifying string literal u\"abc\" directly or indirectly is undefined behaviour.\n", errout.str());
|
||||
}
|
||||
|
||||
void alwaysTrueFalseStringCompare() {
|
||||
|
|
|
@ -5361,6 +5361,7 @@ private:
|
|||
GET_SYMBOL_DB("void foo1(int, char* a) { }\n"
|
||||
"void foo1(int, char a) { }\n"
|
||||
"void foo1(int, wchar_t a) { }\n"
|
||||
"void foo1(int, char16_t a) { }\n"
|
||||
"void foo2(int, float a) { }\n"
|
||||
"void foo2(int, wchar_t a) { }\n"
|
||||
"void foo3(int, float a) { }\n"
|
||||
|
@ -5368,10 +5369,11 @@ private:
|
|||
"void func() {\n"
|
||||
" foo1(1, 'c');\n"
|
||||
" foo1(2, L'c');\n"
|
||||
" foo2(3, 'c');\n"
|
||||
" foo2(4, L'c');\n"
|
||||
" foo3(5, 'c');\n"
|
||||
" foo3(6, L'c');\n"
|
||||
" foo1(3, u'c');\n"
|
||||
" foo2(4, 'c');\n"
|
||||
" foo2(5, L'c');\n"
|
||||
" foo3(6, 'c');\n"
|
||||
" foo3(7, L'c');\n"
|
||||
"}");
|
||||
|
||||
ASSERT_EQUALS("", errout.str());
|
||||
|
@ -5382,18 +5384,21 @@ private:
|
|||
f = Token::findsimplematch(tokenizer.tokens(), "foo1 ( 2");
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 3);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo2 ( 3");
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 5);
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo1 ( 3");
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 4);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo2 ( 4");
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 5);
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 6);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo3 ( 5");
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 7);
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo2 ( 5");
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 6);
|
||||
|
||||
f = Token::findsimplematch(tokenizer.tokens(), "foo3 ( 6");
|
||||
ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 8);
|
||||
|
||||
// Error: ambiguous function call
|
||||
//f = Token::findsimplematch(tokenizer.tokens(), "foo3 ( 6");
|
||||
//ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 7);
|
||||
//f = Token::findsimplematch(tokenizer.tokens(), "foo3 ( 7");
|
||||
//ASSERT_EQUALS(true, db && f && f->function() && f->function()->tokenDef->linenr() == 8);
|
||||
}
|
||||
|
||||
void findFunction16() {
|
||||
|
@ -6369,6 +6374,14 @@ private:
|
|||
ASSERT_EQUALS("signed long", typeOf("(signed long)1 + (unsigned int)2;", "+"));
|
||||
ASSERT_EQUALS("unsigned long", typeOf("(unsigned long)1 + (signed int)2;", "+"));
|
||||
|
||||
// char
|
||||
ASSERT_EQUALS("char", typeOf("'a';", "'a'", "test.cpp"));
|
||||
ASSERT_EQUALS("signed int", typeOf("'a';", "'a'", "test.c"));
|
||||
ASSERT_EQUALS("wchar_t", typeOf("L'a';", "L'a'", "test.cpp"));
|
||||
ASSERT_EQUALS("wchar_t", typeOf("L'a';", "L'a'", "test.c"));
|
||||
ASSERT_EQUALS("signed int", typeOf("'aaa';", "'aaa'", "test.cpp"));
|
||||
ASSERT_EQUALS("signed int", typeOf("'aaa';", "'aaa'", "test.c"));
|
||||
|
||||
// char *
|
||||
ASSERT_EQUALS("const char *", typeOf("\"hello\" + 1;", "+"));
|
||||
ASSERT_EQUALS("const char", typeOf("\"hello\"[1];", "["));
|
||||
|
@ -6498,6 +6511,25 @@ private:
|
|||
ASSERT_EQUALS("unsigned long long", typeOf("enum E : unsigned long long { }; void foo() { E e[3]; bar(e[0]); }", "[ 0"));
|
||||
|
||||
// Library types
|
||||
{
|
||||
// Char types
|
||||
Settings settings;
|
||||
const Library::PodType char8 = { 1, 'u' };
|
||||
const Library::PodType char16 = { 2, 'u' };
|
||||
const Library::PodType char32 = { 4, 'u' };
|
||||
settings.library.mPodTypes["char8_t"] = char8;
|
||||
settings.library.mPodTypes["char16_t"] = char16;
|
||||
settings.library.mPodTypes["char32_t"] = char32;
|
||||
settings.sizeof_short = 2;
|
||||
settings.sizeof_int = 4;
|
||||
|
||||
ASSERT_EQUALS("unsigned char", typeOf("u8'a';", "u8'a'", "test.cpp", &settings));
|
||||
ASSERT_EQUALS("unsigned short", typeOf("u'a';", "u'a'", "test.cpp", &settings));
|
||||
ASSERT_EQUALS("unsigned int", typeOf("U'a';", "U'a'", "test.cpp", &settings));
|
||||
ASSERT_EQUALS("const unsigned char *", typeOf("u8\"a\";", "u8\"a\"", "test.cpp", &settings));
|
||||
ASSERT_EQUALS("const unsigned short *", typeOf("u\"a\";", "u\"a\"", "test.cpp", &settings));
|
||||
ASSERT_EQUALS("const unsigned int *", typeOf("U\"a\";", "U\"a\"", "test.cpp", &settings));
|
||||
}
|
||||
{
|
||||
// PodType
|
||||
Settings settingsWin64;
|
||||
|
|
|
@ -56,6 +56,8 @@ private:
|
|||
TEST_CASE(multiCompare3); // false positive for %or% on code using "|="
|
||||
TEST_CASE(multiCompare4);
|
||||
TEST_CASE(multiCompare5);
|
||||
TEST_CASE(charTypes);
|
||||
TEST_CASE(stringTypes);
|
||||
TEST_CASE(getStrLength);
|
||||
TEST_CASE(getStrSize);
|
||||
TEST_CASE(getCharAt);
|
||||
|
@ -266,6 +268,102 @@ private:
|
|||
ASSERT_EQUALS(true, Token::multiCompare(&tok, "+|%or%|%oror%", 0) >= 0);
|
||||
}
|
||||
|
||||
void charTypes() const {
|
||||
Token tok;
|
||||
|
||||
tok.str("'a'");
|
||||
ASSERT_EQUALS(true, tok.isCChar());
|
||||
ASSERT_EQUALS(false, tok.isUtf8());
|
||||
ASSERT_EQUALS(false, tok.isUtf16());
|
||||
ASSERT_EQUALS(false, tok.isUtf32());
|
||||
ASSERT_EQUALS(false, tok.isLong());
|
||||
ASSERT_EQUALS(false, tok.isCMultiChar());
|
||||
|
||||
tok.str("u8'a'");
|
||||
ASSERT_EQUALS(false, tok.isCChar());
|
||||
ASSERT_EQUALS(true, tok.isUtf8());
|
||||
ASSERT_EQUALS(false, tok.isUtf16());
|
||||
ASSERT_EQUALS(false, tok.isUtf32());
|
||||
ASSERT_EQUALS(false, tok.isLong());
|
||||
ASSERT_EQUALS(false, tok.isCMultiChar());
|
||||
|
||||
tok.str("u'a'");
|
||||
ASSERT_EQUALS(false, tok.isCChar());
|
||||
ASSERT_EQUALS(false, tok.isUtf8());
|
||||
ASSERT_EQUALS(true, tok.isUtf16());
|
||||
ASSERT_EQUALS(false, tok.isUtf32());
|
||||
ASSERT_EQUALS(false, tok.isLong());
|
||||
ASSERT_EQUALS(false, tok.isCMultiChar());
|
||||
|
||||
tok.str("U'a'");
|
||||
ASSERT_EQUALS(false, tok.isCChar());
|
||||
ASSERT_EQUALS(false, tok.isUtf8());
|
||||
ASSERT_EQUALS(false, tok.isUtf16());
|
||||
ASSERT_EQUALS(true, tok.isUtf32());
|
||||
ASSERT_EQUALS(false, tok.isLong());
|
||||
ASSERT_EQUALS(false, tok.isCMultiChar());
|
||||
|
||||
tok.str("L'a'");
|
||||
ASSERT_EQUALS(false, tok.isCChar());
|
||||
ASSERT_EQUALS(false, tok.isUtf8());
|
||||
ASSERT_EQUALS(false, tok.isUtf16());
|
||||
ASSERT_EQUALS(false, tok.isUtf32());
|
||||
ASSERT_EQUALS(true, tok.isLong());
|
||||
ASSERT_EQUALS(false, tok.isCMultiChar());
|
||||
|
||||
tok.str("'aaa'");
|
||||
ASSERT_EQUALS(false, tok.isCChar());
|
||||
ASSERT_EQUALS(false, tok.isUtf8());
|
||||
ASSERT_EQUALS(false, tok.isUtf16());
|
||||
ASSERT_EQUALS(false, tok.isUtf32());
|
||||
ASSERT_EQUALS(false, tok.isLong());
|
||||
ASSERT_EQUALS(true, tok.isCMultiChar());
|
||||
}
|
||||
|
||||
void stringTypes() const {
|
||||
Token tok;
|
||||
|
||||
tok.str("\"a\"");
|
||||
ASSERT_EQUALS(true, tok.isCChar());
|
||||
ASSERT_EQUALS(false, tok.isUtf8());
|
||||
ASSERT_EQUALS(false, tok.isUtf16());
|
||||
ASSERT_EQUALS(false, tok.isUtf32());
|
||||
ASSERT_EQUALS(false, tok.isLong());
|
||||
ASSERT_EQUALS(false, tok.isCMultiChar());
|
||||
|
||||
tok.str("u8\"a\"");
|
||||
ASSERT_EQUALS(false, tok.isCChar());
|
||||
ASSERT_EQUALS(true, tok.isUtf8());
|
||||
ASSERT_EQUALS(false, tok.isUtf16());
|
||||
ASSERT_EQUALS(false, tok.isUtf32());
|
||||
ASSERT_EQUALS(false, tok.isLong());
|
||||
ASSERT_EQUALS(false, tok.isCMultiChar());
|
||||
|
||||
tok.str("u\"a\"");
|
||||
ASSERT_EQUALS(false, tok.isCChar());
|
||||
ASSERT_EQUALS(false, tok.isUtf8());
|
||||
ASSERT_EQUALS(true, tok.isUtf16());
|
||||
ASSERT_EQUALS(false, tok.isUtf32());
|
||||
ASSERT_EQUALS(false, tok.isLong());
|
||||
ASSERT_EQUALS(false, tok.isCMultiChar());
|
||||
|
||||
tok.str("U\"a\"");
|
||||
ASSERT_EQUALS(false, tok.isCChar());
|
||||
ASSERT_EQUALS(false, tok.isUtf8());
|
||||
ASSERT_EQUALS(false, tok.isUtf16());
|
||||
ASSERT_EQUALS(true, tok.isUtf32());
|
||||
ASSERT_EQUALS(false, tok.isLong());
|
||||
ASSERT_EQUALS(false, tok.isCMultiChar());
|
||||
|
||||
tok.str("L\"a\"");
|
||||
ASSERT_EQUALS(false, tok.isCChar());
|
||||
ASSERT_EQUALS(false, tok.isUtf8());
|
||||
ASSERT_EQUALS(false, tok.isUtf16());
|
||||
ASSERT_EQUALS(false, tok.isUtf32());
|
||||
ASSERT_EQUALS(true, tok.isLong());
|
||||
ASSERT_EQUALS(false, tok.isCMultiChar());
|
||||
}
|
||||
|
||||
void getStrLength() const {
|
||||
Token tok;
|
||||
|
||||
|
@ -296,18 +394,19 @@ private:
|
|||
|
||||
void getStrSize() const {
|
||||
Token tok;
|
||||
Settings settings;
|
||||
|
||||
tok.str("\"\"");
|
||||
ASSERT_EQUALS(sizeof(""), Token::getStrSize(&tok));
|
||||
ASSERT_EQUALS(sizeof(""), Token::getStrSize(&tok, &settings));
|
||||
|
||||
tok.str("\"abc\"");
|
||||
ASSERT_EQUALS(sizeof("abc"), Token::getStrSize(&tok));
|
||||
ASSERT_EQUALS(sizeof("abc"), Token::getStrSize(&tok, &settings));
|
||||
|
||||
tok.str("\"\\0abc\"");
|
||||
ASSERT_EQUALS(sizeof("\0abc"), Token::getStrSize(&tok));
|
||||
ASSERT_EQUALS(sizeof("\0abc"), Token::getStrSize(&tok, &settings));
|
||||
|
||||
tok.str("\"\\\\\"");
|
||||
ASSERT_EQUALS(sizeof("\\"), Token::getStrSize(&tok));
|
||||
ASSERT_EQUALS(sizeof("\\"), Token::getStrSize(&tok, &settings));
|
||||
}
|
||||
|
||||
void getCharAt() const {
|
||||
|
|
Loading…
Reference in New Issue