217 lines
6.7 KiB
C++
217 lines
6.7 KiB
C++
/*
|
|
* Cppcheck - A tool for static C/C++ code analysis
|
|
* Copyright (C) 2007-2022 Cppcheck team.
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "vfvalue.h"
|
|
|
|
#include "errortypes.h"
|
|
#include "token.h"
|
|
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
namespace ValueFlow {
|
|
Value::Value(const Token *c, long long val, Bound b)
|
|
: valueType(ValueType::INT),
|
|
bound(b),
|
|
intvalue(val),
|
|
tokvalue(nullptr),
|
|
floatValue(0.0),
|
|
varvalue(val),
|
|
condition(c),
|
|
varId(0),
|
|
safe(false),
|
|
conditional(false),
|
|
macro(false),
|
|
defaultArg(false),
|
|
indirect(0),
|
|
moveKind(MoveKind::NonMovedVariable),
|
|
path(0),
|
|
wideintvalue(0),
|
|
subexpressions(),
|
|
capturetok(nullptr),
|
|
lifetimeKind(LifetimeKind::Object),
|
|
lifetimeScope(LifetimeScope::Local),
|
|
valueKind(ValueKind::Possible) {
|
|
errorPath.emplace_back(c, "Assuming that condition '" + c->expressionString() + "' is not redundant");
|
|
}
|
|
|
|
void Value::assumeCondition(const Token *tok) {
|
|
condition = tok;
|
|
errorPath.emplace_back(tok, "Assuming that condition '" + tok->expressionString() + "' is not redundant");
|
|
}
|
|
|
|
std::string Value::toString() const {
|
|
std::stringstream ss;
|
|
if (this->isImpossible())
|
|
ss << "!";
|
|
if (this->bound == Bound::Lower)
|
|
ss << ">=";
|
|
if (this->bound == Bound::Upper)
|
|
ss << "<=";
|
|
switch (this->valueType) {
|
|
case ValueType::INT:
|
|
ss << this->intvalue;
|
|
break;
|
|
case ValueType::TOK:
|
|
ss << this->tokvalue->str();
|
|
break;
|
|
case ValueType::FLOAT:
|
|
ss << this->floatValue;
|
|
break;
|
|
case ValueType::MOVED:
|
|
ss << toString(this->moveKind);
|
|
break;
|
|
case ValueType::UNINIT:
|
|
ss << "Uninit";
|
|
break;
|
|
case ValueType::BUFFER_SIZE:
|
|
case ValueType::CONTAINER_SIZE:
|
|
ss << "size=" << this->intvalue;
|
|
break;
|
|
case ValueType::ITERATOR_START:
|
|
ss << "start=" << this->intvalue;
|
|
break;
|
|
case ValueType::ITERATOR_END:
|
|
ss << "end=" << this->intvalue;
|
|
break;
|
|
case ValueType::LIFETIME:
|
|
ss << "lifetime[" << toString(this->lifetimeKind) << "]=("
|
|
<< this->tokvalue->expressionString() << ")";
|
|
break;
|
|
case ValueType::SYMBOLIC:
|
|
ss << "symbolic=(" << this->tokvalue->expressionString();
|
|
if (this->intvalue > 0)
|
|
ss << "+" << this->intvalue;
|
|
else if (this->intvalue < 0)
|
|
ss << "-" << -this->intvalue;
|
|
ss << ")";
|
|
break;
|
|
}
|
|
if (this->indirect > 0)
|
|
for (int i = 0; i < this->indirect; i++)
|
|
ss << "*";
|
|
if (this->path > 0)
|
|
ss << "@" << this->path;
|
|
return ss.str();
|
|
}
|
|
|
|
std::string Value::infoString() const {
|
|
switch (valueType) {
|
|
case ValueType::INT:
|
|
return MathLib::toString(intvalue);
|
|
case ValueType::TOK:
|
|
return tokvalue->str();
|
|
case ValueType::FLOAT:
|
|
return MathLib::toString(floatValue);
|
|
case ValueType::MOVED:
|
|
return "<Moved>";
|
|
case ValueType::UNINIT:
|
|
return "<Uninit>";
|
|
case ValueType::BUFFER_SIZE:
|
|
case ValueType::CONTAINER_SIZE:
|
|
return "size=" + MathLib::toString(intvalue);
|
|
case ValueType::ITERATOR_START:
|
|
return "start=" + MathLib::toString(intvalue);
|
|
case ValueType::ITERATOR_END:
|
|
return "end=" + MathLib::toString(intvalue);
|
|
case ValueType::LIFETIME:
|
|
return "lifetime=" + tokvalue->str();
|
|
case ValueType::SYMBOLIC:
|
|
std::string result = "symbolic=" + tokvalue->expressionString();
|
|
if (intvalue > 0)
|
|
result += "+" + MathLib::toString(intvalue);
|
|
else if (intvalue < 0)
|
|
result += "-" + MathLib::toString(-intvalue);
|
|
return result;
|
|
}
|
|
throw InternalError(nullptr, "Invalid ValueFlow Value type");
|
|
}
|
|
|
|
const char *Value::toString(MoveKind moveKind) {
|
|
switch (moveKind) {
|
|
case MoveKind::NonMovedVariable:
|
|
return "NonMovedVariable";
|
|
case MoveKind::MovedVariable:
|
|
return "MovedVariable";
|
|
case MoveKind::ForwardedVariable:
|
|
return "ForwardedVariable";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
const char *Value::toString(LifetimeKind lifetimeKind) {
|
|
switch (lifetimeKind) {
|
|
case LifetimeKind::Object:
|
|
return "Object";
|
|
case LifetimeKind::SubObject:
|
|
return "SubObject";
|
|
case LifetimeKind::Lambda:
|
|
return "Lambda";
|
|
case LifetimeKind::Iterator:
|
|
return "Iterator";
|
|
case LifetimeKind::Address:
|
|
return "Address";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
bool Value::sameToken(const Token *tok1, const Token *tok2) {
|
|
if (tok1 == tok2)
|
|
return true;
|
|
if (!tok1)
|
|
return false;
|
|
if (tok1->exprId() == 0 || tok2->exprId() == 0)
|
|
return false;
|
|
return tok1->exprId() == tok2->exprId();
|
|
}
|
|
|
|
const char *Value::toString(LifetimeScope lifetimeScope) {
|
|
switch (lifetimeScope) {
|
|
case LifetimeScope::Local:
|
|
return "Local";
|
|
case LifetimeScope::Argument:
|
|
return "Argument";
|
|
case LifetimeScope::SubFunction:
|
|
return "SubFunction";
|
|
case LifetimeScope::ThisPointer:
|
|
return "ThisPointer";
|
|
case LifetimeScope::ThisValue:
|
|
return "ThisValue";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
const char *Value::toString(Bound bound) {
|
|
switch (bound) {
|
|
case Bound::Point:
|
|
return "Point";
|
|
case Bound::Upper:
|
|
return "Upper";
|
|
case Bound::Lower:
|
|
return "Lower";
|
|
}
|
|
return "";
|
|
}
|
|
|
|
Value Value::unknown() {
|
|
Value v;
|
|
v.valueType = ValueType::UNINIT;
|
|
return v;
|
|
}
|
|
}
|