Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -651,9 +651,12 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
try {
if (mSettings.library.markupFile(filename)) {
if (mUnusedFunctionsCheck && mSettings.isUnusedFunctionCheckEnabled() && mSettings.buildDir.empty()) {
// this is not a real source file - we just want to tokenize it. treat it as C anyways as the language needs to be determined.
Tokenizer tokenizer(mSettings, this);
if (fileStream)
tokenizer.list.setLang(Standards::Language::C);
if (fileStream) {
tokenizer.list.createTokens(*fileStream, filename);
}
else {
std::ifstream in(filename);
tokenizer.list.createTokens(in, filename);
Expand Down Expand Up @@ -821,7 +824,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 @@ -929,7 +929,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 @@ -949,7 +949,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 @@ -1738,13 +1738,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 @@ -607,6 +607,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 @@ -1598,7 +1598,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 @@ -1754,15 +1754,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
4 changes: 2 additions & 2 deletions lib/symboldatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7596,7 +7596,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 @@ -7686,7 +7686,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: 0 additions & 1 deletion lib/token.h
Original file line number Diff line number Diff line change
Expand Up @@ -1479,7 +1479,6 @@ class CPPCHECKLIB Token {
mImpl->mDebug = td;
}

/** defaults to C++ if it cannot be determined */
bool isCpp() const;
};

Expand Down
72 changes: 71 additions & 1 deletion lib/tokenlist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
*/

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

#include "tokenlist.h"

#include "astutils.h"
Expand All @@ -40,6 +41,15 @@

#include <simplecpp.h>

//#define N_ASSERT_LANG

#ifndef N_ASSERT_LANG
#include <cassert>
#define ASSERT_LANG(x) assert(x)
#else
#define ASSERT_LANG(x)
#endif

// How many compileExpression recursions are allowed?
// For practical code this could be endless. But in some special torture test
// there needs to be a limit.
Expand Down Expand Up @@ -83,9 +93,16 @@ 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());
// TODO: cannot enable assert as this might occur for unknown extensions
//ASSERT_LANG(mLang != Standards::Language::None);
if (mLang == Standards::Language::None) {
// TODO: should default to C instead like we do for headers
// default to C++
mLang = Standards::Language::CPP;
}
}
}

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

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

appendFileIfNew(file0);

return createTokensInternal(code, file0);
}

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

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

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 +2136,33 @@ 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_LANG(mLang != Standards::Language::None);

// TODO: remove the fallback
if (mLang == Standards::Language::None)
return false; // treat as C++ by default

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

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

// TODO: remove the fallback
if (mLang == Standards::Language::None)
return true; // treat as C++ by default

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

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

mLang = lang;
}
19 changes: 10 additions & 9 deletions lib/tokenlist.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,15 +61,13 @@ class CPPCHECKLIB TokenList {
/** @return the source file path. e.g. "file.cpp" */
const std::string& getSourceFilePath() const;

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

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

void setLang(Standards::Language lang);

/**
* Delete all tokens in given token list
Expand Down Expand Up @@ -105,7 +103,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 @@ -203,6 +202,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 @@ -3810,20 +3810,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 @@ -3838,9 +3838,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 @@ -7680,7 +7680,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 @@ -9174,11 +9174,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 @@ -9300,7 +9300,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