Import Clang ast dump (experimental)
This commit is contained in:
parent
84cb5fea2a
commit
b03bdfaf72
8
Makefile
8
Makefile
|
@ -184,6 +184,7 @@ LIBOBJ = $(libcppdir)/analyzerinfo.o \
|
||||||
$(libcppdir)/checkunusedfunctions.o \
|
$(libcppdir)/checkunusedfunctions.o \
|
||||||
$(libcppdir)/checkunusedvar.o \
|
$(libcppdir)/checkunusedvar.o \
|
||||||
$(libcppdir)/checkvaarg.o \
|
$(libcppdir)/checkvaarg.o \
|
||||||
|
$(libcppdir)/clangastdump.o \
|
||||||
$(libcppdir)/cppcheck.o \
|
$(libcppdir)/cppcheck.o \
|
||||||
$(libcppdir)/ctu.o \
|
$(libcppdir)/ctu.o \
|
||||||
$(libcppdir)/errorlogger.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
|
$(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
|
$(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
|
$(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
|
$(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
|
$(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
|
$(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
|
$(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
|
$(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
|
||||||
|
|
|
@ -133,6 +133,9 @@ bool CmdLineParser::parseFromArgs(int argc, const char* const argv[])
|
||||||
else if (std::strncmp(argv[i], "--addon=", 8) == 0)
|
else if (std::strncmp(argv[i], "--addon=", 8) == 0)
|
||||||
mSettings->addons.emplace_back(argv[i]+8);
|
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) {
|
else if (std::strncmp(argv[i], "--cppcheck-build-dir=", 21) == 0) {
|
||||||
mSettings->buildDir = Path::fromNativeSeparators(argv[i] + 21);
|
mSettings->buildDir = Path::fromNativeSeparators(argv[i] + 21);
|
||||||
if (endsWith(mSettings->buildDir, '/'))
|
if (endsWith(mSettings->buildDir, '/'))
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "clangastdump.h"
|
||||||
|
#include "symboldatabase.h"
|
||||||
|
#include "tokenize.h"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
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<std::string> splitString(const std::string &line)
|
||||||
|
{
|
||||||
|
std::vector<std::string> 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<std::string, int> varId;
|
||||||
|
std::map<std::string, Variable *> 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<std::shared_ptr<AstNode>> 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<std::string> mExtTokens;
|
||||||
|
Data *mData;
|
||||||
|
SymbolDatabase *mSymbolDatabase;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef std::shared_ptr<AstNode> 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,"<col:") == 0)
|
||||||
|
col = std::atoi(ext.substr(5).c_str());
|
||||||
|
else if (ext.compare(0,6,"<line:") == 0)
|
||||||
|
line = std::atoi(ext.substr(6).c_str());
|
||||||
|
else if (ext[0] == '<')
|
||||||
|
file = tokenList->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<SymbolDatabase *>(tokenizer->getSymbolDatabase());
|
||||||
|
symbolDatabase->scopeList.push_back(Scope(nullptr, nullptr, nullptr));
|
||||||
|
symbolDatabase->scopeList.back().type = Scope::ScopeType::eGlobal;
|
||||||
|
|
||||||
|
std::string line;
|
||||||
|
std::vector<AstNodePtr> 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<AstNode>(nodeType, ext, &data, symbolDatabase));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const int level = (pos1 - 1) / 2;
|
||||||
|
if (level == 0 || tree.empty())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
AstNodePtr newNode = std::make_shared<AstNode>(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();
|
||||||
|
}
|
||||||
|
|
|
@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
#ifndef clangastdumpH
|
||||||
|
#define clangastdumpH
|
||||||
|
//---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
class SymbolDatabase;
|
||||||
|
class Tokenizer;
|
||||||
|
|
||||||
|
namespace clangastdump {
|
||||||
|
|
||||||
|
void parseClangAstDump(Tokenizer *tokenizer, std::istream &f);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "check.h"
|
#include "check.h"
|
||||||
#include "checkunusedfunctions.h"
|
#include "checkunusedfunctions.h"
|
||||||
|
#include "clangastdump.h"
|
||||||
#include "ctu.h"
|
#include "ctu.h"
|
||||||
#include "library.h"
|
#include "library.h"
|
||||||
#include "mathlib.h"
|
#include "mathlib.h"
|
||||||
|
@ -196,6 +197,24 @@ static std::vector<std::string> split(const std::string &str, const std::string
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static std::pair<bool,std::string> executeCommand(const std::string &cmd)
|
||||||
|
{
|
||||||
|
#ifdef _WIN32
|
||||||
|
std::unique_ptr<FILE, decltype(&_pclose)> pipe(_popen(cmd.c_str(), "r"), _pclose);
|
||||||
|
#else
|
||||||
|
std::unique_ptr<FILE, decltype(&pclose)> pipe(popen(cmd.c_str(), "r"), pclose);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (!pipe)
|
||||||
|
return std::pair<bool, std::string>(false, "");
|
||||||
|
|
||||||
|
char buffer[1024];
|
||||||
|
std::string result;
|
||||||
|
while (fgets(buffer, sizeof(buffer), pipe.get()) != nullptr)
|
||||||
|
result += buffer;
|
||||||
|
return std::pair<bool, std::string>(true, result);
|
||||||
|
}
|
||||||
|
|
||||||
CppCheck::CppCheck(ErrorLogger &errorLogger, bool useGlobalSuppressions)
|
CppCheck::CppCheck(ErrorLogger &errorLogger, bool useGlobalSuppressions)
|
||||||
: mErrorLogger(errorLogger), mExitCode(0), mSuppressInternalErrorFound(false), mUseGlobalSuppressions(useGlobalSuppressions), mTooManyConfigs(false), mSimplify(true)
|
: 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)
|
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<bool, std::string> 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);
|
std::ifstream fin(path);
|
||||||
return checkFile(Path::simplifyPath(path), emptyString, fin);
|
return checkFile(Path::simplifyPath(path), emptyString, fin);
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,12 +112,12 @@ ErrorLogger::ErrorMessage::ErrorMessage(const std::list<const Token*>& callstack
|
||||||
: id(id), severity(severity), cwe(cwe.id), inconclusive(inconclusive)
|
: id(id), severity(severity), cwe(cwe.id), inconclusive(inconclusive)
|
||||||
{
|
{
|
||||||
// Format callstack
|
// Format callstack
|
||||||
for (std::list<const Token *>::const_iterator it = callstack.begin(); it != callstack.end(); ++it) {
|
for (const Token *tok: callstack) {
|
||||||
// --errorlist can provide null values here
|
// --errorlist can provide null values here
|
||||||
if (!(*it))
|
if (!tok)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
callStack.emplace_back(*it, list);
|
callStack.emplace_back(tok, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (list && !list->getFiles().empty())
|
if (list && !list->getFiles().empty())
|
||||||
|
|
|
@ -31,6 +31,7 @@ HEADERS += $${PWD}/analyzerinfo.h \
|
||||||
$${PWD}/checkunusedfunctions.h \
|
$${PWD}/checkunusedfunctions.h \
|
||||||
$${PWD}/checkunusedvar.h \
|
$${PWD}/checkunusedvar.h \
|
||||||
$${PWD}/checkvaarg.h \
|
$${PWD}/checkvaarg.h \
|
||||||
|
$${PWD}/clangastdump.h \
|
||||||
$${PWD}/cppcheck.h \
|
$${PWD}/cppcheck.h \
|
||||||
$${PWD}/ctu.h \
|
$${PWD}/ctu.h \
|
||||||
$${PWD}/errorlogger.h \
|
$${PWD}/errorlogger.h \
|
||||||
|
@ -82,6 +83,7 @@ SOURCES += $${PWD}/analyzerinfo.cpp \
|
||||||
$${PWD}/checkunusedfunctions.cpp \
|
$${PWD}/checkunusedfunctions.cpp \
|
||||||
$${PWD}/checkunusedvar.cpp \
|
$${PWD}/checkunusedvar.cpp \
|
||||||
$${PWD}/checkvaarg.cpp \
|
$${PWD}/checkvaarg.cpp \
|
||||||
|
$${PWD}/clangastdump.cpp \
|
||||||
$${PWD}/cppcheck.cpp \
|
$${PWD}/cppcheck.cpp \
|
||||||
$${PWD}/ctu.cpp \
|
$${PWD}/ctu.cpp \
|
||||||
$${PWD}/errorlogger.cpp \
|
$${PWD}/errorlogger.cpp \
|
||||||
|
|
|
@ -34,6 +34,7 @@ Settings::Settings()
|
||||||
checkLibrary(false),
|
checkLibrary(false),
|
||||||
checkHeaders(true),
|
checkHeaders(true),
|
||||||
checkUnusedTemplates(false),
|
checkUnusedTemplates(false),
|
||||||
|
clang(false),
|
||||||
debugSimplified(false),
|
debugSimplified(false),
|
||||||
debugnormal(false),
|
debugnormal(false),
|
||||||
debugwarnings(false),
|
debugwarnings(false),
|
||||||
|
|
|
@ -93,6 +93,9 @@ public:
|
||||||
/** Check unused templates */
|
/** Check unused templates */
|
||||||
bool checkUnusedTemplates;
|
bool checkUnusedTemplates;
|
||||||
|
|
||||||
|
/** Use Clang */
|
||||||
|
bool clang;
|
||||||
|
|
||||||
/** @brief include paths excluded from checking the configuration */
|
/** @brief include paths excluded from checking the configuration */
|
||||||
std::set<std::string> configExcludePaths;
|
std::set<std::string> configExcludePaths;
|
||||||
|
|
||||||
|
|
|
@ -39,6 +39,9 @@
|
||||||
SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
|
SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger)
|
||||||
: mTokenizer(tokenizer), mSettings(settings), mErrorLogger(errorLogger)
|
: mTokenizer(tokenizer), mSettings(settings), mErrorLogger(errorLogger)
|
||||||
{
|
{
|
||||||
|
if (!tokenizer || !tokenizer->tokens())
|
||||||
|
return;
|
||||||
|
|
||||||
mIsCpp = isCPP();
|
mIsCpp = isCPP();
|
||||||
|
|
||||||
if (mSettings->defaultSign == 's' || mSettings->defaultSign == 'S')
|
if (mSettings->defaultSign == 's' || mSettings->defaultSign == 'S')
|
||||||
|
@ -1715,6 +1718,13 @@ void SymbolDatabase::validate() const
|
||||||
//validateVariables();
|
//validateVariables();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SymbolDatabase::clangSetVariables(const std::map<std::string, Variable *> &variableMap)
|
||||||
|
{
|
||||||
|
mVariableList.resize(variableMap.size() + 1);
|
||||||
|
for (std::map<std::string, Variable *>::const_iterator it = variableMap.begin(); it != variableMap.end(); ++it)
|
||||||
|
mVariableList[it->second->declarationId()] = it->second;
|
||||||
|
}
|
||||||
|
|
||||||
Variable::~Variable()
|
Variable::~Variable()
|
||||||
{
|
{
|
||||||
delete mValueType;
|
delete mValueType;
|
||||||
|
@ -1738,6 +1748,9 @@ const Token * Variable::declEndToken() const
|
||||||
|
|
||||||
void Variable::evaluate(const Settings* settings)
|
void Variable::evaluate(const Settings* settings)
|
||||||
{
|
{
|
||||||
|
if (!settings)
|
||||||
|
return;
|
||||||
|
|
||||||
const Library * const lib = settings ? &settings->library : nullptr;
|
const Library * const lib = settings ? &settings->library : nullptr;
|
||||||
|
|
||||||
if (mNameToken)
|
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)
|
static std::string qualifiedName(const Scope *scope)
|
||||||
{
|
{
|
||||||
std::string name = scope->className;
|
std::string name = scope->className;
|
||||||
|
|
|
@ -716,6 +716,7 @@ public:
|
||||||
enum Type { eConstructor, eCopyConstructor, eMoveConstructor, eOperatorEqual, eDestructor, eFunction, eLambda };
|
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 Tokenizer *mTokenizer, const Token *tok, const Scope *scope, const Token *tokDef, const Token *tokArgDef);
|
||||||
|
Function(const Token *tokenDef);
|
||||||
|
|
||||||
const std::string &name() const {
|
const std::string &name() const {
|
||||||
return tokenDef->str();
|
return tokenDef->str();
|
||||||
|
@ -1304,6 +1305,8 @@ public:
|
||||||
/** Set array dimensions when valueflow analysis is completed */
|
/** Set array dimensions when valueflow analysis is completed */
|
||||||
void setArrayDimensionsUsingValueFlow();
|
void setArrayDimensionsUsingValueFlow();
|
||||||
|
|
||||||
|
void clangSetVariables(const std::map<std::string, Variable *> &variableMap);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class Scope;
|
friend class Scope;
|
||||||
friend class Function;
|
friend class Function;
|
||||||
|
|
|
@ -94,6 +94,11 @@ int TokenList::appendFileIfNew(const std::string &fileName)
|
||||||
return mFiles.size() - 1;
|
return mFiles.size() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TokenList::clangSetOrigFiles()
|
||||||
|
{
|
||||||
|
mOrigFiles = mFiles;
|
||||||
|
}
|
||||||
|
|
||||||
void TokenList::deleteTokens(Token *tok)
|
void TokenList::deleteTokens(Token *tok)
|
||||||
{
|
{
|
||||||
while (tok) {
|
while (tok) {
|
||||||
|
|
|
@ -186,6 +186,8 @@ public:
|
||||||
*/
|
*/
|
||||||
void simplifyStdType();
|
void simplifyStdType();
|
||||||
|
|
||||||
|
void clangSetOrigFiles();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/** Disable copy constructor, no implementation */
|
/** Disable copy constructor, no implementation */
|
||||||
|
|
Loading…
Reference in New Issue