sped up `Tokenizer::dump()` (#5009)
Scanning the `cli` folder with `DISABLE_VALUEFLOW=1` `Tokenizer::dump()` will consume almost 25% of the total Ir count when an addon is specified. This is mainly caused by the usage of `std::ostream`. Encountered while profiling #4958.
This commit is contained in:
parent
98401a3046
commit
0fadf9ed25
|
@ -315,8 +315,8 @@ static void createDumpFile(const Settings& settings,
|
|||
break;
|
||||
}
|
||||
|
||||
fdump << "<?xml version=\"1.0\"?>" << std::endl;
|
||||
fdump << "<dumps" << language << ">" << std::endl;
|
||||
fdump << "<?xml version=\"1.0\"?>\n";
|
||||
fdump << "<dumps" << language << ">\n";
|
||||
fdump << " <platform"
|
||||
<< " name=\"" << settings.platform.toString() << '\"'
|
||||
<< " char_bit=\"" << settings.platform.char_bit << '\"'
|
||||
|
@ -325,7 +325,7 @@ static void createDumpFile(const Settings& settings,
|
|||
<< " long_bit=\"" << settings.platform.long_bit << '\"'
|
||||
<< " long_long_bit=\"" << settings.platform.long_long_bit << '\"'
|
||||
<< " pointer_bit=\"" << (settings.platform.sizeof_pointer * settings.platform.char_bit) << '\"'
|
||||
<< "/>\n";
|
||||
<< "/>" << '\n';
|
||||
}
|
||||
|
||||
static std::string executeAddon(const AddonInfo &addonInfo,
|
||||
|
@ -571,16 +571,16 @@ unsigned int CppCheck::check(const std::string &path)
|
|||
std::string dumpFile;
|
||||
createDumpFile(mSettings, path, fdump, dumpFile);
|
||||
if (fdump.is_open()) {
|
||||
fdump << "<dump cfg=\"\">" << std::endl;
|
||||
fdump << "<dump cfg=\"\">\n";
|
||||
for (const ErrorMessage& errmsg: compilerWarnings)
|
||||
fdump << " <clang-warning file=\"" << toxml(errmsg.callStack.front().getfile()) << "\" line=\"" << errmsg.callStack.front().line << "\" column=\"" << errmsg.callStack.front().column << "\" message=\"" << toxml(errmsg.shortMessage()) << "\"/>\n";
|
||||
fdump << " <standards>" << std::endl;
|
||||
fdump << " <c version=\"" << mSettings.standards.getC() << "\"/>" << std::endl;
|
||||
fdump << " <cpp version=\"" << mSettings.standards.getCPP() << "\"/>" << std::endl;
|
||||
fdump << " </standards>" << std::endl;
|
||||
fdump << " <standards>\n";
|
||||
fdump << " <c version=\"" << mSettings.standards.getC() << "\"/>\n";
|
||||
fdump << " <cpp version=\"" << mSettings.standards.getCPP() << "\"/>\n";
|
||||
fdump << " </standards>\n";
|
||||
tokenizer.dump(fdump);
|
||||
fdump << "</dump>" << std::endl;
|
||||
fdump << "</dumps>" << std::endl;
|
||||
fdump << "</dump>\n";
|
||||
fdump << "</dumps>\n";
|
||||
fdump.close();
|
||||
}
|
||||
|
||||
|
|
|
@ -731,36 +731,36 @@ std::string ErrorMessage::FileLocation::stringify() const
|
|||
|
||||
std::string ErrorLogger::toxml(const std::string &str)
|
||||
{
|
||||
std::ostringstream xml;
|
||||
std::string xml;
|
||||
for (const unsigned char c : str) {
|
||||
switch (c) {
|
||||
case '<':
|
||||
xml << "<";
|
||||
xml += "<";
|
||||
break;
|
||||
case '>':
|
||||
xml << ">";
|
||||
xml += ">";
|
||||
break;
|
||||
case '&':
|
||||
xml << "&";
|
||||
xml += "&";
|
||||
break;
|
||||
case '\"':
|
||||
xml << """;
|
||||
xml += """;
|
||||
break;
|
||||
case '\'':
|
||||
xml << "'";
|
||||
xml += "'";
|
||||
break;
|
||||
case '\0':
|
||||
xml << "\\0";
|
||||
xml += "\\0";
|
||||
break;
|
||||
default:
|
||||
if (c >= ' ' && c <= 0x7f)
|
||||
xml << c;
|
||||
xml += c;
|
||||
else
|
||||
xml << 'x';
|
||||
xml += 'x';
|
||||
break;
|
||||
}
|
||||
}
|
||||
return xml.str();
|
||||
return xml;
|
||||
}
|
||||
|
||||
std::string ErrorLogger::plistHeader(const std::string &version, const std::vector<std::string> &files)
|
||||
|
|
|
@ -3615,26 +3615,50 @@ bool Variable::arrayDimensions(const Settings* settings, bool& isContainer)
|
|||
return arr;
|
||||
}
|
||||
|
||||
static std::string scopeTypeToString(Scope::ScopeType type)
|
||||
{
|
||||
switch (type) {
|
||||
case Scope::ScopeType::eGlobal:
|
||||
return "Global";
|
||||
case Scope::ScopeType::eClass:
|
||||
return "Class";
|
||||
case Scope::ScopeType::eStruct:
|
||||
return "Struct";
|
||||
case Scope::ScopeType::eUnion:
|
||||
return "Union";
|
||||
case Scope::ScopeType::eNamespace:
|
||||
return "Namespace";
|
||||
case Scope::ScopeType::eFunction:
|
||||
return "Function";
|
||||
case Scope::ScopeType::eIf:
|
||||
return "If";
|
||||
case Scope::ScopeType::eElse:
|
||||
return "Else";
|
||||
case Scope::ScopeType::eFor:
|
||||
return "For";
|
||||
case Scope::ScopeType::eWhile:
|
||||
return "While";
|
||||
case Scope::ScopeType::eDo:
|
||||
return "Do";
|
||||
case Scope::ScopeType::eSwitch:
|
||||
return "Switch";
|
||||
case Scope::ScopeType::eTry:
|
||||
return "Try";
|
||||
case Scope::ScopeType::eCatch:
|
||||
return "Catch";
|
||||
case Scope::ScopeType::eUnconditional:
|
||||
return "Unconditional";
|
||||
case Scope::ScopeType::eLambda:
|
||||
return "Lambda";
|
||||
case Scope::ScopeType::eEnum:
|
||||
return "Enum";
|
||||
}
|
||||
return "Unknown";
|
||||
}
|
||||
|
||||
static std::ostream & operator << (std::ostream & s, Scope::ScopeType type)
|
||||
{
|
||||
s << (type == Scope::eGlobal ? "Global" :
|
||||
type == Scope::eClass ? "Class" :
|
||||
type == Scope::eStruct ? "Struct" :
|
||||
type == Scope::eUnion ? "Union" :
|
||||
type == Scope::eNamespace ? "Namespace" :
|
||||
type == Scope::eFunction ? "Function" :
|
||||
type == Scope::eIf ? "If" :
|
||||
type == Scope::eElse ? "Else" :
|
||||
type == Scope::eFor ? "For" :
|
||||
type == Scope::eWhile ? "While" :
|
||||
type == Scope::eDo ? "Do" :
|
||||
type == Scope::eSwitch ? "Switch" :
|
||||
type == Scope::eTry ? "Try" :
|
||||
type == Scope::eCatch ? "Catch" :
|
||||
type == Scope::eUnconditional ? "Unconditional" :
|
||||
type == Scope::eLambda ? "Lambda" :
|
||||
type == Scope::eEnum ? "Enum" :
|
||||
"Unknown");
|
||||
s << scopeTypeToString(type);
|
||||
return s;
|
||||
}
|
||||
|
||||
|
@ -4010,137 +4034,223 @@ void SymbolDatabase::printOut(const char *title) const
|
|||
|
||||
void SymbolDatabase::printXml(std::ostream &out) const
|
||||
{
|
||||
out << std::setiosflags(std::ios::boolalpha);
|
||||
std::string outs;
|
||||
|
||||
std::set<const Variable *> variables;
|
||||
|
||||
// Scopes..
|
||||
out << " <scopes>" << std::endl;
|
||||
outs += " <scopes>\n";
|
||||
for (std::list<Scope>::const_iterator scope = scopeList.cbegin(); scope != scopeList.cend(); ++scope) {
|
||||
out << " <scope";
|
||||
out << " id=\"" << &*scope << "\"";
|
||||
out << " type=\"" << scope->type << "\"";
|
||||
if (!scope->className.empty())
|
||||
out << " className=\"" << ErrorLogger::toxml(scope->className) << "\"";
|
||||
if (scope->bodyStart)
|
||||
out << " bodyStart=\"" << scope->bodyStart << '\"';
|
||||
if (scope->bodyEnd)
|
||||
out << " bodyEnd=\"" << scope->bodyEnd << '\"';
|
||||
if (scope->nestedIn)
|
||||
out << " nestedIn=\"" << scope->nestedIn << "\"";
|
||||
if (scope->function)
|
||||
out << " function=\"" << scope->function << "\"";
|
||||
if (scope->definedType)
|
||||
out << " definedType=\"" << scope->definedType << "\"";
|
||||
outs += " <scope";
|
||||
outs += " id=\"";
|
||||
outs += ptr_to_string(&*scope);
|
||||
outs += "\"";
|
||||
outs += " type=\"";
|
||||
outs += scopeTypeToString(scope->type);
|
||||
outs += "\"";
|
||||
if (!scope->className.empty()) {
|
||||
outs += " className=\"";
|
||||
outs += ErrorLogger::toxml(scope->className);
|
||||
outs += "\"";
|
||||
}
|
||||
if (scope->bodyStart) {
|
||||
outs += " bodyStart=\"";
|
||||
outs += ptr_to_string(scope->bodyStart);
|
||||
outs += '\"';
|
||||
}
|
||||
if (scope->bodyEnd) {
|
||||
outs += " bodyEnd=\"";
|
||||
outs += ptr_to_string(scope->bodyEnd);
|
||||
outs += '\"';
|
||||
}
|
||||
if (scope->nestedIn) {
|
||||
outs += " nestedIn=\"";
|
||||
outs += ptr_to_string(scope->nestedIn);
|
||||
outs += "\"";
|
||||
}
|
||||
if (scope->function) {
|
||||
outs += " function=\"";
|
||||
outs += ptr_to_string(scope->function);
|
||||
outs += "\"";
|
||||
}
|
||||
if (scope->definedType) {
|
||||
outs += " definedType=\"";
|
||||
outs += ptr_to_string(scope->definedType);
|
||||
outs += "\"";
|
||||
}
|
||||
if (scope->functionList.empty() && scope->varlist.empty())
|
||||
out << "/>" << std::endl;
|
||||
outs += "/>\n";
|
||||
else {
|
||||
out << '>' << std::endl;
|
||||
outs += ">\n";
|
||||
if (!scope->functionList.empty()) {
|
||||
out << " <functionList>" << std::endl;
|
||||
outs += " <functionList>\n";
|
||||
for (std::list<Function>::const_iterator function = scope->functionList.cbegin(); function != scope->functionList.cend(); ++function) {
|
||||
out << " <function id=\"" << &*function
|
||||
<< "\" token=\"" << function->token
|
||||
<< "\" tokenDef=\"" << function->tokenDef
|
||||
<< "\" name=\"" << ErrorLogger::toxml(function->name()) << '\"';
|
||||
out << " type=\"" << (function->type == Function::eConstructor? "Constructor" :
|
||||
function->type == Function::eCopyConstructor ? "CopyConstructor" :
|
||||
function->type == Function::eMoveConstructor ? "MoveConstructor" :
|
||||
function->type == Function::eOperatorEqual ? "OperatorEqual" :
|
||||
function->type == Function::eDestructor ? "Destructor" :
|
||||
function->type == Function::eFunction ? "Function" :
|
||||
function->type == Function::eLambda ? "Lambda" :
|
||||
"Unknown") << '\"';
|
||||
outs += " <function id=\"";
|
||||
outs += ptr_to_string(&*function);
|
||||
outs += "\" token=\"";
|
||||
outs += ptr_to_string(function->token);
|
||||
outs += "\" tokenDef=\"";
|
||||
outs += ptr_to_string(function->tokenDef);
|
||||
outs += "\" name=\"";
|
||||
outs += ErrorLogger::toxml(function->name());
|
||||
outs += '\"';
|
||||
outs += " type=\"";
|
||||
outs += (function->type == Function::eConstructor? "Constructor" :
|
||||
function->type == Function::eCopyConstructor ? "CopyConstructor" :
|
||||
function->type == Function::eMoveConstructor ? "MoveConstructor" :
|
||||
function->type == Function::eOperatorEqual ? "OperatorEqual" :
|
||||
function->type == Function::eDestructor ? "Destructor" :
|
||||
function->type == Function::eFunction ? "Function" :
|
||||
function->type == Function::eLambda ? "Lambda" :
|
||||
"Unknown");
|
||||
outs += '\"';
|
||||
if (function->nestedIn->definedType) {
|
||||
if (function->hasVirtualSpecifier())
|
||||
out << " hasVirtualSpecifier=\"true\"";
|
||||
outs += " hasVirtualSpecifier=\"true\"";
|
||||
else if (function->isImplicitlyVirtual())
|
||||
out << " isImplicitlyVirtual=\"true\"";
|
||||
outs += " isImplicitlyVirtual=\"true\"";
|
||||
}
|
||||
if (function->access == AccessControl::Public || function->access == AccessControl::Protected || function->access == AccessControl::Private) {
|
||||
outs += " access=\"";
|
||||
outs += accessControlToString(function->access);
|
||||
outs +="\"";
|
||||
}
|
||||
if (function->access == AccessControl::Public || function->access == AccessControl::Protected || function->access == AccessControl::Private)
|
||||
out << " access=\"" << accessControlToString(function->access) << "\"";
|
||||
if (function->isInlineKeyword())
|
||||
out << " isInlineKeyword=\"true\"";
|
||||
outs += " isInlineKeyword=\"true\"";
|
||||
if (function->isStatic())
|
||||
out << " isStatic=\"true\"";
|
||||
outs += " isStatic=\"true\"";
|
||||
if (function->isAttributeNoreturn())
|
||||
out << " isAttributeNoreturn=\"true\"";
|
||||
if (const Function* overriddenFunction = function->getOverriddenFunction())
|
||||
out << " overriddenFunction=\"" << overriddenFunction << "\"";
|
||||
outs += " isAttributeNoreturn=\"true\"";
|
||||
if (const Function* overriddenFunction = function->getOverriddenFunction()) {
|
||||
outs += " overriddenFunction=\"";
|
||||
outs += ptr_to_string(overriddenFunction);
|
||||
outs += "\"";
|
||||
}
|
||||
if (function->argCount() == 0U)
|
||||
out << "/>" << std::endl;
|
||||
outs += "/>\n";
|
||||
else {
|
||||
out << ">" << std::endl;
|
||||
outs += ">\n";
|
||||
for (unsigned int argnr = 0; argnr < function->argCount(); ++argnr) {
|
||||
const Variable *arg = function->getArgumentVar(argnr);
|
||||
out << " <arg nr=\"" << argnr+1 << "\" variable=\"" << arg << "\"/>" << std::endl;
|
||||
outs += " <arg nr=\"";
|
||||
outs += std::to_string(argnr+1);
|
||||
outs += "\" variable=\"";
|
||||
outs += ptr_to_string(arg);
|
||||
outs += "\"/>\n";
|
||||
variables.insert(arg);
|
||||
}
|
||||
out << " </function>" << std::endl;
|
||||
outs += " </function>\n";
|
||||
}
|
||||
}
|
||||
out << " </functionList>" << std::endl;
|
||||
outs += " </functionList>\n";
|
||||
}
|
||||
if (!scope->varlist.empty()) {
|
||||
out << " <varlist>" << std::endl;
|
||||
for (std::list<Variable>::const_iterator var = scope->varlist.cbegin(); var != scope->varlist.cend(); ++var)
|
||||
out << " <var id=\"" << &*var << "\"/>" << std::endl;
|
||||
out << " </varlist>" << std::endl;
|
||||
outs += " <varlist>\n";
|
||||
for (std::list<Variable>::const_iterator var = scope->varlist.cbegin(); var != scope->varlist.cend(); ++var) {
|
||||
outs += " <var id=\"";
|
||||
outs += ptr_to_string(&*var);
|
||||
outs += "\"/>\n";
|
||||
}
|
||||
outs += " </varlist>\n";
|
||||
}
|
||||
out << " </scope>" << std::endl;
|
||||
outs += " </scope>\n";
|
||||
}
|
||||
}
|
||||
out << " </scopes>" << std::endl;
|
||||
outs += " </scopes>\n";
|
||||
|
||||
if (!typeList.empty()) {
|
||||
out << " <types>\n";
|
||||
outs += " <types>\n";
|
||||
for (const Type& type:typeList) {
|
||||
out << " <type id=\"" << &type << "\" classScope=\"" << type.classScope << "\"";
|
||||
outs += " <type id=\"";
|
||||
outs += ptr_to_string(&type);
|
||||
outs += "\" classScope=\"";
|
||||
outs += ptr_to_string(type.classScope);
|
||||
outs += "\"";
|
||||
if (type.derivedFrom.empty()) {
|
||||
out << "/>\n";
|
||||
outs += "/>\n";
|
||||
continue;
|
||||
}
|
||||
out << ">\n";
|
||||
outs += ">\n";
|
||||
for (const Type::BaseInfo& baseInfo: type.derivedFrom) {
|
||||
out << " <derivedFrom"
|
||||
<< " access=\"" << accessControlToString(baseInfo.access) << "\""
|
||||
<< " type=\"" << baseInfo.type << "\""
|
||||
<< " isVirtual=\"" << (baseInfo.isVirtual ? "true" : "false") << "\""
|
||||
<< " nameTok=\"" << baseInfo.nameTok << "\""
|
||||
<< "/>\n";
|
||||
outs += " <derivedFrom";
|
||||
outs += " access=\"";
|
||||
outs += accessControlToString(baseInfo.access);
|
||||
outs += "\"";
|
||||
outs += " type=\"";
|
||||
outs += ptr_to_string(baseInfo.type);
|
||||
outs += "\"";
|
||||
outs += " isVirtual=\"";
|
||||
outs += bool_to_string(baseInfo.isVirtual);
|
||||
outs += "\"";
|
||||
outs += " nameTok=\"";
|
||||
outs += ptr_to_string(baseInfo.nameTok);
|
||||
outs += "\"";
|
||||
outs += "/>\n";
|
||||
}
|
||||
out << " </type>\n";
|
||||
outs += " </type>\n";
|
||||
}
|
||||
out << " </types>\n";
|
||||
outs += " </types>\n";
|
||||
}
|
||||
|
||||
// Variables..
|
||||
for (const Variable *var : mVariableList)
|
||||
variables.insert(var);
|
||||
out << " <variables>" << std::endl;
|
||||
outs += " <variables>\n";
|
||||
for (const Variable *var : variables) {
|
||||
if (!var)
|
||||
continue;
|
||||
out << " <var id=\"" << var << '\"';
|
||||
out << " nameToken=\"" << var->nameToken() << '\"';
|
||||
out << " typeStartToken=\"" << var->typeStartToken() << '\"';
|
||||
out << " typeEndToken=\"" << var->typeEndToken() << '\"';
|
||||
out << " access=\"" << accessControlToString(var->mAccess) << '\"';
|
||||
out << " scope=\"" << var->scope() << '\"';
|
||||
if (var->valueType())
|
||||
out << " constness=\"" << var->valueType()->constness << '\"';
|
||||
out << " isArray=\"" << var->isArray() << '\"';
|
||||
out << " isClass=\"" << var->isClass() << '\"';
|
||||
out << " isConst=\"" << var->isConst() << '\"';
|
||||
out << " isExtern=\"" << var->isExtern() << '\"';
|
||||
out << " isPointer=\"" << var->isPointer() << '\"';
|
||||
out << " isReference=\"" << var->isReference() << '\"';
|
||||
out << " isStatic=\"" << var->isStatic() << '\"';
|
||||
out << " isVolatile=\"" << var->isVolatile() << '\"';
|
||||
out << "/>" << std::endl;
|
||||
outs += " <var id=\"";
|
||||
outs += ptr_to_string(var);
|
||||
outs += '\"';
|
||||
outs += " nameToken=\"";
|
||||
outs += ptr_to_string(var->nameToken());
|
||||
outs += '\"';
|
||||
outs += " typeStartToken=\"";
|
||||
outs += ptr_to_string(var->typeStartToken());
|
||||
outs += '\"';
|
||||
outs += " typeEndToken=\"";
|
||||
outs += ptr_to_string(var->typeEndToken());
|
||||
outs += '\"';
|
||||
outs += " access=\"";
|
||||
outs += accessControlToString(var->mAccess);
|
||||
outs += '\"';
|
||||
outs += " scope=\"";
|
||||
outs += ptr_to_string(var->scope());
|
||||
outs += '\"';
|
||||
if (var->valueType()) {
|
||||
outs += " constness=\"";
|
||||
outs += std::to_string(var->valueType()->constness);
|
||||
outs += '\"';
|
||||
}
|
||||
outs += " isArray=\"";
|
||||
outs += bool_to_string(var->isArray());
|
||||
outs += '\"';
|
||||
outs += " isClass=\"";
|
||||
outs += bool_to_string(var->isClass());
|
||||
outs += '\"';
|
||||
outs += " isConst=\"";
|
||||
outs += bool_to_string(var->isConst());
|
||||
outs += '\"';
|
||||
outs += " isExtern=\"";
|
||||
outs += bool_to_string(var->isExtern());
|
||||
outs += '\"';
|
||||
outs += " isPointer=\"";
|
||||
outs += bool_to_string(var->isPointer());
|
||||
outs += '\"';
|
||||
outs += " isReference=\"";
|
||||
outs += bool_to_string(var->isReference());
|
||||
outs += '\"';
|
||||
outs += " isStatic=\"";
|
||||
outs += bool_to_string(var->isStatic());
|
||||
outs += '\"';
|
||||
outs += " isVolatile=\"";
|
||||
outs += bool_to_string(var->isVolatile());
|
||||
outs += '\"';
|
||||
outs += "/>\n";
|
||||
}
|
||||
out << " </variables>" << std::endl;
|
||||
out << std::resetiosflags(std::ios::boolalpha);
|
||||
outs += " </variables>\n";
|
||||
|
||||
out << outs;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------
|
||||
|
@ -7443,64 +7553,67 @@ bool ValueType::fromLibraryType(const std::string &typestr, const Settings &sett
|
|||
|
||||
std::string ValueType::dump() const
|
||||
{
|
||||
std::ostringstream ret;
|
||||
std::string ret;
|
||||
switch (type) {
|
||||
case UNKNOWN_TYPE:
|
||||
return "";
|
||||
case NONSTD:
|
||||
ret << "valueType-type=\"nonstd\"";
|
||||
ret += "valueType-type=\"nonstd\"";
|
||||
break;
|
||||
case POD:
|
||||
ret << "valueType-type=\"pod\"";
|
||||
ret += "valueType-type=\"pod\"";
|
||||
break;
|
||||
case RECORD:
|
||||
ret << "valueType-type=\"record\"";
|
||||
ret += "valueType-type=\"record\"";
|
||||
break;
|
||||
case SMART_POINTER:
|
||||
ret << "valueType-type=\"smart-pointer\"";
|
||||
ret += "valueType-type=\"smart-pointer\"";
|
||||
break;
|
||||
case CONTAINER:
|
||||
ret << "valueType-type=\"container\"";
|
||||
ret << " valueType-containerId=\"" << container << "\"";
|
||||
case CONTAINER: {
|
||||
ret += "valueType-type=\"container\"";
|
||||
ret += " valueType-containerId=\"";
|
||||
ret += ptr_to_string(container);
|
||||
ret += "\"";
|
||||
break;
|
||||
}
|
||||
case ITERATOR:
|
||||
ret << "valueType-type=\"iterator\"";
|
||||
ret += "valueType-type=\"iterator\"";
|
||||
break;
|
||||
case VOID:
|
||||
ret << "valueType-type=\"void\"";
|
||||
ret += "valueType-type=\"void\"";
|
||||
break;
|
||||
case BOOL:
|
||||
ret << "valueType-type=\"bool\"";
|
||||
ret += "valueType-type=\"bool\"";
|
||||
break;
|
||||
case CHAR:
|
||||
ret << "valueType-type=\"char\"";
|
||||
ret += "valueType-type=\"char\"";
|
||||
break;
|
||||
case SHORT:
|
||||
ret << "valueType-type=\"short\"";
|
||||
ret += "valueType-type=\"short\"";
|
||||
break;
|
||||
case WCHAR_T:
|
||||
ret << "valueType-type=\"wchar_t\"";
|
||||
ret += "valueType-type=\"wchar_t\"";
|
||||
break;
|
||||
case INT:
|
||||
ret << "valueType-type=\"int\"";
|
||||
ret += "valueType-type=\"int\"";
|
||||
break;
|
||||
case LONG:
|
||||
ret << "valueType-type=\"long\"";
|
||||
ret += "valueType-type=\"long\"";
|
||||
break;
|
||||
case LONGLONG:
|
||||
ret << "valueType-type=\"long long\"";
|
||||
ret += "valueType-type=\"long long\"";
|
||||
break;
|
||||
case UNKNOWN_INT:
|
||||
ret << "valueType-type=\"unknown int\"";
|
||||
ret += "valueType-type=\"unknown int\"";
|
||||
break;
|
||||
case FLOAT:
|
||||
ret << "valueType-type=\"float\"";
|
||||
ret += "valueType-type=\"float\"";
|
||||
break;
|
||||
case DOUBLE:
|
||||
ret << "valueType-type=\"double\"";
|
||||
ret += "valueType-type=\"double\"";
|
||||
break;
|
||||
case LONGDOUBLE:
|
||||
ret << "valueType-type=\"long double\"";
|
||||
ret += "valueType-type=\"long double\"";
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -7508,36 +7621,51 @@ std::string ValueType::dump() const
|
|||
case Sign::UNKNOWN_SIGN:
|
||||
break;
|
||||
case Sign::SIGNED:
|
||||
ret << " valueType-sign=\"signed\"";
|
||||
ret += " valueType-sign=\"signed\"";
|
||||
break;
|
||||
case Sign::UNSIGNED:
|
||||
ret << " valueType-sign=\"unsigned\"";
|
||||
ret += " valueType-sign=\"unsigned\"";
|
||||
break;
|
||||
}
|
||||
|
||||
if (bits > 0)
|
||||
ret << " valueType-bits=\"" << bits << '\"';
|
||||
if (bits > 0) {
|
||||
ret += " valueType-bits=\"";
|
||||
ret += std::to_string(bits);
|
||||
ret += '\"';
|
||||
}
|
||||
|
||||
if (pointer > 0)
|
||||
ret << " valueType-pointer=\"" << pointer << '\"';
|
||||
if (pointer > 0) {
|
||||
ret += " valueType-pointer=\"";
|
||||
ret += std::to_string(pointer);
|
||||
ret += '\"';
|
||||
}
|
||||
|
||||
if (constness > 0)
|
||||
ret << " valueType-constness=\"" << constness << '\"';
|
||||
if (constness > 0) {
|
||||
ret += " valueType-constness=\"";
|
||||
ret += std::to_string(constness);
|
||||
ret += '\"';
|
||||
}
|
||||
|
||||
if (reference == Reference::None)
|
||||
ret << " valueType-reference=\"None\"";
|
||||
ret += " valueType-reference=\"None\"";
|
||||
else if (reference == Reference::LValue)
|
||||
ret << " valueType-reference=\"LValue\"";
|
||||
ret += " valueType-reference=\"LValue\"";
|
||||
else if (reference == Reference::RValue)
|
||||
ret << " valueType-reference=\"RValue\"";
|
||||
ret += " valueType-reference=\"RValue\"";
|
||||
|
||||
if (typeScope)
|
||||
ret << " valueType-typeScope=\"" << typeScope << '\"';
|
||||
if (typeScope) {
|
||||
ret += " valueType-typeScope=\"";
|
||||
ret += ptr_to_string(typeScope);
|
||||
ret += '\"';
|
||||
}
|
||||
|
||||
if (!originalTypeName.empty())
|
||||
ret << " valueType-originalTypeName=\"" << ErrorLogger::toxml(originalTypeName) << '\"';
|
||||
if (!originalTypeName.empty()) {
|
||||
ret += " valueType-originalTypeName=\"";
|
||||
ret += ErrorLogger::toxml(originalTypeName);
|
||||
ret += '\"';
|
||||
}
|
||||
|
||||
return ret.str();
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool ValueType::isConst(nonneg int indirect) const
|
||||
|
|
140
lib/token.cpp
140
lib/token.cpp
|
@ -1695,119 +1695,171 @@ std::string Token::astStringZ3() const
|
|||
|
||||
void Token::printValueFlow(bool xml, std::ostream &out) const
|
||||
{
|
||||
std::string outs;
|
||||
|
||||
int line = 0;
|
||||
if (xml)
|
||||
out << " <valueflow>" << std::endl;
|
||||
outs += " <valueflow>\n";
|
||||
else
|
||||
out << "\n\n##Value flow" << std::endl;
|
||||
outs += "\n\n##Value flow\n";
|
||||
for (const Token *tok = this; tok; tok = tok->next()) {
|
||||
const auto* const values = tok->mImpl->mValues;
|
||||
if (!values)
|
||||
continue;
|
||||
if (values->empty()) // Values might be removed by removeContradictions
|
||||
continue;
|
||||
if (xml)
|
||||
out << " <values id=\"" << values << "\">" << std::endl;
|
||||
else if (line != tok->linenr())
|
||||
out << "Line " << tok->linenr() << std::endl;
|
||||
if (xml) {
|
||||
outs += " <values id=\"";
|
||||
outs += ptr_to_string(values);
|
||||
outs += "\">";
|
||||
outs += '\n';
|
||||
}
|
||||
else if (line != tok->linenr()) {
|
||||
outs += "Line ";
|
||||
outs += std::to_string(tok->linenr());
|
||||
outs += '\n';
|
||||
}
|
||||
line = tok->linenr();
|
||||
if (!xml) {
|
||||
ValueFlow::Value::ValueKind valueKind = values->front().valueKind;
|
||||
const bool same = std::all_of(values->begin(), values->end(), [&](const ValueFlow::Value& value) {
|
||||
return value.valueKind == valueKind;
|
||||
});
|
||||
out << " " << tok->str() << " ";
|
||||
outs += " ";
|
||||
outs += tok->str();
|
||||
outs += " ";
|
||||
if (same) {
|
||||
switch (valueKind) {
|
||||
case ValueFlow::Value::ValueKind::Impossible:
|
||||
case ValueFlow::Value::ValueKind::Known:
|
||||
out << "always ";
|
||||
outs += "always ";
|
||||
break;
|
||||
case ValueFlow::Value::ValueKind::Inconclusive:
|
||||
out << "inconclusive ";
|
||||
outs += "inconclusive ";
|
||||
break;
|
||||
case ValueFlow::Value::ValueKind::Possible:
|
||||
out << "possible ";
|
||||
outs += "possible ";
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (values->size() > 1U)
|
||||
out << '{';
|
||||
outs += '{';
|
||||
}
|
||||
for (const ValueFlow::Value& value : *values) {
|
||||
if (xml) {
|
||||
out << " <value ";
|
||||
outs += " <value ";
|
||||
switch (value.valueType) {
|
||||
case ValueFlow::Value::ValueType::INT:
|
||||
if (tok->valueType() && tok->valueType()->sign == ValueType::UNSIGNED)
|
||||
out << "intvalue=\"" << (MathLib::biguint)value.intvalue << '\"';
|
||||
else
|
||||
out << "intvalue=\"" << value.intvalue << '\"';
|
||||
if (tok->valueType() && tok->valueType()->sign == ValueType::UNSIGNED) {
|
||||
outs += "intvalue=\"";
|
||||
outs += std::to_string(static_cast<MathLib::biguint>(value.intvalue));
|
||||
outs += '\"';
|
||||
}
|
||||
else {
|
||||
outs += "intvalue=\"";
|
||||
outs += std::to_string(value.intvalue);
|
||||
outs += '\"';
|
||||
}
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::TOK:
|
||||
out << "tokvalue=\"" << value.tokvalue << '\"';
|
||||
outs += "tokvalue=\"";
|
||||
outs += ptr_to_string(value.tokvalue);
|
||||
outs += '\"';
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::FLOAT:
|
||||
out << "floatvalue=\"" << value.floatValue << '\"';
|
||||
outs += "floatvalue=\"";
|
||||
outs += std::to_string(value.floatValue); // TODO: should this be MathLib::toString()?
|
||||
outs += '\"';
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::MOVED:
|
||||
out << "movedvalue=\"" << ValueFlow::Value::toString(value.moveKind) << '\"';
|
||||
outs += "movedvalue=\"";
|
||||
outs += ValueFlow::Value::toString(value.moveKind);
|
||||
outs += '\"';
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::UNINIT:
|
||||
out << "uninit=\"1\"";
|
||||
outs += "uninit=\"1\"";
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::BUFFER_SIZE:
|
||||
out << "buffer-size=\"" << value.intvalue << "\"";
|
||||
outs += "buffer-size=\"";
|
||||
outs += std::to_string(value.intvalue);
|
||||
outs += "\"";
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::CONTAINER_SIZE:
|
||||
out << "container-size=\"" << value.intvalue << '\"';
|
||||
outs += "container-size=\"";
|
||||
outs += std::to_string(value.intvalue);
|
||||
outs += '\"';
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::ITERATOR_START:
|
||||
out << "iterator-start=\"" << value.intvalue << '\"';
|
||||
outs += "iterator-start=\"";
|
||||
outs += std::to_string(value.intvalue);
|
||||
outs += '\"';
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::ITERATOR_END:
|
||||
out << "iterator-end=\"" << value.intvalue << '\"';
|
||||
outs += "iterator-end=\"";
|
||||
outs += std::to_string(value.intvalue);
|
||||
outs += '\"';
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::LIFETIME:
|
||||
out << "lifetime=\"" << value.tokvalue << '\"';
|
||||
out << " lifetime-scope=\"" << ValueFlow::Value::toString(value.lifetimeScope) << "\"";
|
||||
out << " lifetime-kind=\"" << ValueFlow::Value::toString(value.lifetimeKind) << "\"";
|
||||
outs += "lifetime=\"";
|
||||
outs += ptr_to_string(value.tokvalue);
|
||||
outs += '\"';
|
||||
outs += " lifetime-scope=\"";
|
||||
outs += ValueFlow::Value::toString(value.lifetimeScope);
|
||||
outs += "\"";
|
||||
outs += " lifetime-kind=\"";
|
||||
outs += ValueFlow::Value::toString(value.lifetimeKind);
|
||||
outs += "\"";
|
||||
break;
|
||||
case ValueFlow::Value::ValueType::SYMBOLIC:
|
||||
out << "symbolic=\"" << value.tokvalue << '\"';
|
||||
out << " symbolic-delta=\"" << value.intvalue << '\"';
|
||||
outs += "symbolic=\"";
|
||||
outs += ptr_to_string(value.tokvalue);
|
||||
outs += '\"';
|
||||
outs += " symbolic-delta=\"";
|
||||
outs += std::to_string(value.intvalue);
|
||||
outs += '\"';
|
||||
break;
|
||||
}
|
||||
out << " bound=\"" << ValueFlow::Value::toString(value.bound) << "\"";
|
||||
if (value.condition)
|
||||
out << " condition-line=\"" << value.condition->linenr() << '\"';
|
||||
outs += " bound=\"";
|
||||
outs += ValueFlow::Value::toString(value.bound);
|
||||
outs += "\"";
|
||||
if (value.condition) {
|
||||
outs += " condition-line=\"";
|
||||
outs += std::to_string(value.condition->linenr());
|
||||
outs += '\"';
|
||||
}
|
||||
if (value.isKnown())
|
||||
out << " known=\"true\"";
|
||||
outs += " known=\"true\"";
|
||||
else if (value.isPossible())
|
||||
out << " possible=\"true\"";
|
||||
outs += " possible=\"true\"";
|
||||
else if (value.isImpossible())
|
||||
out << " impossible=\"true\"";
|
||||
outs += " impossible=\"true\"";
|
||||
else if (value.isInconclusive())
|
||||
out << " inconclusive=\"true\"";
|
||||
out << " path=\"" << value.path << "\"";
|
||||
out << "/>" << std::endl;
|
||||
outs += " inconclusive=\"true\"";
|
||||
|
||||
outs += " path=\"";
|
||||
outs += std::to_string(value.path);
|
||||
outs += "\"";
|
||||
|
||||
outs += "/>\n";
|
||||
}
|
||||
|
||||
else {
|
||||
if (&value != &values->front())
|
||||
out << ",";
|
||||
out << value.toString();
|
||||
outs += ",";
|
||||
outs += value.toString();
|
||||
}
|
||||
}
|
||||
if (xml)
|
||||
out << " </values>" << std::endl;
|
||||
outs += " </values>\n";
|
||||
else if (values->size() > 1U)
|
||||
out << '}' << std::endl;
|
||||
outs += "}\n";
|
||||
else
|
||||
out << std::endl;
|
||||
outs += '\n';
|
||||
}
|
||||
if (xml)
|
||||
out << " </valueflow>" << std::endl;
|
||||
outs += " </valueflow>\n";
|
||||
|
||||
out << outs;
|
||||
}
|
||||
|
||||
const ValueFlow::Value * Token::getValueLE(const MathLib::bigint val, const Settings *settings) const
|
||||
|
|
251
lib/tokenize.cpp
251
lib/tokenize.cpp
|
@ -4014,8 +4014,8 @@ void Tokenizer::simplifyTemplates()
|
|||
/** Class used in Tokenizer::setVarIdPass1 */
|
||||
class VariableMap {
|
||||
private:
|
||||
std::map<std::string, nonneg int> mVariableId;
|
||||
std::map<std::string, nonneg int> mVariableId_global;
|
||||
std::unordered_map<std::string, nonneg int> mVariableId;
|
||||
std::unordered_map<std::string, nonneg int> mVariableId_global;
|
||||
std::stack<std::vector<std::pair<std::string, nonneg int>>> mScopeInfo;
|
||||
mutable nonneg int mVarId{};
|
||||
public:
|
||||
|
@ -4027,7 +4027,7 @@ public:
|
|||
return mVariableId.find(varname) != mVariableId.end();
|
||||
}
|
||||
|
||||
const std::map<std::string, nonneg int>& map(bool global) const {
|
||||
const std::unordered_map<std::string, nonneg int>& map(bool global) const {
|
||||
return global ? mVariableId_global : mVariableId;
|
||||
}
|
||||
nonneg int getVarId() const {
|
||||
|
@ -4067,7 +4067,7 @@ void VariableMap::addVariable(const std::string& varname, bool globalNamespace)
|
|||
mVariableId_global[varname] = mVariableId[varname];
|
||||
return;
|
||||
}
|
||||
std::map<std::string, nonneg int>::iterator it = mVariableId.find(varname);
|
||||
std::unordered_map<std::string, nonneg int>::iterator it = mVariableId.find(varname);
|
||||
if (it == mVariableId.end()) {
|
||||
mScopeInfo.top().emplace_back(varname, 0);
|
||||
mVariableId[varname] = ++mVarId;
|
||||
|
@ -4330,7 +4330,7 @@ void Tokenizer::setVarIdClassDeclaration(Token* const startToken,
|
|||
--indentlevel;
|
||||
inEnum = false;
|
||||
} else if (initList && indentlevel == 0 && Token::Match(tok->previous(), "[,:] %name% [({]")) {
|
||||
const std::map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
|
||||
const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
|
||||
if (it != variableMap.map(false).end()) {
|
||||
tok->varId(it->second);
|
||||
}
|
||||
|
@ -4348,7 +4348,7 @@ void Tokenizer::setVarIdClassDeclaration(Token* const startToken,
|
|||
}
|
||||
|
||||
if (!inEnum) {
|
||||
const std::map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
|
||||
const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
|
||||
if (it != variableMap.map(false).end()) {
|
||||
tok->varId(it->second);
|
||||
setVarIdStructMembers(&tok, structMembers, variableMap.getVarId());
|
||||
|
@ -4692,7 +4692,7 @@ void Tokenizer::setVarIdPass1()
|
|||
while (tok != end) {
|
||||
if (tok->isName() && !(Token::simpleMatch(tok->next(), "<") &&
|
||||
Token::Match(tok->tokAt(-1), ":: %name%"))) {
|
||||
const std::map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
|
||||
const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
|
||||
if (it != variableMap.map(false).end())
|
||||
tok->varId(it->second);
|
||||
}
|
||||
|
@ -4757,7 +4757,7 @@ void Tokenizer::setVarIdPass1()
|
|||
|
||||
if ((!scopeStack.top().isEnum || !(Token::Match(tok->previous(), "{|,") && Token::Match(tok->next(), ",|=|}"))) &&
|
||||
!Token::simpleMatch(tok->next(), ": ;")) {
|
||||
const std::map<std::string, nonneg int>::const_iterator it = variableMap.map(globalNamespace).find(tok->str());
|
||||
const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(globalNamespace).find(tok->str());
|
||||
if (it != variableMap.map(globalNamespace).end()) {
|
||||
tok->varId(it->second);
|
||||
setVarIdStructMembers(&tok, structMembers, variableMap.getVarId());
|
||||
|
@ -5797,134 +5797,223 @@ void Tokenizer::dump(std::ostream &out) const
|
|||
// The idea is not that this will be readable for humans. It's a
|
||||
// data dump that 3rd party tools could load and get useful info from.
|
||||
|
||||
std::string outs;
|
||||
|
||||
std::set<const Library::Container*> containers;
|
||||
|
||||
// tokens..
|
||||
out << " <tokenlist>" << std::endl;
|
||||
outs += " <tokenlist>";
|
||||
outs += '\n';
|
||||
for (const Token *tok = list.front(); tok; tok = tok->next()) {
|
||||
out << " <token id=\"" << tok << "\" file=\"" << ErrorLogger::toxml(list.file(tok)) << "\" linenr=\"" << tok->linenr() << "\" column=\"" << tok->column() << "\"";
|
||||
out << " str=\"" << ErrorLogger::toxml(tok->str()) << '\"';
|
||||
out << " scope=\"" << tok->scope() << '\"';
|
||||
outs += " <token id=\"";
|
||||
outs += ptr_to_string(tok);
|
||||
outs += "\" file=\"";
|
||||
outs += ErrorLogger::toxml(list.file(tok));
|
||||
outs += "\" linenr=\"";
|
||||
outs += std::to_string(tok->linenr());
|
||||
outs += "\" column=\"";
|
||||
outs += std::to_string(tok->column());
|
||||
outs += "\"";
|
||||
|
||||
outs += " str=\"";
|
||||
outs += ErrorLogger::toxml(tok->str());
|
||||
outs += '\"';
|
||||
|
||||
outs += " scope=\"";
|
||||
outs += ptr_to_string(tok->scope());
|
||||
outs += '\"';
|
||||
if (tok->isName()) {
|
||||
out << " type=\"name\"";
|
||||
outs += " type=\"name\"";
|
||||
if (tok->isUnsigned())
|
||||
out << " isUnsigned=\"true\"";
|
||||
outs += " isUnsigned=\"true\"";
|
||||
else if (tok->isSigned())
|
||||
out << " isSigned=\"true\"";
|
||||
outs += " isSigned=\"true\"";
|
||||
} else if (tok->isNumber()) {
|
||||
out << " type=\"number\"";
|
||||
outs += " type=\"number\"";
|
||||
if (MathLib::isInt(tok->str()))
|
||||
out << " isInt=\"true\"";
|
||||
outs += " isInt=\"true\"";
|
||||
if (MathLib::isFloat(tok->str()))
|
||||
out << " isFloat=\"true\"";
|
||||
} else if (tok->tokType() == Token::eString)
|
||||
out << " type=\"string\" strlen=\"" << Token::getStrLength(tok) << '\"';
|
||||
outs += " isFloat=\"true\"";
|
||||
} else if (tok->tokType() == Token::eString) {
|
||||
outs += " type=\"string\" strlen=\"";
|
||||
outs += std::to_string(Token::getStrLength(tok));
|
||||
outs += '\"';
|
||||
}
|
||||
else if (tok->tokType() == Token::eChar)
|
||||
out << " type=\"char\"";
|
||||
outs += " type=\"char\"";
|
||||
else if (tok->isBoolean())
|
||||
out << " type=\"boolean\"";
|
||||
outs += " type=\"boolean\"";
|
||||
else if (tok->isOp()) {
|
||||
out << " type=\"op\"";
|
||||
outs += " type=\"op\"";
|
||||
if (tok->isArithmeticalOp())
|
||||
out << " isArithmeticalOp=\"true\"";
|
||||
outs += " isArithmeticalOp=\"true\"";
|
||||
else if (tok->isAssignmentOp())
|
||||
out << " isAssignmentOp=\"true\"";
|
||||
outs += " isAssignmentOp=\"true\"";
|
||||
else if (tok->isComparisonOp())
|
||||
out << " isComparisonOp=\"true\"";
|
||||
outs += " isComparisonOp=\"true\"";
|
||||
else if (tok->tokType() == Token::eLogicalOp)
|
||||
out << " isLogicalOp=\"true\"";
|
||||
outs += " isLogicalOp=\"true\"";
|
||||
}
|
||||
if (tok->isCast())
|
||||
out << " isCast=\"true\"";
|
||||
outs += " isCast=\"true\"";
|
||||
if (tok->isExternC())
|
||||
out << " externLang=\"C\"";
|
||||
outs += " externLang=\"C\"";
|
||||
if (tok->isExpandedMacro())
|
||||
out << " isExpandedMacro=\"true\"";
|
||||
outs += " isExpandedMacro=\"true\"";
|
||||
if (tok->isTemplateArg())
|
||||
out << " isTemplateArg=\"true\"";
|
||||
outs += " isTemplateArg=\"true\"";
|
||||
if (tok->isRemovedVoidParameter())
|
||||
out << " isRemovedVoidParameter=\"true\"";
|
||||
outs += " isRemovedVoidParameter=\"true\"";
|
||||
if (tok->isSplittedVarDeclComma())
|
||||
out << " isSplittedVarDeclComma=\"true\"";
|
||||
outs += " isSplittedVarDeclComma=\"true\"";
|
||||
if (tok->isSplittedVarDeclEq())
|
||||
out << " isSplittedVarDeclEq=\"true\"";
|
||||
outs += " isSplittedVarDeclEq=\"true\"";
|
||||
if (tok->isImplicitInt())
|
||||
out << " isImplicitInt=\"true\"";
|
||||
outs += " isImplicitInt=\"true\"";
|
||||
if (tok->isComplex())
|
||||
out << " isComplex=\"true\"";
|
||||
outs += " isComplex=\"true\"";
|
||||
if (tok->isRestrict())
|
||||
out << " isRestrict=\"true\"";
|
||||
outs += " isRestrict=\"true\"";
|
||||
if (tok->isAtomic())
|
||||
out << " isAtomic=\"true\"";
|
||||
outs += " isAtomic=\"true\"";
|
||||
if (tok->isAttributeExport())
|
||||
out << " isAttributeExport=\"true\"";
|
||||
if (tok->link())
|
||||
out << " link=\"" << tok->link() << '\"';
|
||||
if (tok->varId() > 0)
|
||||
out << " varId=\"" << tok->varId() << '\"';
|
||||
if (tok->exprId() > 0)
|
||||
out << " exprId=\"" << tok->exprId() << '\"';
|
||||
if (tok->variable())
|
||||
out << " variable=\"" << tok->variable() << '\"';
|
||||
if (tok->function())
|
||||
out << " function=\"" << tok->function() << '\"';
|
||||
if (!tok->values().empty())
|
||||
out << " values=\"" << &tok->values() << '\"';
|
||||
if (tok->type())
|
||||
out << " type-scope=\"" << tok->type()->classScope << '\"';
|
||||
if (tok->astParent())
|
||||
out << " astParent=\"" << tok->astParent() << '\"';
|
||||
if (tok->astOperand1())
|
||||
out << " astOperand1=\"" << tok->astOperand1() << '\"';
|
||||
if (tok->astOperand2())
|
||||
out << " astOperand2=\"" << tok->astOperand2() << '\"';
|
||||
if (!tok->originalName().empty())
|
||||
out << " originalName=\"" << tok->originalName() << '\"';
|
||||
outs += " isAttributeExport=\"true\"";
|
||||
if (tok->link()) {
|
||||
outs += " link=\"";
|
||||
outs += ptr_to_string(tok->link());
|
||||
outs += '\"';
|
||||
}
|
||||
if (tok->varId() > 0) {
|
||||
outs += " varId=\"";
|
||||
outs += std::to_string(tok->varId());
|
||||
outs += '\"';
|
||||
}
|
||||
if (tok->exprId() > 0) {
|
||||
outs += " exprId=\"";
|
||||
outs += std::to_string(tok->exprId());
|
||||
outs += '\"';
|
||||
}
|
||||
if (tok->variable()) {
|
||||
outs += " variable=\"";
|
||||
outs += ptr_to_string(tok->variable());
|
||||
outs += '\"';
|
||||
}
|
||||
if (tok->function()) {
|
||||
outs += " function=\"";
|
||||
outs += ptr_to_string(tok->function());
|
||||
outs += '\"';
|
||||
}
|
||||
if (!tok->values().empty()) {
|
||||
outs += " values=\"";
|
||||
outs += ptr_to_string(&tok->values());
|
||||
outs += '\"';
|
||||
}
|
||||
if (tok->type()) {
|
||||
outs += " type-scope=\"";
|
||||
outs += ptr_to_string(tok->type()->classScope);
|
||||
outs += '\"';
|
||||
}
|
||||
if (tok->astParent()) {
|
||||
outs += " astParent=\"";
|
||||
outs += ptr_to_string(tok->astParent());
|
||||
outs += '\"';
|
||||
}
|
||||
if (tok->astOperand1()) {
|
||||
outs += " astOperand1=\"";
|
||||
outs += ptr_to_string(tok->astOperand1());
|
||||
outs += '\"';
|
||||
}
|
||||
if (tok->astOperand2()) {
|
||||
outs += " astOperand2=\"";
|
||||
outs += ptr_to_string(tok->astOperand2());
|
||||
outs += '\"';
|
||||
}
|
||||
if (!tok->originalName().empty()) {
|
||||
outs += " originalName=\"";
|
||||
outs += tok->originalName();
|
||||
outs += '\"';
|
||||
}
|
||||
if (tok->valueType()) {
|
||||
const std::string vt = tok->valueType()->dump();
|
||||
if (!vt.empty())
|
||||
out << ' ' << vt;
|
||||
if (!vt.empty()) {
|
||||
outs += ' ';
|
||||
outs += vt;
|
||||
}
|
||||
containers.insert(tok->valueType()->container);
|
||||
}
|
||||
if (!tok->varId() && tok->scope()->isExecutable() && Token::Match(tok, "%name% (")) {
|
||||
if (mSettings->library.isnoreturn(tok))
|
||||
out << " noreturn=\"true\"";
|
||||
outs += " noreturn=\"true\"";
|
||||
}
|
||||
|
||||
out << "/>" << std::endl;
|
||||
outs += "/>";
|
||||
outs += '\n';
|
||||
}
|
||||
out << " </tokenlist>" << std::endl;
|
||||
outs += " </tokenlist>";
|
||||
outs += '\n';
|
||||
|
||||
out << outs;
|
||||
outs.clear();
|
||||
|
||||
mSymbolDatabase->printXml(out);
|
||||
|
||||
containers.erase(nullptr);
|
||||
if (!containers.empty()) {
|
||||
out << " <containers>\n";
|
||||
outs += " <containers>";
|
||||
outs += '\n';
|
||||
for (const Library::Container* c: containers) {
|
||||
out << " <container id=\"" << c << "\" array-like-index-op=\""
|
||||
<< (c->arrayLike_indexOp ? "true" : "false") << "\" "
|
||||
<< "std-string-like=\"" << (c->stdStringLike ? "true" : "false") << "\"/>\n";
|
||||
outs += " <container id=\"";
|
||||
outs += ptr_to_string(c);
|
||||
outs += "\" array-like-index-op=\"";
|
||||
outs += (c->arrayLike_indexOp ? "true" : "false");
|
||||
outs += "\" ";
|
||||
outs += "std-string-like=\"";
|
||||
outs +=(c->stdStringLike ? "true" : "false");
|
||||
outs += "\"/>";
|
||||
outs += '\n';
|
||||
}
|
||||
out << " </containers>\n";
|
||||
outs += " </containers>";
|
||||
outs += '\n';
|
||||
}
|
||||
|
||||
if (list.front())
|
||||
list.front()->printValueFlow(true, out);
|
||||
|
||||
if (!mTypedefInfo.empty()) {
|
||||
out << " <typedef-info>" << std::endl;
|
||||
outs += " <typedef-info>";
|
||||
outs += '\n';
|
||||
for (const TypedefInfo &typedefInfo: mTypedefInfo) {
|
||||
out << " <info"
|
||||
<< " name=\"" << typedefInfo.name << "\""
|
||||
<< " file=\"" << ErrorLogger::toxml(typedefInfo.filename) << "\""
|
||||
<< " line=\"" << typedefInfo.lineNumber << "\""
|
||||
<< " column=\"" << typedefInfo.column << "\""
|
||||
<< " used=\"" << (typedefInfo.used?1:0) << "\""
|
||||
<< "/>" << std::endl;
|
||||
outs += " <info";
|
||||
|
||||
outs += " name=\"";
|
||||
outs += typedefInfo.name;
|
||||
outs += "\"";
|
||||
|
||||
outs += " file=\"";
|
||||
outs += ErrorLogger::toxml(typedefInfo.filename);
|
||||
outs += "\"";
|
||||
|
||||
outs += " line=\"";
|
||||
outs += std::to_string(typedefInfo.lineNumber);
|
||||
outs += "\"";
|
||||
|
||||
outs += " column=\"";
|
||||
outs += std::to_string(typedefInfo.column);
|
||||
outs += "\"";
|
||||
|
||||
outs += " used=\"";
|
||||
outs += std::to_string(typedefInfo.used?1:0);
|
||||
outs += "\"";
|
||||
|
||||
outs += "/>";
|
||||
outs += '\n';
|
||||
}
|
||||
out << " </typedef-info>" << std::endl;
|
||||
outs += " </typedef-info>";
|
||||
outs += '\n';
|
||||
}
|
||||
out << mTemplateSimplifier->dump();
|
||||
outs += mTemplateSimplifier->dump();
|
||||
|
||||
out << outs;
|
||||
}
|
||||
|
||||
void Tokenizer::simplifyHeadersAndUnusedTemplates()
|
||||
|
|
73
lib/utils.h
73
lib/utils.h
|
@ -26,6 +26,7 @@
|
|||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <initializer_list>
|
||||
#include <limits>
|
||||
#include <stdexcept>
|
||||
|
@ -269,4 +270,76 @@ std::size_t getArrayLength(const T (& /*unused*/)[size])
|
|||
return size;
|
||||
}
|
||||
|
||||
/** this is meant as a replacement for when we cannot print a pointer via the stream insertion operator (operator<<) for performance reasons */
|
||||
// TODO: should give portable value / only used by Tokenizer::dump() and underlying functions - something deterministic would also help with comparing the output
|
||||
static inline std::string ptr_to_string(const void* p)
|
||||
{
|
||||
#if (defined(__APPLE__) && defined(__MACH__))
|
||||
if (p == nullptr)
|
||||
return "0x0";
|
||||
#elif !defined(_WIN32) || defined(__MINGW32__)
|
||||
if (p == nullptr)
|
||||
return "0";
|
||||
#endif
|
||||
|
||||
static constexpr int ptr_size = sizeof(void*);
|
||||
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
// two characters of each byte / contains terminating \0
|
||||
static constexpr int buf_size = (ptr_size * 2) + 1;
|
||||
#else
|
||||
// two characters of each byte / contains 0x prefix and contains terminating \0
|
||||
static constexpr int buf_size = (ptr_size * 2) + 2 + 1;
|
||||
#endif
|
||||
char buf[buf_size];
|
||||
|
||||
// needs to be signed so we don't underflow in padding loop
|
||||
int idx = sizeof(buf) - 1;
|
||||
buf[idx--] = '\0'; // terminate string
|
||||
|
||||
uintptr_t l = reinterpret_cast<uintptr_t>(p);
|
||||
while (l != 0)
|
||||
{
|
||||
char c;
|
||||
const uintptr_t temp = l % 16; // get the remainder
|
||||
if (temp < 10) {
|
||||
// 0-9
|
||||
c = '0' + temp;
|
||||
}
|
||||
else {
|
||||
#if !defined(_WIN32) || defined(__MINGW32__)
|
||||
// a-f
|
||||
c = 'a' + (temp - 10);
|
||||
#else
|
||||
// A-F
|
||||
c = 'A' + (temp - 10);
|
||||
#endif
|
||||
}
|
||||
buf[idx--] = c; // store in reverse order
|
||||
l = l / 16;
|
||||
}
|
||||
|
||||
#if defined(_WIN32) && !defined(__MINGW32__)
|
||||
// pad address with 0
|
||||
while (idx >= 0) {
|
||||
buf[idx--] = '0';
|
||||
}
|
||||
|
||||
// 000000F0A61FF122 or 0230FB33
|
||||
return buf;
|
||||
#else
|
||||
// add 0x prefix
|
||||
buf[idx--] = 'x';
|
||||
buf[idx--] = '0';
|
||||
|
||||
// 0x7ffc5aa334d8
|
||||
return &buf[idx+1];
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline std::string bool_to_string(bool b)
|
||||
{
|
||||
return b ? "true" : "false";
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
|
@ -36,6 +38,7 @@ private:
|
|||
TEST_CASE(isStringLiteral);
|
||||
TEST_CASE(isCharLiteral);
|
||||
TEST_CASE(strToInt);
|
||||
TEST_CASE(ptrToString);
|
||||
}
|
||||
|
||||
void isValidGlobPattern() const {
|
||||
|
@ -330,6 +333,58 @@ private:
|
|||
ASSERT_EQUALS("out of range (stoull)", err);
|
||||
}
|
||||
}
|
||||
|
||||
void ptrToString() const
|
||||
{
|
||||
struct Dummy {};
|
||||
// stack address
|
||||
{
|
||||
const Dummy d;
|
||||
const Dummy* const dp = &d;
|
||||
std::ostringstream oss;
|
||||
oss << dp;
|
||||
ASSERT_EQUALS(oss.str(), ptr_to_string(dp));
|
||||
}
|
||||
// highest address
|
||||
{
|
||||
// NOLINTNEXTLINE(performance-no-int-to-ptr)
|
||||
const void* const p = reinterpret_cast<void*>(std::numeric_limits<uintptr_t>::max());
|
||||
std::ostringstream oss;
|
||||
oss << p;
|
||||
ASSERT_EQUALS(oss.str(), ptr_to_string(p));
|
||||
}
|
||||
// same in-between address
|
||||
{
|
||||
const Dummy d;
|
||||
const Dummy* dp = &d;
|
||||
dp = dp - ((unsigned long long)dp / 2);
|
||||
std::ostringstream oss;
|
||||
oss << dp;
|
||||
ASSERT_EQUALS(oss.str(), ptr_to_string(dp));
|
||||
}
|
||||
// lowest address
|
||||
{
|
||||
// NOLINTNEXTLINE(performance-no-int-to-ptr)
|
||||
const void* const p = reinterpret_cast<void*>(std::numeric_limits<uintptr_t>::min() + 1);
|
||||
std::ostringstream oss;
|
||||
oss << p;
|
||||
ASSERT_EQUALS(oss.str(), ptr_to_string(p));
|
||||
}
|
||||
// heap address
|
||||
{
|
||||
const auto dp = std::unique_ptr<Dummy>(new Dummy);
|
||||
std::ostringstream oss;
|
||||
oss << dp.get();
|
||||
ASSERT_EQUALS(oss.str(), ptr_to_string(dp.get()));
|
||||
}
|
||||
// NULL pointer
|
||||
{
|
||||
const Dummy* const dp = nullptr;
|
||||
std::ostringstream oss;
|
||||
oss << dp;
|
||||
ASSERT_EQUALS(oss.str(), ptr_to_string(dp));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_TEST(TestUtils)
|
||||
|
|
Loading…
Reference in New Issue