From b03bdfaf72f67b46d651a3c05ab3ce6f4f86601d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Marjam=C3=A4ki?= Date: Sun, 5 Jan 2020 15:12:53 +0100 Subject: [PATCH] Import Clang ast dump (experimental) --- Makefile | 8 +- cli/cmdlineparser.cpp | 3 + lib/clangastdump.cpp | 306 +++++++++++++++++++++++++++++++++++++++++ lib/clangastdump.h | 37 +++++ lib/cppcheck.cpp | 37 +++++ lib/errorlogger.cpp | 6 +- lib/lib.pri | 2 + lib/settings.cpp | 1 + lib/settings.h | 3 + lib/symboldatabase.cpp | 33 +++++ lib/symboldatabase.h | 3 + lib/tokenlist.cpp | 5 + lib/tokenlist.h | 2 + 13 files changed, 441 insertions(+), 5 deletions(-) create mode 100644 lib/clangastdump.cpp create mode 100644 lib/clangastdump.h diff --git a/Makefile b/Makefile index 0023b4b16..b008aa403 100644 --- a/Makefile +++ b/Makefile @@ -184,6 +184,7 @@ LIBOBJ = $(libcppdir)/analyzerinfo.o \ $(libcppdir)/checkunusedfunctions.o \ $(libcppdir)/checkunusedvar.o \ $(libcppdir)/checkvaarg.o \ + $(libcppdir)/clangastdump.o \ $(libcppdir)/cppcheck.o \ $(libcppdir)/ctu.o \ $(libcppdir)/errorlogger.o \ @@ -479,7 +480,10 @@ $(libcppdir)/checkunusedvar.o: lib/checkunusedvar.cpp lib/astutils.h lib/check.h $(libcppdir)/checkvaarg.o: lib/checkvaarg.cpp lib/astutils.h lib/check.h lib/checkvaarg.h lib/config.h lib/errorlogger.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/checkvaarg.o $(libcppdir)/checkvaarg.cpp -$(libcppdir)/cppcheck.o: lib/cppcheck.cpp externals/picojson.h externals/simplecpp/simplecpp.h externals/tinyxml/tinyxml2.h lib/analyzerinfo.h lib/check.h lib/checkunusedfunctions.h lib/config.h lib/cppcheck.h lib/ctu.h lib/errorlogger.h lib/exprengine.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/version.h +$(libcppdir)/clangastdump.o: lib/clangastdump.cpp lib/clangastdump.h lib/config.h lib/errorlogger.h lib/library.h lib/mathlib.h lib/platform.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h + $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/clangastdump.o $(libcppdir)/clangastdump.cpp + +$(libcppdir)/cppcheck.o: lib/cppcheck.cpp externals/picojson.h externals/simplecpp/simplecpp.h externals/tinyxml/tinyxml2.h lib/analyzerinfo.h lib/check.h lib/checkunusedfunctions.h lib/clangastdump.h lib/config.h lib/cppcheck.h lib/ctu.h lib/errorlogger.h lib/exprengine.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/preprocessor.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h lib/version.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/cppcheck.o $(libcppdir)/cppcheck.cpp $(libcppdir)/ctu.o: lib/ctu.cpp externals/tinyxml/tinyxml2.h lib/astutils.h lib/check.h lib/config.h lib/ctu.h lib/errorlogger.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h @@ -488,7 +492,7 @@ $(libcppdir)/ctu.o: lib/ctu.cpp externals/tinyxml/tinyxml2.h lib/astutils.h lib/ $(libcppdir)/errorlogger.o: lib/errorlogger.cpp externals/tinyxml/tinyxml2.h lib/analyzerinfo.h lib/check.h lib/config.h lib/cppcheck.h lib/errorlogger.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/errorlogger.o $(libcppdir)/errorlogger.cpp -$(libcppdir)/exprengine.o: lib/exprengine.cpp lib/astutils.h lib/config.h lib/errorlogger.h lib/exprengine.h lib/importproject.h lib/library.h lib/mathlib.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h +$(libcppdir)/exprengine.o: lib/exprengine.cpp lib/astutils.h lib/config.h lib/errorlogger.h lib/exprengine.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/symboldatabase.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h $(CXX) ${INCLUDE_FOR_LIB} $(CPPFLAGS) $(CPPFILESDIR) $(CXXFLAGS) $(UNDEF_STRICT_ANSI) -c -o $(libcppdir)/exprengine.o $(libcppdir)/exprengine.cpp $(libcppdir)/importproject.o: lib/importproject.cpp externals/picojson.h externals/tinyxml/tinyxml2.h lib/config.h lib/errorlogger.h lib/importproject.h lib/library.h lib/mathlib.h lib/path.h lib/platform.h lib/settings.h lib/standards.h lib/suppressions.h lib/templatesimplifier.h lib/timer.h lib/token.h lib/tokenize.h lib/tokenlist.h lib/utils.h lib/valueflow.h diff --git a/cli/cmdlineparser.cpp b/cli/cmdlineparser.cpp index d52ab1629..3fbc7f6c6 100644 --- a/cli/cmdlineparser.cpp +++ b/cli/cmdlineparser.cpp @@ -133,6 +133,9 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[]) else if (std::strncmp(argv[i], "--addon=", 8) == 0) mSettings->addons.emplace_back(argv[i]+8); + else if (std::strcmp(argv[i], "--clang") == 0) + mSettings->clang = true; + else if (std::strncmp(argv[i], "--cppcheck-build-dir=", 21) == 0) { mSettings->buildDir = Path::fromNativeSeparators(argv[i] + 21); if (endsWith(mSettings->buildDir, '/')) diff --git a/lib/clangastdump.cpp b/lib/clangastdump.cpp new file mode 100644 index 000000000..212756190 --- /dev/null +++ b/lib/clangastdump.cpp @@ -0,0 +1,306 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2019 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 . + */ + +#include "clangastdump.h" +#include "symboldatabase.h" +#include "tokenize.h" + +#include +#include +#include + +static const std::string BinaryOperator = "BinaryOperator"; +static const std::string CallExpr = "CallExpr"; +static const std::string CompoundStmt = "CompoundStmt"; +static const std::string DeclRefExpr = "DeclRefExpr"; +static const std::string FunctionDecl = "FunctionDecl"; +static const std::string ImplicitCastExpr = "ImplicitCastExpr"; +static const std::string IntegerLiteral = "IntegerLiteral"; +static const std::string ParmVarDecl = "ParmVarDecl"; +static const std::string ReturnStmt = "ReturnStmt"; +static const std::string UnaryOperator = "UnaryOperator"; + +static std::string unquote(const std::string &s) +{ + return (s[0] == '\'') ? s.substr(1, s.size() - 2) : s; +} + +static std::vector splitString(const std::string &line) +{ + std::vector ret; + std::string::size_type pos1 = line.find_first_not_of(" "); + while (pos1 != std::string::npos) { + std::string::size_type pos2; + if (line[pos1] == '<') + pos2 = line.find(">", pos1); + else if (line[pos1] == '\'') + pos2 = line.find("\'", pos1+1); + else + pos2 = line.find(" ", pos1) - 1; + ret.push_back(line.substr(pos1, pos2+1-pos1)); + if (pos2 == std::string::npos) + break; + pos1 = line.find_first_not_of(" ", pos2 + 1); + } + return ret; +} + +namespace clangastdump { + struct Data { + std::map varId; + std::map variableMap; + }; + + class AstNode { + public: + AstNode(const std::string &nodeType, const std::string &ext, Data *data, SymbolDatabase *symbolDatabase) + : nodeType(nodeType), mExtTokens(splitString(ext)), mData(data), mSymbolDatabase(symbolDatabase) + {} + std::string nodeType; + std::vector> children; + + void setLocations(TokenList *tokenList, int file, int line, int col); + + void dumpAst(int num = 0, int indent = 0) const; + Token *createTokens(TokenList *tokenList); + private: + Token *addtoken(TokenList *tokenList, const std::string &str); + Token *addTypeTokens(TokenList *tokenList, const std::string &str); + std::string getSpelling() const; + std::string getType() const; + + int mFile = 0; + int mLine = 1; + int mCol = 1; + int mVarId = 0; + std::vector mExtTokens; + Data *mData; + SymbolDatabase *mSymbolDatabase; + }; + + typedef std::shared_ptr AstNodePtr; +} + +std::string clangastdump::AstNode::getSpelling() const +{ + if (nodeType == ParmVarDecl) + return mExtTokens[mExtTokens.size() - 2]; + return ""; +} + +std::string clangastdump::AstNode::getType() const +{ + if (nodeType == DeclRefExpr) + return unquote(mExtTokens.back()); + if (nodeType == BinaryOperator) + return unquote(mExtTokens[mExtTokens.size() - 2]); + if (nodeType == IntegerLiteral) + return unquote(mExtTokens[mExtTokens.size() - 2]); + return ""; +} + +void clangastdump::AstNode::dumpAst(int num, int indent) const +{ + (void)num; + std::cout << std::string(indent, ' ') << nodeType; + for (auto tok: mExtTokens) + std::cout << " " << tok; + std::cout << std::endl; + for (int c = 0; c < children.size(); ++c) + children[c]->dumpAst(c, indent + 2); +} + +void clangastdump::AstNode::setLocations(TokenList *tokenList, int file, int line, int col) +{ + for (const std::string &ext: mExtTokens) { + if (ext.compare(0,5,"appendFileIfNew(ext.substr(1,ext.find(":") - 1)); + } + mFile = file; + mLine = line; + mCol = col; + for (auto child: children) + child->setLocations(tokenList, file, line, col); +} + +Token *clangastdump::AstNode::addtoken(TokenList *tokenList, const std::string &str) +{ + tokenList->addtoken(str, mLine, mFile); + if (getType() == "int") + tokenList->back()->setValueType(new ValueType(ValueType::Sign::SIGNED, ValueType::Type::INT, 0)); + return tokenList->back(); +} + +Token *clangastdump::AstNode::addTypeTokens(TokenList *tokenList, const std::string &str) +{ + if (str.find(" (") == std::string::npos) + return addtoken(tokenList, unquote(str)); + return addtoken(tokenList, str.substr(1,str.find(" (")-1)); +} + +Token *clangastdump::AstNode::createTokens(TokenList *tokenList) +{ + if (nodeType == BinaryOperator) { + Token *tok1 = children[0]->createTokens(tokenList); + Token *binop = addtoken(tokenList, unquote(mExtTokens.back())); + Token *tok2 = children[1]->createTokens(tokenList); + binop->astOperand1(tok1); + binop->astOperand2(tok2); + return binop; + } + if (nodeType == CallExpr) { + Token *op1 = children[0]->createTokens(tokenList); + Token *call = addtoken(tokenList, "("); + call->astOperand1(op1); + for (int c = 1; c < children.size(); ++c) + call->astOperand2(children[c]->createTokens(tokenList)); + call->link(addtoken(tokenList, ")")); + return call; + } + if (nodeType == CompoundStmt) { + Token *start = addtoken(tokenList, "{"); + for (AstNodePtr child: children) { + child->createTokens(tokenList); + child->addtoken(tokenList, ";"); + } + Token *end = addtoken(tokenList, "}"); + start->link(end); + return start; + } + if (nodeType == DeclRefExpr) { + Token *vartok = addtoken(tokenList, unquote(mExtTokens[mExtTokens.size() - 2])); + std::string addr = mExtTokens[mExtTokens.size() - 3]; + vartok->varId(mData->varId[addr]); + vartok->variable(mData->variableMap[addr]); + return vartok; + } + if (nodeType == FunctionDecl) { + addTypeTokens(tokenList, mExtTokens.back()); + Token *nameToken = addtoken(tokenList, mExtTokens[mExtTokens.size() - 2]); + Scope &globalScope = mSymbolDatabase->scopeList.front(); + mSymbolDatabase->scopeList.push_back(Scope(nullptr, nullptr, &globalScope)); + Scope &scope = mSymbolDatabase->scopeList.back(); + mSymbolDatabase->functionScopes.push_back(&scope); + globalScope.functionList.push_back(Function(nameToken)); + scope.function = &globalScope.functionList.back(); + Token *par1 = addtoken(tokenList, "("); + for (AstNodePtr child: children) { + if (child->nodeType != ParmVarDecl) + continue; + if (tokenList->back() != par1) + addtoken(tokenList, ","); + addTypeTokens(tokenList, child->mExtTokens.back()); + const std::string spelling = child->getSpelling(); + if (!spelling.empty()) { + Token *vartok = addtoken(tokenList, spelling); + std::string addr = child->mExtTokens[0]; + int varId = mData->varId.size() + 1; + mData->varId[addr] = varId; + vartok->varId(varId); + scope.function->argumentList.push_back(Variable(vartok, nullptr, nullptr, varId, AccessControl::Argument, nullptr, nullptr, nullptr)); + Variable *var = &scope.function->argumentList.back(); + mData->variableMap[addr] = var; + vartok->variable(var); + var->setValueType(ValueType(ValueType::Sign::SIGNED, ValueType::Type::INT, 0)); + } + } + Token *par2 = addtoken(tokenList, ")"); + par1->link(par2); + children.back()->createTokens(tokenList); + if (Token::simpleMatch(par2, ") {")) { + Token *bodyStart = par2->next(); + scope.bodyStart = bodyStart; + scope.bodyEnd = bodyStart->link(); + } + return nullptr; + } + if (nodeType == ImplicitCastExpr) + return children[0]->createTokens(tokenList); + if (nodeType == IntegerLiteral) + return addtoken(tokenList, mExtTokens.back()); + if (nodeType == ReturnStmt) { + Token *tok1 = addtoken(tokenList, "return"); + if (!children.empty()) + tok1->astOperand1(children[0]->createTokens(tokenList)); + return tok1; + } + if (nodeType == UnaryOperator) { + Token *unop = addtoken(tokenList, unquote(mExtTokens.back())); + unop->astOperand1(children[0]->createTokens(tokenList)); + return unop; + } + return addtoken(tokenList, "?" + nodeType + "?"); +} + +void clangastdump::parseClangAstDump(Tokenizer *tokenizer, std::istream &f) +{ + TokenList *tokenList = &tokenizer->list; + clangastdump::Data data; + + tokenizer->createSymbolDatabase(); + SymbolDatabase *symbolDatabase = const_cast(tokenizer->getSymbolDatabase()); + symbolDatabase->scopeList.push_back(Scope(nullptr, nullptr, nullptr)); + symbolDatabase->scopeList.back().type = Scope::ScopeType::eGlobal; + + std::string line; + std::vector tree; + while (std::getline(f,line)) { + const std::string::size_type pos1 = line.find("-"); + if (pos1 == std::string::npos) + continue; + const std::string::size_type pos2 = line.find(" ", pos1); + if (pos2 < pos1 + 4 || pos2 == std::string::npos) + continue; + const std::string nodeType = line.substr(pos1+1, pos2 - pos1 - 1); + const std::string ext = line.substr(pos2); + + if (nodeType == FunctionDecl) { + if (!tree.empty()) { + tree[0]->setLocations(tokenList, 0, 1, 1); + tree[0]->createTokens(tokenList); + } + tree.clear(); + tree.push_back(std::make_shared(nodeType, ext, &data, symbolDatabase)); + continue; + } + + const int level = (pos1 - 1) / 2; + if (level == 0 || tree.empty()) + continue; + + AstNodePtr newNode = std::make_shared(nodeType, ext, &data, symbolDatabase); + tree[level - 1]->children.push_back(newNode); + if (level >= tree.size()) + tree.push_back(newNode); + else + tree[level] = newNode; + } + + if (!tree.empty()) { + tree[0]->setLocations(tokenList, 0, 1, 1); + tree[0]->createTokens(tokenList); + } + + symbolDatabase->clangSetVariables(data.variableMap); + tokenList->clangSetOrigFiles(); +} + diff --git a/lib/clangastdump.h b/lib/clangastdump.h new file mode 100644 index 000000000..0d712d824 --- /dev/null +++ b/lib/clangastdump.h @@ -0,0 +1,37 @@ +/* + * Cppcheck - A tool for static C/C++ code analysis + * Copyright (C) 2007-2020 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 . + */ + + +//--------------------------------------------------------------------------- +#ifndef clangastdumpH +#define clangastdumpH +//--------------------------------------------------------------------------- + +#include +#include + +class SymbolDatabase; +class Tokenizer; + +namespace clangastdump { + + void parseClangAstDump(Tokenizer *tokenizer, std::istream &f); + +} + +#endif diff --git a/lib/cppcheck.cpp b/lib/cppcheck.cpp index f4f275a3c..0e3f6e92e 100644 --- a/lib/cppcheck.cpp +++ b/lib/cppcheck.cpp @@ -19,6 +19,7 @@ #include "check.h" #include "checkunusedfunctions.h" +#include "clangastdump.h" #include "ctu.h" #include "library.h" #include "mathlib.h" @@ -196,6 +197,24 @@ static std::vector split(const std::string &str, const std::string return ret; } +static std::pair executeCommand(const std::string &cmd) +{ +#ifdef _WIN32 + std::unique_ptr pipe(_popen(cmd.c_str(), "r"), _pclose); +#else + std::unique_ptr pipe(popen(cmd.c_str(), "r"), pclose); +#endif + + if (!pipe) + return std::pair(false, ""); + + char buffer[1024]; + std::string result; + while (fgets(buffer, sizeof(buffer), pipe.get()) != nullptr) + result += buffer; + return std::pair(true, result); +} + CppCheck::CppCheck(ErrorLogger &errorLogger, bool useGlobalSuppressions) : mErrorLogger(errorLogger), mExitCode(0), mSuppressInternalErrorFound(false), mUseGlobalSuppressions(useGlobalSuppressions), mTooManyConfigs(false), mSimplify(true) { @@ -222,6 +241,24 @@ const char * CppCheck::extraVersion() unsigned int CppCheck::check(const std::string &path) { + if (mSettings.clang) { + /* Experimental: import clang ast dump */ + const std::string cmd = "clang -cc1 -ast-dump " + path; + std::pair res = executeCommand(cmd); + if (!res.first) { + std::cerr << "Failed to execute '" + cmd + "'" << std::endl; + return 0; + } + //std::cout << "Checking Clang ast dump:\n" << res.second << std::endl; + std::istringstream ast(res.second); + Tokenizer tokenizer(&mSettings, this); + clangastdump::parseClangAstDump(&tokenizer, ast); + //tokenizer.tokens()->printOut(""); + //tokenizer.tokens()->printAst(true, false, std::cout); + ExprEngine::runChecks(this, &tokenizer, &mSettings); + return 0; + } + std::ifstream fin(path); return checkFile(Path::simplifyPath(path), emptyString, fin); } diff --git a/lib/errorlogger.cpp b/lib/errorlogger.cpp index 8dc654b32..b03c5d388 100644 --- a/lib/errorlogger.cpp +++ b/lib/errorlogger.cpp @@ -112,12 +112,12 @@ ErrorLogger::ErrorMessage::ErrorMessage(const std::list& callstack : id(id), severity(severity), cwe(cwe.id), inconclusive(inconclusive) { // Format callstack - for (std::list::const_iterator it = callstack.begin(); it != callstack.end(); ++it) { + for (const Token *tok: callstack) { // --errorlist can provide null values here - if (!(*it)) + if (!tok) continue; - callStack.emplace_back(*it, list); + callStack.emplace_back(tok, list); } if (list && !list->getFiles().empty()) diff --git a/lib/lib.pri b/lib/lib.pri index f689e5289..83b357b38 100644 --- a/lib/lib.pri +++ b/lib/lib.pri @@ -31,6 +31,7 @@ HEADERS += $${PWD}/analyzerinfo.h \ $${PWD}/checkunusedfunctions.h \ $${PWD}/checkunusedvar.h \ $${PWD}/checkvaarg.h \ + $${PWD}/clangastdump.h \ $${PWD}/cppcheck.h \ $${PWD}/ctu.h \ $${PWD}/errorlogger.h \ @@ -82,6 +83,7 @@ SOURCES += $${PWD}/analyzerinfo.cpp \ $${PWD}/checkunusedfunctions.cpp \ $${PWD}/checkunusedvar.cpp \ $${PWD}/checkvaarg.cpp \ + $${PWD}/clangastdump.cpp \ $${PWD}/cppcheck.cpp \ $${PWD}/ctu.cpp \ $${PWD}/errorlogger.cpp \ diff --git a/lib/settings.cpp b/lib/settings.cpp index f329bc552..b74566e3c 100644 --- a/lib/settings.cpp +++ b/lib/settings.cpp @@ -34,6 +34,7 @@ Settings::Settings() checkLibrary(false), checkHeaders(true), checkUnusedTemplates(false), + clang(false), debugSimplified(false), debugnormal(false), debugwarnings(false), diff --git a/lib/settings.h b/lib/settings.h index 2caacfaf1..d72444c55 100644 --- a/lib/settings.h +++ b/lib/settings.h @@ -93,6 +93,9 @@ public: /** Check unused templates */ bool checkUnusedTemplates; + /** Use Clang */ + bool clang; + /** @brief include paths excluded from checking the configuration */ std::set configExcludePaths; diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index df3aff0a5..7bfea025c 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -39,6 +39,9 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) : mTokenizer(tokenizer), mSettings(settings), mErrorLogger(errorLogger) { + if (!tokenizer || !tokenizer->tokens()) + return; + mIsCpp = isCPP(); if (mSettings->defaultSign == 's' || mSettings->defaultSign == 'S') @@ -1715,6 +1718,13 @@ void SymbolDatabase::validate() const //validateVariables(); } +void SymbolDatabase::clangSetVariables(const std::map &variableMap) +{ + mVariableList.resize(variableMap.size() + 1); + for (std::map::const_iterator it = variableMap.begin(); it != variableMap.end(); ++it) + mVariableList[it->second->declarationId()] = it->second; +} + Variable::~Variable() { delete mValueType; @@ -1738,6 +1748,9 @@ const Token * Variable::declEndToken() const void Variable::evaluate(const Settings* settings) { + if (!settings) + return; + const Library * const lib = settings ? &settings->library : nullptr; if (mNameToken) @@ -2020,6 +2033,26 @@ Function::Function(const Tokenizer *mTokenizer, } } +Function::Function(const Token *tokenDef) + : tokenDef(tokenDef), + argDef(nullptr), + token(nullptr), + arg(nullptr), + retDef(nullptr), + retType(nullptr), + functionScope(nullptr), + nestedIn(nullptr), + initArgCount(0), + type(eFunction), + access(AccessControl::Public), + noexceptArg(nullptr), + throwArg(nullptr), + templateDef(nullptr), + mFlags(0) +{ +} + + static std::string qualifiedName(const Scope *scope) { std::string name = scope->className; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 30592243e..4338ee49b 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -716,6 +716,7 @@ public: enum Type { eConstructor, eCopyConstructor, eMoveConstructor, eOperatorEqual, eDestructor, eFunction, eLambda }; Function(const Tokenizer *mTokenizer, const Token *tok, const Scope *scope, const Token *tokDef, const Token *tokArgDef); + Function(const Token *tokenDef); const std::string &name() const { return tokenDef->str(); @@ -1304,6 +1305,8 @@ public: /** Set array dimensions when valueflow analysis is completed */ void setArrayDimensionsUsingValueFlow(); + void clangSetVariables(const std::map &variableMap); + private: friend class Scope; friend class Function; diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index ad7b22bc3..9c02b35be 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -94,6 +94,11 @@ int TokenList::appendFileIfNew(const std::string &fileName) return mFiles.size() - 1; } +void TokenList::clangSetOrigFiles() +{ + mOrigFiles = mFiles; +} + void TokenList::deleteTokens(Token *tok) { while (tok) { diff --git a/lib/tokenlist.h b/lib/tokenlist.h index 58c1fbcd6..3257ec671 100644 --- a/lib/tokenlist.h +++ b/lib/tokenlist.h @@ -186,6 +186,8 @@ public: */ void simplifyStdType(); + void clangSetOrigFiles(); + private: /** Disable copy constructor, no implementation */