Skip to content

Commit

Permalink
make sure the language for a TokenList is always determined
Browse files Browse the repository at this point in the history
  • Loading branch information
firewave committed Jan 13, 2024
1 parent d015007 commit e1ec95b
Show file tree
Hide file tree
Showing 16 changed files with 117 additions and 56 deletions.
7 changes: 6 additions & 1 deletion lib/clangimport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,12 @@ namespace clangimport {
void dumpAst(int num = 0, int indent = 0) const;
void createTokens1(TokenList &tokenList) {
//dumpAst();
if (!tokenList.back())
if (!tokenList.back()) {
setLocations(tokenList, 0, 1, 1);
// FIXME: treat as C++ if no filename (i.e. no lang) is specified for now
if (tokenList.getSourceFilePath().empty())
tokenList.setLang(Standards::Language::CPP);
}
else
setLocations(tokenList, tokenList.back()->fileIndex(), tokenList.back()->linenr(), 1);
createTokens(tokenList);
Expand Down Expand Up @@ -626,6 +630,7 @@ void clangimport::AstNode::setValueType(Token *tok)
continue;

TokenList decl(nullptr);
decl.setLang(tok->isCpp() ? Standards::Language::CPP : Standards::Language::C);
addTypeTokens(decl, type, tok->scope());
if (!decl.front())
break;
Expand Down
7 changes: 5 additions & 2 deletions lib/cppcheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ static void createDumpFile(const Settings& settings,
case Standards::Language::CPP:
language = " language=\"cpp\"";
break;
case Standards::Language::None:
case Standards::Language::None: {
// TODO: error out on unknown language?
const Standards::Language lang = Path::identify(filename);
if (lang == Standards::Language::CPP)
Expand All @@ -203,6 +203,9 @@ static void createDumpFile(const Settings& settings,
language = " language=\"c\"";
break;
}
case Standards::Language::Markup:
break;
}

fdump << "<?xml version=\"1.0\"?>\n";
fdump << "<dumps" << language << ">\n";
Expand Down Expand Up @@ -797,7 +800,7 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
}
Tokenizer tokenizer2(mSettings, this);
std::istringstream istr2(code);
tokenizer2.list.createTokens(istr2);
tokenizer2.list.createTokens(istr2, Path::identify(*files.begin()));
executeRules("define", tokenizer2);
}
#endif
Expand Down
8 changes: 4 additions & 4 deletions lib/importproject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -560,11 +560,11 @@ namespace {
replaceAll(c, "$(Configuration)", p.configuration);
replaceAll(c, "$(Platform)", p.platformStr);

// TODO : Better evaluation
Settings s;
std::istringstream istr(c);
// TODO: evaluate without using the Tokenizer
const Settings s;
Tokenizer tokenizer(s);
tokenizer.tokenize(istr,"vcxproj");
std::istringstream istr(c);
tokenizer.tokenize(istr,"vcxproj.c");
for (const Token *tok = tokenizer.tokens(); tok; tok = tok->next()) {
if (tok->str() == "(" && tok->astOperand1() && tok->astOperand2()) {
if (tok->astOperand1()->expressionString() == "Configuration.Contains")
Expand Down
11 changes: 6 additions & 5 deletions lib/library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ static std::vector<std::string> getnames(const char *names)
return ret;
}

static void gettokenlistfromvalid(const std::string& valid, TokenList& tokenList)
static void gettokenlistfromvalid(const std::string& valid, bool cpp, TokenList& tokenList)
{
std::istringstream istr(valid + ',');
tokenList.createTokens(istr);
tokenList.createTokens(istr, cpp ? Standards::Language::CPP : Standards::Language::C);
for (Token *tok = tokenList.front(); tok; tok = tok->next()) {
if (Token::Match(tok,"- %num%")) {
tok->str("-" + tok->strAt(1));
Expand Down Expand Up @@ -920,7 +920,7 @@ bool Library::isIntArgValid(const Token *ftok, int argnr, const MathLib::bigint
if (ac->valid.find('.') != std::string::npos)
return isFloatArgValid(ftok, argnr, argvalue);
TokenList tokenList(nullptr);
gettokenlistfromvalid(ac->valid, tokenList);
gettokenlistfromvalid(ac->valid, ftok->isCpp(), tokenList);
for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
if (tok->isNumber() && argvalue == MathLib::toBigNumber(tok->str()))
return true;
Expand All @@ -940,7 +940,7 @@ bool Library::isFloatArgValid(const Token *ftok, int argnr, double argvalue) con
if (!ac || ac->valid.empty())
return true;
TokenList tokenList(nullptr);
gettokenlistfromvalid(ac->valid, tokenList);
gettokenlistfromvalid(ac->valid, ftok->isCpp(), tokenList);
for (const Token *tok = tokenList.front(); tok; tok = tok->next()) {
if (Token::Match(tok, "%num% : %num%") && argvalue >= MathLib::toDoubleNumber(tok->str()) && argvalue <= MathLib::toDoubleNumber(tok->strAt(2)))
return true;
Expand Down Expand Up @@ -1729,13 +1729,14 @@ bool Library::hasAnyTypeCheck(const std::string& typeName) const

std::shared_ptr<Token> createTokenFromExpression(const std::string& returnValue,
const Settings* settings,
bool cpp,
std::unordered_map<nonneg int, const Token*>* lookupVarId)
{
std::shared_ptr<TokenList> tokenList = std::make_shared<TokenList>(settings);
{
const std::string code = "return " + returnValue + ";";
std::istringstream istr(code);
if (!tokenList->createTokens(istr))
if (!tokenList->createTokens(istr, cpp ? Standards::Language::CPP : Standards::Language::C))
return nullptr;
}

Expand Down
1 change: 1 addition & 0 deletions lib/library.h
Original file line number Diff line number Diff line change
Expand Up @@ -603,6 +603,7 @@ CPPCHECKLIB const Library::Container * getLibraryContainer(const Token * tok);

std::shared_ptr<Token> createTokenFromExpression(const std::string& returnValue,
const Settings* settings,
bool cpp,
std::unordered_map<nonneg int, const Token*>* lookupVarId = nullptr);

/// @}
Expand Down
7 changes: 4 additions & 3 deletions lib/programmemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1595,7 +1595,7 @@ namespace {
arg_map[argn] = v;
argn++;
}
return evaluateLibraryFunction(arg_map, returnValue, settings);
return evaluateLibraryFunction(arg_map, returnValue, settings, ftok->isCpp());
}
}
}
Expand Down Expand Up @@ -1751,15 +1751,16 @@ std::vector<ValueFlow::Value> execute(const Scope* scope, ProgramMemory& pm, con

ValueFlow::Value evaluateLibraryFunction(const std::unordered_map<nonneg int, ValueFlow::Value>& args,
const std::string& returnValue,
const Settings* settings)
const Settings* settings,
bool cpp)
{
thread_local static std::unordered_map<std::string,
std::function<ValueFlow::Value(const std::unordered_map<nonneg int, ValueFlow::Value>& arg)>>
functions = {};
if (functions.count(returnValue) == 0) {

std::unordered_map<nonneg int, const Token*> lookupVarId;
std::shared_ptr<Token> expr = createTokenFromExpression(returnValue, settings, &lookupVarId);
std::shared_ptr<Token> expr = createTokenFromExpression(returnValue, settings, cpp, &lookupVarId);

functions[returnValue] =
[lookupVarId, expr, settings](const std::unordered_map<nonneg int, ValueFlow::Value>& xargs) {
Expand Down
3 changes: 2 additions & 1 deletion lib/programmemory.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,8 @@ ProgramMemory getProgramMemory(const Token* tok, const Token* expr, const ValueF

ValueFlow::Value evaluateLibraryFunction(const std::unordered_map<nonneg int, ValueFlow::Value>& args,
const std::string& returnValue,
const Settings* settings);
const Settings* settings,
bool cpp);

#endif

Expand Down
2 changes: 1 addition & 1 deletion lib/standards.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
* This struct contains all possible standards that cppcheck recognize.
*/
struct Standards {
enum Language { None, C, CPP };
enum Language { None, C, CPP, Markup };

/** C code standard */
enum cstd_t { C89, C99, C11, CLatest = C11 } c = CLatest;
Expand Down
4 changes: 2 additions & 2 deletions lib/symboldatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7479,7 +7479,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
ValueType valuetype;
TokenList tokenList(&mSettings);
std::istringstream istr(typestr+";");
tokenList.createTokens(istr);
tokenList.createTokens(istr, tok->isCpp() ? Standards::Language::CPP : Standards::Language::C);
tokenList.simplifyStdType();
if (parsedecl(tokenList.front(), &valuetype, mDefaultSignedness, mSettings, mIsCpp)) {
valuetype.originalTypeName = typestr;
Expand Down Expand Up @@ -7569,7 +7569,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
}
TokenList tokenList(&mSettings);
std::istringstream istr(typestr+";");
if (tokenList.createTokens(istr)) {
if (tokenList.createTokens(istr, tok->isCpp() ? Standards::Language::CPP : Standards::Language::C)) {
ValueType vt;
tokenList.simplifyPlatformTypes();
tokenList.simplifyStdType();
Expand Down
1 change: 1 addition & 0 deletions lib/token.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2741,5 +2741,6 @@ bool Token::isCpp() const
if (mTokensFrontBack && mTokensFrontBack->list) {
return mTokensFrontBack->list->isCPP();
}
assert(false);
return true; // assume C++ by default
}
2 changes: 1 addition & 1 deletion lib/token.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ class CPPCHECKLIB Token {
friend class TestToken;

private:
TokensFrontBack* mTokensFrontBack{};
TokensFrontBack* const mTokensFrontBack{};

public:
Token(const Token &) = delete;
Expand Down
51 changes: 49 additions & 2 deletions lib/tokenlist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "standards.h"
#include "token.h"

#include <cassert>
#include <cctype>
#include <exception>
#include <functional>
Expand Down Expand Up @@ -83,9 +84,14 @@ void TokenList::deallocateTokens()

void TokenList::determineCppC()
{
// only try to determine it if it wasn't enforced
// only try to determine if it wasn't enforced
if (mLang == Standards::Language::None) {
mLang = Path::identify(getSourceFilePath());
if (mSettings->library.markupFile(getSourceFilePath())) {
mLang = Standards::Language::Markup;
}
else {
mLang = Path::identify(getSourceFilePath());
}
}
}

Expand Down Expand Up @@ -317,8 +323,27 @@ void TokenList::insertTokens(Token *dest, const Token *src, nonneg int n)

bool TokenList::createTokens(std::istream &code, const std::string& file0)
{
assert(!file0.empty());

appendFileIfNew(file0);

return createTokensInternal(code, file0);
}

//---------------------------------------------------------------------------

bool TokenList::createTokens(std::istream &code, Standards::Language lang)
{
if (mLang == Standards::Language::None)
mLang = lang;

return createTokensInternal(code, "");
}

//---------------------------------------------------------------------------

bool TokenList::createTokensInternal(std::istream &code, const std::string& file0)
{
simplecpp::OutputList outputList;
simplecpp::TokenList tokens(code, mFiles, file0, &outputList);

Expand Down Expand Up @@ -2096,3 +2121,25 @@ bool TokenList::isKeyword(const std::string &str) const
static const auto& latest_c_keywords = Keywords::getAll(Standards::cstd_t::CLatest);
return latest_c_keywords.find(str) != latest_c_keywords.end();
}

bool TokenList::isC() const
{
assert(mLang != Standards::Language::None);

return mLang == Standards::Language::C;
}

bool TokenList::isCPP() const
{
assert(mLang != Standards::Language::None);

return mLang == Standards::Language::CPP;
}

void TokenList::setLang(Standards::Language lang)
{
assert(lang != Standards::Language::None);
assert(mLang == Standards::Language::None);

mLang = lang;
}
15 changes: 8 additions & 7 deletions lib/tokenlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,12 @@ class CPPCHECKLIB TokenList {
const std::string& getSourceFilePath() const;

/** Is the code C. Used for bailouts */
bool isC() const {
return mLang == Standards::Language::C;
}
bool isC() const;

/** Is the code CPP. Used for bailouts */
bool isCPP() const {
return mLang == Standards::Language::CPP;
}
bool isCPP() const;

void setLang(Standards::Language lang);

/**
* Delete all tokens in given token list
Expand Down Expand Up @@ -104,7 +102,8 @@ class CPPCHECKLIB TokenList {
* @param code input stream for code
* @param file0 source file name
*/
bool createTokens(std::istream &code, const std::string& file0 = emptyString);
bool createTokens(std::istream &code, const std::string& file0);
bool createTokens(std::istream &code, Standards::Language lang);

void createTokens(simplecpp::TokenList&& tokenList);

Expand Down Expand Up @@ -202,6 +201,8 @@ class CPPCHECKLIB TokenList {
private:
void determineCppC();

bool createTokensInternal(std::istream &code, const std::string& file0);

/** Token list */
TokensFrontBack mTokensFrontBack;

Expand Down
20 changes: 10 additions & 10 deletions lib/valueflow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3738,20 +3738,20 @@ static bool isNotEqual(std::pair<const Token*, const Token*> x, std::pair<const
start2 = skipCVRefs(start2, y.second);
return !(start1 == x.second && start2 == y.second);
}
static bool isNotEqual(std::pair<const Token*, const Token*> x, const std::string& y)
static bool isNotEqual(std::pair<const Token*, const Token*> x, const std::string& y, bool cpp)
{
TokenList tokenList(nullptr);
std::istringstream istr(y);
tokenList.createTokens(istr);
tokenList.createTokens(istr, cpp ? Standards::Language::CPP : Standards::Language::C);
return isNotEqual(x, std::make_pair(tokenList.front(), tokenList.back()));
}
static bool isNotEqual(std::pair<const Token*, const Token*> x, const ValueType* y)
static bool isNotEqual(std::pair<const Token*, const Token*> x, const ValueType* y, bool cpp)
{
if (y == nullptr)
return false;
if (y->originalTypeName.empty())
return false;
return isNotEqual(x, y->originalTypeName);
return isNotEqual(x, y->originalTypeName, cpp);
}

static bool isDifferentType(const Token* src, const Token* dst)
Expand All @@ -3766,9 +3766,9 @@ static bool isDifferentType(const Token* src, const Token* dst)
std::pair<const Token*, const Token*> parentdecl = Token::typeDecl(dst);
if (isNotEqual(decl, parentdecl))
return true;
if (isNotEqual(decl, dst->valueType()))
if (isNotEqual(decl, dst->valueType(), dst->isCpp()))
return true;
if (isNotEqual(parentdecl, src->valueType()))
if (isNotEqual(parentdecl, src->valueType(), src->isCpp()))
return true;
}
return false;
Expand Down Expand Up @@ -7592,7 +7592,7 @@ static void valueFlowLibraryFunction(Token *tok, const std::string &returnValue,
if (returnValue.find("arg") != std::string::npos && argValues.empty())
return;
productParams(settings, argValues, [&](const std::unordered_map<nonneg int, ValueFlow::Value>& arg) {
ValueFlow::Value value = evaluateLibraryFunction(arg, returnValue, settings);
ValueFlow::Value value = evaluateLibraryFunction(arg, returnValue, settings, tok->isCpp());
if (value.isUninitValue())
return;
ValueFlow::Value::ValueKind kind = ValueFlow::Value::ValueKind::Known;
Expand Down Expand Up @@ -9086,11 +9086,11 @@ static bool getMinMaxValues(const ValueType *vt, const Platform &platform, MathL
return true;
}

static bool getMinMaxValues(const std::string &typestr, const Settings *settings, MathLib::bigint &minvalue, MathLib::bigint &maxvalue)
static bool getMinMaxValues(const std::string &typestr, const Settings *settings, bool cpp, MathLib::bigint &minvalue, MathLib::bigint &maxvalue)
{
TokenList typeTokens(settings);
std::istringstream istr(typestr+";");
if (!typeTokens.createTokens(istr))
if (!typeTokens.createTokens(istr, cpp ? Standards::Language::CPP : Standards::Language::C))
return false;
typeTokens.simplifyPlatformTypes();
typeTokens.simplifyStdType();
Expand Down Expand Up @@ -9210,7 +9210,7 @@ static void valueFlowUnknownFunctionReturn(TokenList &tokenlist, const Settings
// Get min/max values for return type
const std::string &typestr = settings->library.returnValueType(tok->previous());
MathLib::bigint minvalue, maxvalue;
if (!getMinMaxValues(typestr, settings, minvalue, maxvalue))
if (!getMinMaxValues(typestr, settings, tok->isCpp(), minvalue, maxvalue))
continue;

for (MathLib::bigint value : unknownValues) {
Expand Down
Loading

0 comments on commit e1ec95b

Please sign in to comment.