Symboldatabase: Improve valuetypes for containers, iterators, and smart pointers (#3398)
This commit is contained in:
parent
f946bbc249
commit
fdaeaacc40
|
@ -73,6 +73,7 @@ static bool isRaiiClass(const ValueType *valueType, bool cpp, bool defaultReturn
|
|||
return true;
|
||||
return defaultReturn;
|
||||
|
||||
case ValueType::Type::SMART_POINTER:
|
||||
case ValueType::Type::CONTAINER:
|
||||
case ValueType::Type::ITERATOR:
|
||||
case ValueType::Type::VOID:
|
||||
|
|
|
@ -500,6 +500,7 @@ Library::Error Library::load(const tinyxml2::XMLDocument &doc)
|
|||
if (!className)
|
||||
return Error(ErrorCode::MISSING_ATTRIBUTE, "class-name");
|
||||
SmartPointer& smartPointer = smartPointers[className];
|
||||
smartPointer.name = className;
|
||||
for (const tinyxml2::XMLElement* smartPointerNode = node->FirstChildElement(); smartPointerNode;
|
||||
smartPointerNode = smartPointerNode->NextSiblingElement()) {
|
||||
const std::string smartPointerNodeName = smartPointerNode->Name();
|
||||
|
|
|
@ -431,6 +431,7 @@ public:
|
|||
std::vector<std::string> defines; // to provide some library defines
|
||||
|
||||
struct SmartPointer {
|
||||
std::string name = "";
|
||||
bool unique = false;
|
||||
};
|
||||
|
||||
|
|
|
@ -5717,6 +5717,17 @@ static void setAutoTokenProperties(Token * const autoTok)
|
|||
autoTok->isStandardType(true);
|
||||
}
|
||||
|
||||
static bool isContainerYieldElement(Library::Container::Yield yield)
|
||||
{
|
||||
return yield == Library::Container::Yield::ITEM || yield == Library::Container::Yield::AT_INDEX ||
|
||||
yield == Library::Container::Yield::BUFFER || yield == Library::Container::Yield::BUFFER_NT;
|
||||
}
|
||||
|
||||
static bool isContainerYieldPointer(Library::Container::Yield yield)
|
||||
{
|
||||
return yield == Library::Container::Yield::BUFFER || yield == Library::Container::Yield::BUFFER_NT;
|
||||
}
|
||||
|
||||
void SymbolDatabase::setValueType(Token *tok, const ValueType &valuetype)
|
||||
{
|
||||
tok->setValueType(new ValueType(valuetype));
|
||||
|
@ -5747,10 +5758,18 @@ void SymbolDatabase::setValueType(Token *tok, const ValueType &valuetype)
|
|||
return;
|
||||
}
|
||||
|
||||
if (vt1 && vt1->container && vt1->containerTypeToken && Token::Match(parent, ". %name% (") && vt1->container->getYield(parent->next()->str()) == Library::Container::Yield::ITEM) {
|
||||
if (vt1 && vt1->container && vt1->containerTypeToken && Token::Match(parent, ". %name% (") &&
|
||||
isContainerYieldElement(vt1->container->getYield(parent->next()->str()))) {
|
||||
ValueType item;
|
||||
if (parsedecl(vt1->containerTypeToken, &item, mDefaultSignedness, mSettings))
|
||||
if (parsedecl(vt1->containerTypeToken, &item, mDefaultSignedness, mSettings)) {
|
||||
if (item.constness == 0)
|
||||
item.constness = vt1->constness;
|
||||
if (isContainerYieldPointer(vt1->container->getYield(parent->next()->str())))
|
||||
item.pointer += 1;
|
||||
else
|
||||
item.reference = Reference::LValue;
|
||||
setValueType(parent->tokAt(2), item);
|
||||
}
|
||||
}
|
||||
|
||||
if (vt1 && vt1->smartPointerType && Token::Match(parent, ". %name% (") && parent->originalName() == "->" && !parent->next()->function()) {
|
||||
|
@ -5840,6 +5859,29 @@ void SymbolDatabase::setValueType(Token *tok, const ValueType &valuetype)
|
|||
setValueType(parent, vt);
|
||||
return;
|
||||
}
|
||||
// Dereference iterator
|
||||
if (parent->str() == "*" && !parent->astOperand2() && valuetype.type == ValueType::Type::ITERATOR &&
|
||||
valuetype.containerTypeToken) {
|
||||
ValueType vt;
|
||||
if (parsedecl(valuetype.containerTypeToken, &vt, mDefaultSignedness, mSettings)) {
|
||||
if (vt.constness == 0)
|
||||
vt.constness = valuetype.constness;
|
||||
vt.reference = Reference::LValue;
|
||||
setValueType(parent, vt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
// Dereference smart pointer
|
||||
if (parent->str() == "*" && !parent->astOperand2() && valuetype.type == ValueType::Type::SMART_POINTER &&
|
||||
valuetype.smartPointerTypeToken) {
|
||||
ValueType vt;
|
||||
if (parsedecl(valuetype.smartPointerTypeToken, &vt, mDefaultSignedness, mSettings)) {
|
||||
if (vt.constness == 0)
|
||||
vt.constness = valuetype.constness;
|
||||
setValueType(parent, vt);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (parent->str() == "*" && Token::simpleMatch(parent->astOperand2(), "[") && valuetype.pointer > 0U) {
|
||||
const Token *op1 = parent->astOperand2()->astOperand1();
|
||||
while (op1 && op1->str() == "[")
|
||||
|
@ -6095,7 +6137,7 @@ static const Token * parsedecl(const Token *type, ValueType * const valuetype, V
|
|||
if (!valuetype->typeScope && !valuetype->smartPointerType)
|
||||
valuetype->type = ValueType::Type::UNKNOWN_TYPE;
|
||||
else if (valuetype->smartPointerType)
|
||||
valuetype->type = ValueType::Type::NONSTD;
|
||||
valuetype->type = ValueType::Type::SMART_POINTER;
|
||||
else if (valuetype->typeScope->type == Scope::eEnum) {
|
||||
const Token * enum_type = valuetype->typeScope->enumType;
|
||||
if (enum_type) {
|
||||
|
@ -6193,7 +6235,7 @@ static const Token * parsedecl(const Token *type, ValueType * const valuetype, V
|
|||
valuetype->smartPointer = smartPointer;
|
||||
valuetype->smartPointerTypeToken = argTok->next();
|
||||
valuetype->smartPointerType = argTok->next()->type();
|
||||
valuetype->type = ValueType::Type::NONSTD;
|
||||
valuetype->type = ValueType::Type::SMART_POINTER;
|
||||
type = argTok->link();
|
||||
if (type)
|
||||
type = type->next();
|
||||
|
@ -6478,6 +6520,13 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
|
|||
setValueType(tok, vt);
|
||||
continue;
|
||||
}
|
||||
if (const Library::SmartPointer* sp = mSettings->library.detectSmartPointer(typeStartToken)) {
|
||||
ValueType vt;
|
||||
vt.type = ValueType::Type::SMART_POINTER;
|
||||
vt.smartPointer = sp;
|
||||
setValueType(tok, vt);
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string e = tok->astOperand1()->expressionString();
|
||||
|
||||
|
@ -6487,9 +6536,15 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
|
|||
if (vt.typeScope) {
|
||||
vt.smartPointerType = vt.typeScope->definedType;
|
||||
vt.typeScope = nullptr;
|
||||
setValueType(tok, vt);
|
||||
continue;
|
||||
}
|
||||
if (e == "std::make_shared" && mSettings->library.smartPointers.count("std::shared_ptr") > 0)
|
||||
vt.smartPointer = &mSettings->library.smartPointers.at("std::shared_ptr");
|
||||
if (e == "std::make_unique" && mSettings->library.smartPointers.count("std::unique_ptr") > 0)
|
||||
vt.smartPointer = &mSettings->library.smartPointers.at("std::unique_ptr");
|
||||
vt.type = ValueType::Type::SMART_POINTER;
|
||||
vt.smartPointerTypeToken = tok->astOperand1()->tokAt(3);
|
||||
setValueType(tok, vt);
|
||||
continue;
|
||||
}
|
||||
|
||||
ValueType podtype;
|
||||
|
@ -6527,6 +6582,8 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
|
|||
ValueType vt;
|
||||
vt.type = ValueType::Type::ITERATOR;
|
||||
vt.container = cont;
|
||||
vt.containerTypeToken =
|
||||
tok->astOperand1()->astOperand1()->valueType()->containerTypeToken;
|
||||
setValueType(tok, vt);
|
||||
}
|
||||
}
|
||||
|
@ -6740,6 +6797,9 @@ std::string ValueType::dump() const
|
|||
case RECORD:
|
||||
ret << "valueType-type=\"record\"";
|
||||
break;
|
||||
case SMART_POINTER:
|
||||
ret << "valueType-type=\"smart-pointer\"";
|
||||
break;
|
||||
case CONTAINER:
|
||||
ret << "valueType-type=\"container\"";
|
||||
break;
|
||||
|
@ -6904,8 +6964,8 @@ std::string ValueType::str() const
|
|||
ret += " container(" + container->startPattern + ')';
|
||||
} else if (type == ValueType::Type::ITERATOR && container) {
|
||||
ret += " iterator(" + container->startPattern + ')';
|
||||
} else if (smartPointerType) {
|
||||
ret += " smart-pointer<" + smartPointerType->name() + ">";
|
||||
} else if (type == ValueType::Type::SMART_POINTER && smartPointer) {
|
||||
ret += " smart-pointer(" + smartPointer->name + ")";
|
||||
}
|
||||
for (unsigned int p = 0; p < pointer; p++) {
|
||||
ret += " *";
|
||||
|
|
|
@ -1217,7 +1217,26 @@ enum class Reference {
|
|||
class CPPCHECKLIB ValueType {
|
||||
public:
|
||||
enum Sign { UNKNOWN_SIGN, SIGNED, UNSIGNED } sign;
|
||||
enum Type { UNKNOWN_TYPE, NONSTD, RECORD, CONTAINER, ITERATOR, VOID, BOOL, CHAR, SHORT, WCHAR_T, INT, LONG, LONGLONG, UNKNOWN_INT, FLOAT, DOUBLE, LONGDOUBLE } type;
|
||||
enum Type {
|
||||
UNKNOWN_TYPE,
|
||||
NONSTD,
|
||||
RECORD,
|
||||
SMART_POINTER,
|
||||
CONTAINER,
|
||||
ITERATOR,
|
||||
VOID,
|
||||
BOOL,
|
||||
CHAR,
|
||||
SHORT,
|
||||
WCHAR_T,
|
||||
INT,
|
||||
LONG,
|
||||
LONGLONG,
|
||||
UNKNOWN_INT,
|
||||
FLOAT,
|
||||
DOUBLE,
|
||||
LONGDOUBLE
|
||||
} type;
|
||||
nonneg int bits; ///< bitfield bitcount
|
||||
nonneg int pointer; ///< 0=>not pointer, 1=>*, 2=>**, 3=>***, etc
|
||||
nonneg int constness; ///< bit 0=data, bit 1=*, bit 2=**
|
||||
|
|
|
@ -2058,7 +2058,9 @@ private:
|
|||
" auto p = x.data();\n"
|
||||
" return p;\n"
|
||||
"}");
|
||||
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:2] -> [test.cpp:4]: (error) Returning object that points to local variable 'x' that will be invalid when returning.\n", errout.str());
|
||||
ASSERT_EQUALS(
|
||||
"[test.cpp:3] -> [test.cpp:2] -> [test.cpp:4]: (error) Returning pointer to local variable 'x' that will be invalid when returning.\n",
|
||||
errout.str());
|
||||
|
||||
check("auto f() {\n"
|
||||
" std::vector<int> x;\n"
|
||||
|
|
|
@ -7438,7 +7438,12 @@ private:
|
|||
vector.startPattern2 = "Vector !!::";
|
||||
vector.type_templateArgNo = 0;
|
||||
vector.arrayLike_indexOp = true;
|
||||
vector.functions["front"] = Library::Container::Function{Library::Container::Action::NO_ACTION, Library::Container::Yield::ITEM};
|
||||
vector.functions["front"] =
|
||||
Library::Container::Function{Library::Container::Action::NO_ACTION, Library::Container::Yield::ITEM};
|
||||
vector.functions["data"] =
|
||||
Library::Container::Function{Library::Container::Action::NO_ACTION, Library::Container::Yield::BUFFER};
|
||||
vector.functions["begin"] = Library::Container::Function{Library::Container::Action::NO_ACTION,
|
||||
Library::Container::Yield::START_ITERATOR};
|
||||
set.library.containers["Vector"] = vector;
|
||||
Library::Container string;
|
||||
string.startPattern = "test :: string";
|
||||
|
@ -7447,13 +7452,29 @@ private:
|
|||
set.library.containers["test::string"] = string;
|
||||
ASSERT_EQUALS("signed int", typeOf("Vector<int> v; v[0]=3;", "[", "test.cpp", &set));
|
||||
ASSERT_EQUALS("container(test :: string)", typeOf("{return test::string();}", "(", "test.cpp", &set));
|
||||
ASSERT_EQUALS("container(test :: string)", typeOf("void foo(Vector<test::string> v) { for (auto s: v) { x=s+s; } }", "s", "test.cpp", &set));
|
||||
ASSERT_EQUALS("container(test :: string)", typeOf("void foo(Vector<test::string> v) { for (auto s: v) { x=s+s; } }", "+", "test.cpp", &set));
|
||||
ASSERT_EQUALS("container(test :: string)", typeOf("Vector<test::string> v; x = v.front();", "(", "test.cpp", &set));
|
||||
ASSERT_EQUALS("container(test :: string)", typeOf("void foo(){test::string s; return \"x\"+s;}", "+", "test.cpp", &set));
|
||||
ASSERT_EQUALS("container(test :: string)", typeOf("void foo(){test::string s; return s+\"x\";}", "+", "test.cpp", &set));
|
||||
ASSERT_EQUALS("container(test :: string)", typeOf("void foo(){test::string s; return 'x'+s;}", "+", "test.cpp", &set));
|
||||
ASSERT_EQUALS("container(test :: string)", typeOf("void foo(){test::string s; return s+'x';}", "+", "test.cpp", &set));
|
||||
ASSERT_EQUALS(
|
||||
"container(test :: string)",
|
||||
typeOf("void foo(Vector<test::string> v) { for (auto s: v) { x=s+s; } }", "s", "test.cpp", &set));
|
||||
ASSERT_EQUALS(
|
||||
"container(test :: string)",
|
||||
typeOf("void foo(Vector<test::string> v) { for (auto s: v) { x=s+s; } }", "+", "test.cpp", &set));
|
||||
ASSERT_EQUALS("container(test :: string) &",
|
||||
typeOf("Vector<test::string> v; x = v.front();", "(", "test.cpp", &set));
|
||||
ASSERT_EQUALS("container(test :: string) *",
|
||||
typeOf("Vector<test::string> v; x = v.data();", "(", "test.cpp", &set));
|
||||
ASSERT_EQUALS("signed int &", typeOf("Vector<int> v; x = v.front();", "(", "test.cpp", &set));
|
||||
ASSERT_EQUALS("signed int *", typeOf("Vector<int> v; x = v.data();", "(", "test.cpp", &set));
|
||||
ASSERT_EQUALS("signed int * *", typeOf("Vector<int*> v; x = v.data();", "(", "test.cpp", &set));
|
||||
ASSERT_EQUALS("iterator(Vector <)", typeOf("Vector<int> v; x = v.begin();", "(", "test.cpp", &set));
|
||||
ASSERT_EQUALS("signed int &", typeOf("Vector<int> v; x = *v.begin();", "*", "test.cpp", &set));
|
||||
ASSERT_EQUALS("container(test :: string)",
|
||||
typeOf("void foo(){test::string s; return \"x\"+s;}", "+", "test.cpp", &set));
|
||||
ASSERT_EQUALS("container(test :: string)",
|
||||
typeOf("void foo(){test::string s; return s+\"x\";}", "+", "test.cpp", &set));
|
||||
ASSERT_EQUALS("container(test :: string)",
|
||||
typeOf("void foo(){test::string s; return 'x'+s;}", "+", "test.cpp", &set));
|
||||
ASSERT_EQUALS("container(test :: string)",
|
||||
typeOf("void foo(){test::string s; return s+'x';}", "+", "test.cpp", &set));
|
||||
}
|
||||
|
||||
// new
|
||||
|
@ -7474,7 +7495,14 @@ private:
|
|||
ASSERT_EQUALS("", typeOf("; int x[10] = { [3]=1 };", "[ 3 ]"));
|
||||
|
||||
// std::make_shared
|
||||
ASSERT_EQUALS("smart-pointer<C>", typeOf("class C {}; x = std::make_shared<C>();", "("));
|
||||
{
|
||||
Settings set;
|
||||
Library::SmartPointer sharedPtr;
|
||||
sharedPtr.name = "std::shared_ptr";
|
||||
set.library.smartPointers["std::shared_ptr"] = sharedPtr;
|
||||
ASSERT_EQUALS("smart-pointer(std::shared_ptr)",
|
||||
typeOf("class C {}; x = std::make_shared<C>();", "(", "test.cpp", &set));
|
||||
}
|
||||
|
||||
// return
|
||||
{
|
||||
|
@ -7486,6 +7514,17 @@ private:
|
|||
sC.library.containers["C"] = c;
|
||||
ASSERT_EQUALS("container(C)", typeOf("C f(char *p) { char data[10]; return data; }", "return", "test.cpp", &sC));
|
||||
}
|
||||
// Smart pointer
|
||||
{
|
||||
Settings set;
|
||||
Library::SmartPointer myPtr;
|
||||
myPtr.name = "MyPtr";
|
||||
set.library.smartPointers["MyPtr"] = myPtr;
|
||||
ASSERT_EQUALS("smart-pointer(MyPtr)",
|
||||
typeOf("void f() { MyPtr<int> p; return p; }", "p ;", "test.cpp", &set));
|
||||
ASSERT_EQUALS("signed int", typeOf("void f() { MyPtr<int> p; return *p; }", "* p ;", "test.cpp", &set));
|
||||
ASSERT_EQUALS("smart-pointer(MyPtr)", typeOf("void f() {return MyPtr<int>();}", "(", "test.cpp", &set));
|
||||
}
|
||||
}
|
||||
|
||||
void variadic1() { // #7453
|
||||
|
|
Loading…
Reference in New Issue