SymbolDatabase: Add type information in AST

This commit is contained in:
Daniel Marjamäki 2015-10-04 19:42:58 +02:00
parent 3bc21b8138
commit 9b253612ca
6 changed files with 240 additions and 2 deletions

View File

@ -3649,3 +3649,168 @@ bool SymbolDatabase::isReservedName(const std::string& iName) const
{
return (c_keywords.find(iName) != c_keywords.cend()) || (isCPP() && (cpp_keywords.find(iName) != cpp_keywords.cend()));
}
static void setValueType(Token *tok, ValueType::Sign sign, ValueType::Type type, unsigned int pointer)
{
tok->setValueType(new ValueType(sign,type,pointer));
Token *parent = const_cast<Token *>(tok->astParent());
if (!parent || parent->valueType())
return;
if (!parent->astOperand1() || !parent->astOperand1()->valueType())
return;
if (parent->str() == "[" && pointer > 0U) {
setValueType(parent, sign, type, pointer - 1U);
return;
}
if (parent->str() == "*" && !parent->astOperand2() && pointer > 0U) {
setValueType(parent, sign, type, pointer - 1U);
return;
}
if (parent->astOperand2() && !parent->astOperand2()->valueType())
return;
const ValueType *vt1 = parent->astOperand1()->valueType();
const ValueType *vt2 = parent->astOperand2() ? parent->astOperand2()->valueType() : nullptr;
if (parent->isArithmeticalOp() && vt2) {
if (vt1->pointer != 0U && vt2->pointer == 0U) {
setValueType(parent, vt1->sign, vt1->type, vt1->pointer);
return;
}
if (vt1->pointer == 0U && vt2->pointer != 0U) {
setValueType(parent, vt2->sign, vt2->type, vt2->pointer);
return;
}
if (vt1->pointer != 0U) { // result is pointer diff
setValueType(parent, ValueType::Sign::UNSIGNED, ValueType::Type::INT, 0U);
return;
}
if (vt1->type == ValueType::Type::DOUBLE || vt2->type == ValueType::Type::DOUBLE) {
setValueType(parent, ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::DOUBLE, 0U);
return;
}
if (vt1->type == ValueType::Type::FLOAT || vt2->type == ValueType::Type::FLOAT) {
setValueType(parent, ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::FLOAT, 0U);
return;
}
if (vt1->isIntegral() && vt2->isIntegral()) {
ValueType::Type t = (vt1->type > vt2->type) ? vt1->type : vt2->type;
setValueType(parent, ValueType::Sign::UNKNOWN_SIGN, t, 0U);
return;
}
}
}
void SymbolDatabase::setValueTypeInTokenList(Token *tokens)
{
for (Token *tok = tokens; tok; tok = tok->next())
tok->setValueType(nullptr);
for (Token *tok = tokens; tok; tok = tok->next()) {
if (tok->isNumber()) {
if (MathLib::isFloat(tok->str()))
::setValueType(tok, ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::FLOAT, 0U);
if (MathLib::isInt(tok->str()))
::setValueType(tok, (tok->str()[0] == '-') ? ValueType::Sign::SIGNED : ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::INT, 0U);
} else if (tok->isComparisonOp())
::setValueType(tok, ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::BOOL, 0U);
else if (tok->tokType() == Token::eChar)
::setValueType(tok, ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::CHAR, 0U);
else if (tok->tokType() == Token::eString)
::setValueType(tok, ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::CHAR, 1U);
else if (tok->str() == "(") {
// cast
if (!tok->astOperand2() && !Token::Match(tok, "( %name%")) {
ValueType::Sign s = ValueType::Sign::UNKNOWN_SIGN;
ValueType::Type t = ValueType::Type::UNKNOWN_TYPE;
unsigned int p = 0;
const Token *tok2;
for (tok2 = tok->next(); Token::Match(tok2, "%name%|*"); tok2 = tok2->next()) {
if (tok2->str() == "signed")
s = ValueType::Sign::SIGNED;
else if (tok2->str() == "unsigned")
s = ValueType::Sign::UNSIGNED;
else if (tok2->str() == "bool")
t = ValueType::Type::BOOL;
else if (tok2->str() == "char")
t = ValueType::Type::CHAR;
else if (tok2->str() == "short")
t = ValueType::Type::SHORT;
else if (tok2->str() == "int")
t = ValueType::Type::INT;
else if (tok2->str() == "long")
t = ValueType::Type::LONG;
else if (tok2->str() == "struct")
t = ValueType::Type::NONSTD;
else if (tok2->str() == "*")
p++;
}
if (tok2 && tok2->str() == ")" && t != ValueType::Type::UNKNOWN_TYPE)
::setValueType(tok, s, t, p);
}
} else if (tok->variable()) {
const Variable *var = tok->variable();
ValueType::Sign sign = ValueType::Sign::UNKNOWN_SIGN;
ValueType::Type type = ValueType::Type::UNKNOWN_TYPE;
unsigned int p = var->dimensions().size();
for (const Token *typeTok = var->typeStartToken(); Token::Match(typeTok, "%name%|*|&"); typeTok = typeTok->next()) {
if (typeTok->isUnsigned())
sign = ValueType::Sign::UNSIGNED;
else if (typeTok->isSigned())
sign = ValueType::Sign::SIGNED;
if (typeTok->isStandardType()) {
if (typeTok->str() == "bool")
type = ValueType::Type::BOOL;
else if (typeTok->str() == "char")
type = ValueType::Type::CHAR;
else if (typeTok->str() == "short")
type = ValueType::Type::SHORT;
else if (typeTok->str() == "int")
type = ValueType::Type::INT;
else if (typeTok->str() == "long")
type = ValueType::Type::LONG;
else if (typeTok->str() == "float")
type = ValueType::Type::FLOAT;
else if (typeTok->str() == "double")
type = ValueType::Type::DOUBLE;
}
if (typeTok->str() == "*")
p++;
}
if (type >= ValueType::Type::BOOL)
::setValueType(tok, sign, type, p);
}
}
}
std::string ValueType::str() const
{
std::string ret;
if (isIntegral()) {
if (sign == SIGNED)
ret = "signed ";
else if (sign == UNSIGNED)
ret = "unsigned ";
if (type == BOOL)
ret += "bool";
else if (type == CHAR)
ret += "char";
else if (type == SHORT)
ret += "short";
else if (type == INT)
ret += "int";
else if (type == LONG)
ret += "long";
else if (type == LONGLONG)
ret += "long long";
} else if (type == FLOAT)
ret = "float";
else if (type == DOUBLE)
ret = "double";
for (int p = 0; p < pointer; p++)
ret += "*";
return ret;
}

View File

@ -1008,6 +1008,9 @@ public:
bool isCPP() const;
/** Set valuetype in provided tokenlist */
static void setValueTypeInTokenList(Token *tokens);
private:
friend class Scope;
friend class Function;
@ -1024,7 +1027,6 @@ private:
/** Whether iName is a keyword as defined in http://en.cppreference.com/w/c/keyword and http://en.cppreference.com/w/cpp/keyword*/
bool isReservedName(const std::string& iName) const;
const Tokenizer *_tokenizer;
const Settings *_settings;
ErrorLogger *_errorLogger;
@ -1036,5 +1038,22 @@ private:
std::list<Type> _blankTypes;
};
/** Value type */
class ValueType {
public:
enum Sign {UNKNOWN_SIGN, SIGNED, UNSIGNED} sign;
enum Type {UNKNOWN_TYPE, NONSTD, BOOL, CHAR, SHORT, INT, LONG, LONGLONG, FLOAT, DOUBLE} type;
unsigned int pointer; // 0=>not pointer, 1=>*, 2=>**, 3=>***, etc
ValueType(enum Sign s, enum Type t, unsigned int p) : sign(s), type(t), pointer(p) {}
bool isIntegral() const {
return (type >= ValueType::Type::BOOL && type <= ValueType::Type::LONGLONG);
}
std::string str() const;
};
//---------------------------------------------------------------------------
#endif // symboldatabaseH

View File

@ -49,13 +49,15 @@ Token::Token(Token **t) :
_astOperand1(nullptr),
_astOperand2(nullptr),
_astParent(nullptr),
_originalName(nullptr)
_originalName(nullptr),
valuetype(nullptr)
{
}
Token::~Token()
{
delete _originalName;
delete valuetype;
}
void Token::update_property_info()
@ -1508,3 +1510,12 @@ void Token::assignProgressValues(Token *tok)
for (Token *tok2 = tok; tok2; tok2 = tok2->next())
tok2->_progressValue = count++ * 100 / total_count;
}
void Token::setValueType(ValueType *vt)
{
if (vt != valuetype) {
delete valuetype;
valuetype = vt;
}
}

View File

@ -33,6 +33,7 @@ class Scope;
class Type;
class Function;
class Variable;
class ValueType;
class Settings;
/// @addtogroup Core
@ -223,6 +224,11 @@ public:
**/
static std::string getCharAt(const Token *tok, std::size_t index);
const ValueType *valueType() const {
return valuetype;
}
void setValueType(ValueType *vt);
Token::Type tokType() const {
return _tokType;
}
@ -847,6 +853,9 @@ private:
// original name like size_t
std::string* _originalName;
// ValueType
ValueType *valuetype;
public:
void astOperand1(Token *tok);
void astOperand2(Token *tok);

View File

@ -1726,6 +1726,7 @@ bool Tokenizer::tokenize(std::istream &code,
}
list.createAst();
SymbolDatabase::setValueTypeInTokenList(list.front());
ValueFlow::setValues(&list, _symbolDatabase, _errorLogger, _settings);
}

View File

@ -262,6 +262,8 @@ private:
TEST_CASE(lambda); // ticket #5867
TEST_CASE(circularDependencies); // 6298
TEST_CASE(valuetype);
}
void array() const {
@ -2943,6 +2945,37 @@ private:
" c.f();\n"
"}");
}
std::string typeOf(const char code[], const char str[]) {
Tokenizer tokenizer(&settings, this);
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
tokenizer.getSymbolDatabase();
const Token *tok = Token::findsimplematch(tokenizer.tokens(),str);
return tok->valueType()->str();
}
void valuetype() {
// Constant calculations
ASSERT_EQUALS("int", typeOf("1 + 2", "+"));
//ASSERT_EQUALS("long", typeOf("1L + 2", "+"));
//ASSERT_EQUALS("long long", typeOf("1LL + 2", "+"));
ASSERT_EQUALS("float", typeOf("1.2f + 3", "+"));
ASSERT_EQUALS("float", typeOf("1 + 2.3f", "+"));
// char *
ASSERT_EQUALS("char*", typeOf("\"hello\" + 1", "+"));
ASSERT_EQUALS("char", typeOf("\"hello\"[1]", "["));
ASSERT_EQUALS("char", typeOf("*\"hello\"", "*"));
// Variable calculations
ASSERT_EQUALS("int", typeOf("int x; a = x + 1;", "+"));
ASSERT_EQUALS("float", typeOf("float x; a = x + 1;", "+"));
// array..
ASSERT_EQUALS("int*", typeOf("int x[10]; a = x + 1;", "+"));
ASSERT_EQUALS("int", typeOf("int x[10]; a = x[0] + 1;", "+"));
}
};
REGISTER_TEST(TestSymbolDatabase)