mirror of https://github.com/mono/CppSharp.git
Browse Source
* Code cleanups. * Run GetterSetterToPropertyPass for more generators. * Fixed compile warning when compiling parser bindings. * Cleanup driver code. * Remove dead 32-bit code. * Reduce verbosity when Options.Quiet is set. * Remove test compile-time warnings. * Move .NET tests to tests/dotnet. * Remove unused AST viewer code and premake-qt submodule. * Move tests2/ contents to tests/.quickjs
160 changed files with 219 additions and 2603 deletions
@ -1,3 +0,0 @@ |
|||||||
[submodule "build/modules/premake-qt"] |
|
||||||
path = build/modules/premake-qt |
|
||||||
url = https://github.com/dcourtois/premake-qt.git |
|
@ -1,141 +0,0 @@ |
|||||||
#include "AstModel.h" |
|
||||||
#include <qbrush.h> |
|
||||||
|
|
||||||
|
|
||||||
AstModel::AstModel(GenericAstNode *data, QObject *parent): |
|
||||||
QAbstractItemModel(parent), |
|
||||||
rootItem(data) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
AstModel::~AstModel() |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
int AstModel::columnCount(const QModelIndex &parent) const |
|
||||||
{ |
|
||||||
return 1; |
|
||||||
} |
|
||||||
|
|
||||||
QVariant AstModel::data(const QModelIndex &index, int role) const |
|
||||||
{ |
|
||||||
if (!index.isValid()) |
|
||||||
return QVariant(); |
|
||||||
|
|
||||||
if (role != Qt::DisplayRole && role != Qt::ForegroundRole && role != Qt::NodeRole) |
|
||||||
return QVariant(); |
|
||||||
|
|
||||||
auto item = static_cast<GenericAstNode*>(index.internalPointer()); |
|
||||||
switch (role) |
|
||||||
{ |
|
||||||
case Qt::DisplayRole: |
|
||||||
return QVariant(QString::fromStdString(item->name)); |
|
||||||
case Qt::ForegroundRole: |
|
||||||
switch (item->getColor()) |
|
||||||
{ |
|
||||||
case 0: |
|
||||||
return QVariant(QBrush(Qt::GlobalColor::darkBlue)); |
|
||||||
case 1: |
|
||||||
return QVariant(QBrush(Qt::GlobalColor::darkGreen)); |
|
||||||
default: |
|
||||||
return QVariant(QBrush(Qt::GlobalColor::black)); |
|
||||||
} |
|
||||||
case Qt::NodeRole: |
|
||||||
return QVariant::fromValue(item); |
|
||||||
} |
|
||||||
return QVariant(QString::fromStdString(item->name)); |
|
||||||
} |
|
||||||
|
|
||||||
Qt::ItemFlags AstModel::flags(const QModelIndex &index) const |
|
||||||
{ |
|
||||||
if (!index.isValid()) |
|
||||||
return 0; |
|
||||||
|
|
||||||
return QAbstractItemModel::flags(index); |
|
||||||
} |
|
||||||
|
|
||||||
QVariant AstModel::headerData(int section, Qt::Orientation orientation, int role) const |
|
||||||
{ |
|
||||||
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) |
|
||||||
return QVariant("Test"); |
|
||||||
|
|
||||||
return QVariant(); |
|
||||||
} |
|
||||||
|
|
||||||
QModelIndex AstModel::index(int row, int column, const QModelIndex &parent) const |
|
||||||
{ |
|
||||||
if (!hasIndex(row, column, parent)) |
|
||||||
return QModelIndex(); |
|
||||||
|
|
||||||
|
|
||||||
if (!parent.isValid()) |
|
||||||
{ |
|
||||||
return rootIndex(); |
|
||||||
} |
|
||||||
|
|
||||||
auto parentItem = static_cast<GenericAstNode*>(parent.internalPointer()); |
|
||||||
auto &childItem = parentItem->myChidren[row]; |
|
||||||
if (childItem) |
|
||||||
return createIndex(row, column, childItem.get()); |
|
||||||
else |
|
||||||
return QModelIndex(); |
|
||||||
} |
|
||||||
|
|
||||||
QModelIndex AstModel::rootIndex() const |
|
||||||
{ |
|
||||||
return createIndex(0, 0, rootItem); |
|
||||||
} |
|
||||||
|
|
||||||
QModelIndex AstModel::parent(const QModelIndex &index) const |
|
||||||
{ |
|
||||||
if (!index.isValid()) |
|
||||||
return QModelIndex(); |
|
||||||
|
|
||||||
GenericAstNode *childItem = static_cast<GenericAstNode*>(index.internalPointer()); |
|
||||||
if (childItem == rootItem || childItem->myParent == nullptr) |
|
||||||
return QModelIndex(); |
|
||||||
|
|
||||||
GenericAstNode *parentItem = childItem->myParent; |
|
||||||
|
|
||||||
if (parentItem == rootItem) |
|
||||||
return rootIndex(); |
|
||||||
auto grandFather = parentItem->myParent; |
|
||||||
auto parentRow = grandFather == nullptr ? |
|
||||||
0 : |
|
||||||
grandFather->findChildIndex(parentItem); |
|
||||||
|
|
||||||
return createIndex(parentRow, 0, parentItem); |
|
||||||
} |
|
||||||
|
|
||||||
int AstModel::rowCount(const QModelIndex &parent) const |
|
||||||
{ |
|
||||||
GenericAstNode *parentItem; |
|
||||||
if (parent.column() > 0) |
|
||||||
return 0; |
|
||||||
|
|
||||||
if (parent.isValid()) |
|
||||||
{ |
|
||||||
parentItem = static_cast<GenericAstNode*>(parent.internalPointer()); |
|
||||||
return parentItem->myChidren.size(); |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
return 1; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
bool AstModel::hasChildren(const QModelIndex &parent) const |
|
||||||
{ |
|
||||||
GenericAstNode *parentItem; |
|
||||||
if (parent.column() > 0) |
|
||||||
return false; |
|
||||||
|
|
||||||
if (parent.isValid()) |
|
||||||
parentItem = static_cast<GenericAstNode*>(parent.internalPointer()); |
|
||||||
else |
|
||||||
parentItem = rootItem; |
|
||||||
|
|
||||||
return !parentItem->myChidren.empty(); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
@ -1,35 +0,0 @@ |
|||||||
#pragma once |
|
||||||
|
|
||||||
#include <qabstractitemmodel.h> |
|
||||||
#include "AstReader.h" |
|
||||||
|
|
||||||
namespace Qt |
|
||||||
{ |
|
||||||
int const NodeRole = UserRole + 1; |
|
||||||
} |
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(GenericAstNode*) |
|
||||||
|
|
||||||
class AstModel : public QAbstractItemModel |
|
||||||
{ |
|
||||||
Q_OBJECT |
|
||||||
|
|
||||||
public: |
|
||||||
explicit AstModel(GenericAstNode *data, QObject *parent = 0); |
|
||||||
~AstModel(); |
|
||||||
|
|
||||||
QVariant data(const QModelIndex &index, int role) const override; |
|
||||||
Qt::ItemFlags flags(const QModelIndex &index) const override; |
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; |
|
||||||
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; |
|
||||||
QModelIndex parent(const QModelIndex &index) const override; |
|
||||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override; |
|
||||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override; |
|
||||||
QModelIndex rootIndex() const; |
|
||||||
bool hasChildren(const QModelIndex &parent = QModelIndex()) const override; |
|
||||||
|
|
||||||
private: |
|
||||||
void setupModelData(const QStringList &lines, GenericAstNode *parent); |
|
||||||
|
|
||||||
GenericAstNode *rootItem; |
|
||||||
}; |
|
@ -1,543 +0,0 @@ |
|||||||
#include "AstReader.h" |
|
||||||
#include <sstream> |
|
||||||
#include "CommandLineSplitter.h" |
|
||||||
#include <iostream> |
|
||||||
#include "ClangUtilities/StringLiteralExtractor.h" |
|
||||||
#include "ClangUtilities/TemplateUtilities.h" |
|
||||||
|
|
||||||
|
|
||||||
#pragma warning (push) |
|
||||||
#pragma warning (disable:4100 4127 4800 4512 4245 4291 4510 4610 4324 4267 4244 4996) |
|
||||||
#include <llvm/Support/Path.h> |
|
||||||
#include <clang/Tooling/Tooling.h> |
|
||||||
#include <clang/AST/RecursiveASTVisitor.h> |
|
||||||
#include <clang/Frontend/FrontendActions.h> |
|
||||||
#include <clang/AST/Decl.h> |
|
||||||
#include <clang/Lex/Lexer.h> |
|
||||||
#include <clang/Basic/TargetInfo.h> |
|
||||||
#include <clang/Frontend/CompilerInstance.h> |
|
||||||
#include <clang/AST/Mangle.h> |
|
||||||
#include <clang/Analysis/CFG.h> |
|
||||||
#pragma warning (pop) |
|
||||||
|
|
||||||
using namespace clang; |
|
||||||
|
|
||||||
namespace props |
|
||||||
{ |
|
||||||
std::string const Name = "Name"; |
|
||||||
std::string const Mangling = "Mangling"; |
|
||||||
std::string const Referenced = "Referenced name"; |
|
||||||
std::string const Resolved = "Resolved name"; |
|
||||||
std::string const Value = "Value"; |
|
||||||
std::string const InterpretedValue = "Interpreted value"; |
|
||||||
std::string const IsTemplateDecl = "Is template declaration"; |
|
||||||
std::string const IsGenerated = "Generated"; |
|
||||||
std::string const Type = "Type"; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
CFG::BuildOptions getCFGBuildOptions() |
|
||||||
{ |
|
||||||
CFG::BuildOptions cfgBuildOptions; // TODO: Initialize it correctly
|
|
||||||
cfgBuildOptions.AddImplicitDtors = true; |
|
||||||
cfgBuildOptions.AddTemporaryDtors = true; |
|
||||||
cfgBuildOptions.AddCXXDefaultInitExprInCtors = true; |
|
||||||
cfgBuildOptions.AddInitializers = true; |
|
||||||
return cfgBuildOptions; |
|
||||||
} |
|
||||||
|
|
||||||
std::string getCFG(clang::FunctionDecl const *FD) |
|
||||||
{ |
|
||||||
try |
|
||||||
{ |
|
||||||
auto& astContext = FD->getASTContext(); |
|
||||||
auto cfgBuildOptions = getCFGBuildOptions(); |
|
||||||
auto cfg = CFG::buildCFG(FD, FD->getBody(), &astContext, cfgBuildOptions); |
|
||||||
if (!cfg) |
|
||||||
return ""; |
|
||||||
std::string dumpBuf; |
|
||||||
llvm::raw_string_ostream dumpBufOS(dumpBuf); |
|
||||||
|
|
||||||
cfg->print(dumpBufOS, astContext.getLangOpts(), false); |
|
||||||
auto dumped = dumpBufOS.str(); |
|
||||||
return dumped; |
|
||||||
} |
|
||||||
catch (std::exception &e) |
|
||||||
{ |
|
||||||
return std::string("<Error: ") + e.what() + ">"; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
GenericAstNode::GenericAstNode() : |
|
||||||
myParent(nullptr), hasDetails(false) |
|
||||||
{ |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
int GenericAstNode::findChildIndex(GenericAstNode *node) |
|
||||||
{ |
|
||||||
auto it = std::find_if(myChidren.begin(), myChidren.end(), [node](std::unique_ptr<GenericAstNode> const & n){return n.get() == node; }); |
|
||||||
return it == myChidren.end() ? |
|
||||||
-1 : |
|
||||||
it - myChidren.begin(); |
|
||||||
} |
|
||||||
|
|
||||||
void GenericAstNode::attach(std::unique_ptr<GenericAstNode> child) |
|
||||||
{ |
|
||||||
child->myParent = this; |
|
||||||
myChidren.push_back(std::move(child)); |
|
||||||
} |
|
||||||
|
|
||||||
//struct SourceRangeVisitor : boost::static_visitor<SourceRange>
|
|
||||||
//{
|
|
||||||
// template<class T>
|
|
||||||
// SourceRange operator()(T const *t) const
|
|
||||||
// {
|
|
||||||
// if (t == nullptr)
|
|
||||||
// return SourceRange();
|
|
||||||
// return t->getSourceRange();
|
|
||||||
// }
|
|
||||||
//};
|
|
||||||
|
|
||||||
SourceRange GenericAstNode::getRange() |
|
||||||
{ |
|
||||||
//return boost::apply_visitor(SourceRangeVisitor(), myAstNode);
|
|
||||||
return SourceRange(); |
|
||||||
} |
|
||||||
|
|
||||||
bool GenericAstNode::getRangeInMainFile(std::pair<int, int> &result, clang::SourceManager const &manager, clang::ASTContext &context) |
|
||||||
{ |
|
||||||
auto range = getRange(); |
|
||||||
if (range.isInvalid()) |
|
||||||
{ |
|
||||||
return false; |
|
||||||
} |
|
||||||
auto start = manager.getDecomposedSpellingLoc(range.getBegin()); |
|
||||||
auto end = manager.getDecomposedSpellingLoc(clang::Lexer::getLocForEndOfToken(range.getEnd(), 0, manager, context.getLangOpts())); |
|
||||||
if (start.first != end.first || start.first != manager.getMainFileID()) |
|
||||||
{ |
|
||||||
//Not in the same file, or not in the main file (probably #included)
|
|
||||||
return false; |
|
||||||
} |
|
||||||
result = std::make_pair(start.second, end.second); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
//struct NodeColorVisitor : boost::static_visitor<int>
|
|
||||||
//{
|
|
||||||
// int operator()(Decl const *) const
|
|
||||||
// {
|
|
||||||
// return 0;
|
|
||||||
// }
|
|
||||||
// int operator()(Stmt const *) const
|
|
||||||
// {
|
|
||||||
// return 1;
|
|
||||||
// }
|
|
||||||
//};
|
|
||||||
|
|
||||||
int GenericAstNode::getColor() |
|
||||||
{ |
|
||||||
//return boost::apply_visitor(NodeColorVisitor(), myAstNode);
|
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
void GenericAstNode::setProperty(std::string const &propertyName, std::string const &value) |
|
||||||
{ |
|
||||||
myProperties[propertyName] = value; |
|
||||||
} |
|
||||||
|
|
||||||
GenericAstNode::Properties const &GenericAstNode::getProperties() const |
|
||||||
{ |
|
||||||
return myProperties; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class AstDumpVisitor : public RecursiveASTVisitor<AstDumpVisitor> |
|
||||||
{ |
|
||||||
public: |
|
||||||
using PARENT = clang::RecursiveASTVisitor<AstDumpVisitor>; |
|
||||||
AstDumpVisitor(clang::ASTContext &context, GenericAstNode *rootNode) : |
|
||||||
myRootNode(rootNode), |
|
||||||
myAstContext(context) |
|
||||||
{ |
|
||||||
myStack.push_back(myRootNode); |
|
||||||
} |
|
||||||
|
|
||||||
bool shouldVisitTemplateInstantiations() const |
|
||||||
{ |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
bool shouldVisitImplicitCode() const |
|
||||||
{ |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
std::string getMangling(clang::NamedDecl const *ND) |
|
||||||
{ |
|
||||||
if (auto funcContext = dyn_cast<FunctionDecl>(ND->getDeclContext())) |
|
||||||
{ |
|
||||||
if (funcContext->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) |
|
||||||
{ |
|
||||||
return "<Cannot mangle template name>"; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
std::vector<TagDecl const *> containers; |
|
||||||
auto currentElement = dyn_cast<TagDecl>(ND->getDeclContext()); |
|
||||||
while (currentElement) |
|
||||||
{ |
|
||||||
containers.push_back(currentElement); |
|
||||||
currentElement = dyn_cast<TagDecl>(currentElement->getDeclContext()); |
|
||||||
} |
|
||||||
for (auto tag : containers) |
|
||||||
{ |
|
||||||
if (auto partialSpe = dyn_cast<ClassTemplatePartialSpecializationDecl>(tag)) |
|
||||||
{ |
|
||||||
return "<Inside partial specialization " + tag->getNameAsString() + ": " + ND->getNameAsString() + ">"; |
|
||||||
} |
|
||||||
else if (auto recContext = dyn_cast<CXXRecordDecl>(tag)) |
|
||||||
{ |
|
||||||
if (recContext->getDescribedClassTemplate() != nullptr) |
|
||||||
{ |
|
||||||
return "<Inside a template" + tag->getNameAsString() + ": " + ND->getNameAsString() + ">"; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
auto mangleContext = std::unique_ptr<clang::MangleContext>{ND->getASTContext().createMangleContext()}; |
|
||||||
std::string FrontendBuf; |
|
||||||
llvm::raw_string_ostream FrontendBufOS(FrontendBuf); |
|
||||||
|
|
||||||
if (auto ctor = dyn_cast<CXXConstructorDecl>(ND)) |
|
||||||
{ |
|
||||||
mangleContext->mangleCXXCtor(ctor, CXXCtorType::Ctor_Complete, FrontendBufOS); |
|
||||||
} |
|
||||||
else if (auto dtor = dyn_cast<CXXDestructorDecl>(ND)) |
|
||||||
{ |
|
||||||
mangleContext->mangleCXXDtor(dtor, CXXDtorType::Dtor_Complete, FrontendBufOS); |
|
||||||
} |
|
||||||
else if (mangleContext->shouldMangleDeclName(ND) && !isa<ParmVarDecl>(ND)) |
|
||||||
{ |
|
||||||
mangleContext->mangleName(ND, FrontendBufOS); |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
return ND->getNameAsString(); |
|
||||||
} |
|
||||||
return FrontendBufOS.str(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
bool TraverseDecl(clang::Decl *decl) |
|
||||||
{ |
|
||||||
if (decl == nullptr) |
|
||||||
{ |
|
||||||
return PARENT::TraverseDecl(decl); |
|
||||||
} |
|
||||||
auto node = std::make_unique<GenericAstNode>(); |
|
||||||
node->myAstNode = decl; |
|
||||||
node->name = decl->getDeclKindName() + std::string("Decl"); // Try to mimick clang default dump
|
|
||||||
if (auto *FD = dyn_cast<FunctionDecl>(decl)) |
|
||||||
{ |
|
||||||
#ifndef NDEBUG |
|
||||||
auto &mngr = FD->getASTContext().getSourceManager(); |
|
||||||
auto fileName = mngr.getFilename(FD->getLocation()).str(); |
|
||||||
bool invalid; |
|
||||||
auto startingLine = mngr.getExpansionLineNumber(FD->getLocation(), &invalid); |
|
||||||
|
|
||||||
std::string FrontendBuf; |
|
||||||
llvm::raw_string_ostream FrontendBufOS(FrontendBuf); |
|
||||||
clang::PrintingPolicy policyForDebug(FD->getASTContext().getLangOpts()); |
|
||||||
FD->getNameForDiagnostic(FrontendBufOS, policyForDebug, true); |
|
||||||
auto debugName = FrontendBufOS.str(); |
|
||||||
|
|
||||||
RecordDecl const*containingClass = nullptr; |
|
||||||
if (FD->isCXXClassMember()) |
|
||||||
{ |
|
||||||
auto methodDecl = cast<CXXMethodDecl>(FD); |
|
||||||
containingClass = cast<RecordDecl>(methodDecl->getDeclContext()); |
|
||||||
} |
|
||||||
#endif |
|
||||||
|
|
||||||
node->name += " " + clang_utilities::getFunctionPrototype(FD, false); |
|
||||||
if (FD->getTemplatedKind() != FunctionDecl::TK_FunctionTemplate) |
|
||||||
{ |
|
||||||
node->setProperty(props::Mangling, getMangling(FD)); |
|
||||||
} |
|
||||||
node->setProperty(props::Name, clang_utilities::getFunctionPrototype(FD, true)); |
|
||||||
if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) |
|
||||||
{ |
|
||||||
node->setProperty(props::IsGenerated, MD->isUserProvided() ? "False" : "True"); |
|
||||||
|
|
||||||
} |
|
||||||
node->hasDetails = true; |
|
||||||
node->detailsTitle = "Control flow graph"; |
|
||||||
node->detailsComputer = [FD]() {return getCFG(FD); }; |
|
||||||
} |
|
||||||
else if (auto *PVD = dyn_cast<ParmVarDecl>(decl)) |
|
||||||
{ |
|
||||||
if (auto *PFD = dyn_cast_or_null<FunctionDecl>(decl->getParentFunctionOrMethod())) |
|
||||||
{ |
|
||||||
if (PFD->getTemplatedKind() != FunctionDecl::TK_FunctionTemplate) |
|
||||||
{ |
|
||||||
node->setProperty(props::Mangling, getMangling(PFD)); |
|
||||||
} |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
node->setProperty(props::Mangling, getMangling(PVD)); |
|
||||||
} |
|
||||||
node->setProperty(props::Name, PVD->getNameAsString()); |
|
||||||
} |
|
||||||
else if (auto *VD = dyn_cast<VarDecl>(decl)) |
|
||||||
{ |
|
||||||
//node->setProperty(props::Mangling, getMangling(VD));
|
|
||||||
node->setProperty(props::Name, VD->getNameAsString()); |
|
||||||
node->setProperty(props::Type, clang_utilities::getTypeName(VD->getType(), true)); |
|
||||||
} |
|
||||||
else if (auto *ECD = dyn_cast<EnumConstantDecl>(decl)) |
|
||||||
{ |
|
||||||
node->setProperty(props::Name, ECD->getNameAsString()); |
|
||||||
node->setProperty(props::Value, ECD->getInitVal().toString(10)); |
|
||||||
} |
|
||||||
else if (auto *tag = dyn_cast<TagDecl>(decl)) |
|
||||||
{ |
|
||||||
std::string nameBuf; |
|
||||||
llvm::raw_string_ostream os(nameBuf); |
|
||||||
|
|
||||||
if (TypedefNameDecl *Typedef = tag->getTypedefNameForAnonDecl()) |
|
||||||
os << Typedef->getIdentifier()->getName(); |
|
||||||
else if (tag->getIdentifier()) |
|
||||||
os << tag->getIdentifier()->getName(); |
|
||||||
else |
|
||||||
os << "No name"; |
|
||||||
|
|
||||||
if (auto templateInstance = dyn_cast<ClassTemplateSpecializationDecl>(tag)) |
|
||||||
{ |
|
||||||
clang::PrintingPolicy policy(templateInstance->getASTContext().getLangOpts()); |
|
||||||
clang_utilities::printTemplateArguments(os, policy, &templateInstance->getTemplateArgs(), false); |
|
||||||
} |
|
||||||
node->name += " " + tag->getNameAsString(); |
|
||||||
node->setProperty(props::Name, os.str()); |
|
||||||
} |
|
||||||
else if (auto *ND = dyn_cast<NamedDecl>(decl)) |
|
||||||
{ |
|
||||||
|
|
||||||
|
|
||||||
node->name += " " + ND->getNameAsString(); |
|
||||||
node->setProperty(props::Name, ND->getNameAsString()); |
|
||||||
} |
|
||||||
|
|
||||||
auto nodePtr = node.get(); |
|
||||||
myStack.back()->attach(std::move(node)); |
|
||||||
myStack.push_back(nodePtr); |
|
||||||
auto res = PARENT::TraverseDecl(decl); |
|
||||||
myStack.pop_back(); |
|
||||||
return res; |
|
||||||
} |
|
||||||
|
|
||||||
bool TraverseStmt(clang::Stmt *stmt) |
|
||||||
{ |
|
||||||
if (stmt == nullptr) |
|
||||||
{ |
|
||||||
return PARENT::TraverseStmt(stmt); |
|
||||||
} |
|
||||||
auto node = std::make_unique<GenericAstNode>(); |
|
||||||
node->myAstNode = stmt; |
|
||||||
node->name = stmt->getStmtClassName(); |
|
||||||
auto nodePtr = node.get(); |
|
||||||
myStack.back()->attach(std::move(node)); |
|
||||||
myStack.push_back(nodePtr); |
|
||||||
auto res = PARENT::TraverseStmt(stmt); |
|
||||||
myStack.pop_back(); |
|
||||||
return res; |
|
||||||
} |
|
||||||
|
|
||||||
bool VisitStringLiteral(clang::StringLiteral *s) |
|
||||||
{ |
|
||||||
myStack.back()->name += (" " + s->getBytes()).str(); |
|
||||||
myStack.back()->setProperty(props::InterpretedValue, s->getBytes()); |
|
||||||
auto parts = clang_utilities::splitStringLiteral(s, myAstContext.getSourceManager(), myAstContext.getLangOpts(), myAstContext.getTargetInfo()); |
|
||||||
if (parts.size() == 1) |
|
||||||
{ |
|
||||||
myStack.back()->setProperty(props::Value, parts[0]); |
|
||||||
|
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
int i = 0; |
|
||||||
for (auto &part : parts) |
|
||||||
{ |
|
||||||
++i; |
|
||||||
myStack.back()->setProperty(props::Value + " " + std::to_string(i), part); |
|
||||||
|
|
||||||
} |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
bool VisitIntegerLiteral(clang::IntegerLiteral *i) |
|
||||||
{ |
|
||||||
bool isSigned = i->getType()->isSignedIntegerType(); |
|
||||||
myStack.back()->setProperty(props::Value, i->getValue().toString(10, isSigned)); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
bool VisitCharacterLiteral(clang::CharacterLiteral *c) |
|
||||||
{ |
|
||||||
myStack.back()->setProperty(props::Value, std::string(1, c->getValue())); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
bool VisitFloatingLiteral(clang::FloatingLiteral *f) |
|
||||||
{ |
|
||||||
myStack.back()->setProperty(props::Value, std::to_string(f->getValueAsApproximateDouble())); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
bool VisitCXXRecordDecl(clang::CXXRecordDecl *r) |
|
||||||
{ |
|
||||||
myStack.back()->setProperty(props::IsTemplateDecl, std::to_string(r->getDescribedClassTemplate() != nullptr)); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
void addReference(GenericAstNode *node, clang::NamedDecl *referenced, std::string const &label) |
|
||||||
{ |
|
||||||
auto funcDecl = dyn_cast<FunctionDecl>(referenced); |
|
||||||
myStack.back()->setProperty(label, funcDecl == nullptr ? |
|
||||||
referenced->getNameAsString() : |
|
||||||
clang_utilities::getFunctionPrototype(funcDecl, false)); |
|
||||||
} |
|
||||||
|
|
||||||
bool VisitDeclRefExpr(clang::DeclRefExpr *ref) |
|
||||||
{ |
|
||||||
addReference(myStack.back(), ref->getDecl(), props::Referenced); |
|
||||||
addReference(myStack.back(), ref->getFoundDecl(), props::Resolved); |
|
||||||
|
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
bool TraverseType(clang::QualType type) |
|
||||||
{ |
|
||||||
if (type.isNull()) |
|
||||||
{ |
|
||||||
return PARENT::TraverseType(type); |
|
||||||
} |
|
||||||
auto node = std::make_unique<GenericAstNode>(); |
|
||||||
//node->myType = d;
|
|
||||||
node->name = type->getTypeClassName(); |
|
||||||
auto nodePtr = node.get(); |
|
||||||
myStack.back()->attach(std::move(node)); |
|
||||||
myStack.push_back(nodePtr); |
|
||||||
auto res = PARENT::TraverseType(type); |
|
||||||
myStack.pop_back(); |
|
||||||
return res; |
|
||||||
} |
|
||||||
|
|
||||||
private: |
|
||||||
std::vector<GenericAstNode*> myStack; |
|
||||||
GenericAstNode *myRootNode; |
|
||||||
ASTContext &myAstContext; |
|
||||||
}; |
|
||||||
|
|
||||||
|
|
||||||
AstReader::AstReader() : isReady(false) |
|
||||||
{ |
|
||||||
} |
|
||||||
|
|
||||||
clang::SourceManager &AstReader::getManager() |
|
||||||
{ |
|
||||||
return myAst->getSourceManager(); |
|
||||||
} |
|
||||||
|
|
||||||
clang::ASTContext &AstReader::getContext() |
|
||||||
{ |
|
||||||
return myAst->getASTContext(); |
|
||||||
} |
|
||||||
|
|
||||||
GenericAstNode *AstReader::getRealRoot() |
|
||||||
{ |
|
||||||
return myArtificialRoot->myChidren.front().get(); |
|
||||||
} |
|
||||||
|
|
||||||
GenericAstNode *AstReader::findPosInChildren(std::vector<std::unique_ptr<GenericAstNode>> const &candidates, int position) |
|
||||||
{ |
|
||||||
for (auto &candidate : candidates) |
|
||||||
{ |
|
||||||
std::pair<int, int> location; |
|
||||||
if (!candidate->getRangeInMainFile(location, getManager(), getContext())) |
|
||||||
{ |
|
||||||
continue; |
|
||||||
} |
|
||||||
if (location.first <= position && position <= location.second) |
|
||||||
{ |
|
||||||
return candidate.get(); |
|
||||||
} |
|
||||||
} |
|
||||||
return nullptr; |
|
||||||
} |
|
||||||
|
|
||||||
std::vector<GenericAstNode *> AstReader::getBestNodeMatchingPosition(int position) |
|
||||||
{ |
|
||||||
std::vector<GenericAstNode *> result; |
|
||||||
auto currentNode = getRealRoot(); |
|
||||||
result.push_back(currentNode); |
|
||||||
currentNode = currentNode->myChidren[0].get(); |
|
||||||
result.push_back(currentNode); // Translation unit does not have position
|
|
||||||
while (true) |
|
||||||
{ |
|
||||||
auto bestChild = findPosInChildren(currentNode->myChidren, position); |
|
||||||
if (bestChild == nullptr) |
|
||||||
{ |
|
||||||
return result; |
|
||||||
} |
|
||||||
result.push_back(bestChild); |
|
||||||
currentNode = bestChild; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
GenericAstNode *AstReader::readAst(std::string const &sourceCode, std::string const &options) |
|
||||||
{ |
|
||||||
mySourceCode = sourceCode; |
|
||||||
myArtificialRoot = std::make_unique<GenericAstNode>(); |
|
||||||
auto root = std::make_unique<GenericAstNode>(); |
|
||||||
root->name = "AST"; |
|
||||||
myArtificialRoot->attach(std::move(root)); |
|
||||||
|
|
||||||
auto args = splitCommandLine(options); |
|
||||||
|
|
||||||
std::cout << "Launching Clang to create AST" << std::endl; |
|
||||||
//myAst = clang::tooling::buildASTFromCodeWithArgs(mySourceCode, args);
|
|
||||||
myAst = nullptr; |
|
||||||
if (myAst != nullptr) |
|
||||||
{ |
|
||||||
for (auto it = myAst->top_level_begin(); it != myAst->top_level_end(); ++it) |
|
||||||
{ |
|
||||||
//(*it)->dumpColor();
|
|
||||||
} |
|
||||||
std::cout << "Visiting AST and creating Qt Tree" << std::endl; |
|
||||||
auto visitor = AstDumpVisitor{ myAst->getASTContext(), getRealRoot() }; |
|
||||||
visitor.TraverseDecl(myAst->getASTContext().getTranslationUnitDecl()); |
|
||||||
} |
|
||||||
isReady = true; |
|
||||||
return myArtificialRoot.get(); |
|
||||||
} |
|
||||||
|
|
||||||
bool AstReader::ready() |
|
||||||
{ |
|
||||||
return isReady; |
|
||||||
} |
|
||||||
|
|
||||||
void AstReader::dirty() |
|
||||||
{ |
|
||||||
isReady = false; |
|
||||||
} |
|
||||||
|
|
@ -1,60 +0,0 @@ |
|||||||
#pragma once |
|
||||||
|
|
||||||
#pragma warning (push) |
|
||||||
#pragma warning (disable:4100 4127 4800 4512 4245 4291 4510 4610 4324 4267 4244 4996) |
|
||||||
#include "clang/Frontend/TextDiagnosticBuffer.h" |
|
||||||
#include "clang/Tooling/CommonOptionsParser.h" |
|
||||||
#include "clang/Tooling/Tooling.h" |
|
||||||
#include "llvm/Support/CommandLine.h" |
|
||||||
#include "clang/Basic/SourceLocation.h" |
|
||||||
#pragma warning(pop) |
|
||||||
#include <string> |
|
||||||
#include <variant> |
|
||||||
|
|
||||||
|
|
||||||
class GenericAstNode |
|
||||||
{ |
|
||||||
public: |
|
||||||
GenericAstNode(); |
|
||||||
int findChildIndex(GenericAstNode *node); // Return -1 if not found
|
|
||||||
void attach(std::unique_ptr<GenericAstNode> child); |
|
||||||
std::string name; |
|
||||||
std::vector<std::unique_ptr<GenericAstNode>> myChidren; |
|
||||||
bool getRangeInMainFile(std::pair<int, int> &result, clang::SourceManager const &manager, clang::ASTContext &context); // Return false if the range is not fully in the main file
|
|
||||||
clang::SourceRange getRange(); |
|
||||||
int getColor(); // Will return a color identifier How this is linked to the real color is up to the user
|
|
||||||
using Properties = std::map<std::string, std::string>; |
|
||||||
void setProperty(std::string const &propertyName, std::string const &value); |
|
||||||
Properties const &getProperties() const; |
|
||||||
std::variant<clang::Decl *, clang::Stmt *> myAstNode; |
|
||||||
GenericAstNode *myParent; |
|
||||||
|
|
||||||
bool hasDetails; |
|
||||||
std::string detailsTitle; |
|
||||||
std::string details; |
|
||||||
std::function<std::string()> detailsComputer; |
|
||||||
|
|
||||||
private: |
|
||||||
Properties myProperties; |
|
||||||
}; |
|
||||||
|
|
||||||
class AstReader |
|
||||||
{ |
|
||||||
public: |
|
||||||
AstReader(); |
|
||||||
GenericAstNode *readAst(std::string const &sourceCode, std::string const &options); |
|
||||||
clang::SourceManager &getManager(); |
|
||||||
clang::ASTContext &getContext(); |
|
||||||
GenericAstNode *getRealRoot(); |
|
||||||
std::vector<GenericAstNode *> getBestNodeMatchingPosition(int position); // Return the path from root to the node
|
|
||||||
bool ready(); |
|
||||||
void dirty(); // Ready will be false until the reader is run again
|
|
||||||
private: |
|
||||||
GenericAstNode *findPosInChildren(std::vector<std::unique_ptr<GenericAstNode>> const &candidates, int position); |
|
||||||
std::string args; |
|
||||||
std::string mySourceCode; // Needs to stay alive while we navigate the tree
|
|
||||||
std::unique_ptr<clang::ASTUnit> myAst; |
|
||||||
std::unique_ptr<GenericAstNode> myArtificialRoot; // We need an artificial root on top of the real root, because the root is not displayed by Qt
|
|
||||||
bool isReady; |
|
||||||
}; |
|
||||||
|
|
@ -1,304 +0,0 @@ |
|||||||
#include "StringLiteralExtractor.h" |
|
||||||
|
|
||||||
#pragma warning (push) |
|
||||||
#pragma warning (disable:4100 4127 4800 4512 4245 4291 4510 4610 4324 4267 4244 4996 4146) |
|
||||||
#include <clang/AST/Expr.h> |
|
||||||
#include <clang/Lex/Lexer.h> |
|
||||||
#include <clang/Lex/LiteralSupport.h> |
|
||||||
#include <clang/Frontend/FrontendActions.h> |
|
||||||
#include <clang/Basic/SourceLocation.h> |
|
||||||
#include <clang/Basic/TargetInfo.h> |
|
||||||
#include <clang/Basic/CharInfo.h> |
|
||||||
#include <llvm/ADT/StringExtras.h> |
|
||||||
#include <llvm/Support/ConvertUTF.h> |
|
||||||
#pragma warning (pop) |
|
||||||
|
|
||||||
using namespace llvm; |
|
||||||
using namespace clang; |
|
||||||
|
|
||||||
namespace clang_utilities { |
|
||||||
|
|
||||||
// This function is an direct adaptation from ProcessCharEscape in llvm-3.7.1\src\tools\clang\lib\Lex\LiteralSupport.cpp (just removed the diag part)
|
|
||||||
unsigned ProcessCharEscape(const char *ThisTokBegin, |
|
||||||
const char *&ThisTokBuf, |
|
||||||
const char *ThisTokEnd, bool &HadError, |
|
||||||
FullSourceLoc Loc, unsigned CharWidth, |
|
||||||
const LangOptions &Features) |
|
||||||
{ |
|
||||||
// Skip the '\' char.
|
|
||||||
++ThisTokBuf; |
|
||||||
|
|
||||||
// We know that this character can't be off the end of the buffer, because
|
|
||||||
// that would have been \", which would not have been the end of string.
|
|
||||||
unsigned ResultChar = *ThisTokBuf++; |
|
||||||
switch (ResultChar) { |
|
||||||
// These map to themselves.
|
|
||||||
case '\\': case '\'': case '"': case '?': break; |
|
||||||
|
|
||||||
// These have fixed mappings.
|
|
||||||
case 'a': |
|
||||||
// TODO: K&R: the meaning of '\\a' is different in traditional C
|
|
||||||
ResultChar = 7; |
|
||||||
break; |
|
||||||
case 'b': |
|
||||||
ResultChar = 8; |
|
||||||
break; |
|
||||||
case 'e': |
|
||||||
ResultChar = 27; |
|
||||||
break; |
|
||||||
case 'E': |
|
||||||
ResultChar = 27; |
|
||||||
break; |
|
||||||
case 'f': |
|
||||||
ResultChar = 12; |
|
||||||
break; |
|
||||||
case 'n': |
|
||||||
ResultChar = 10; |
|
||||||
break; |
|
||||||
case 'r': |
|
||||||
ResultChar = 13; |
|
||||||
break; |
|
||||||
case 't': |
|
||||||
ResultChar = 9; |
|
||||||
break; |
|
||||||
case 'v': |
|
||||||
ResultChar = 11; |
|
||||||
break; |
|
||||||
case 'x': { // Hex escape.
|
|
||||||
ResultChar = 0; |
|
||||||
if (ThisTokBuf == ThisTokEnd || !isHexDigit(*ThisTokBuf)) { |
|
||||||
HadError = 1; |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
// Hex escapes are a maximal series of hex digits.
|
|
||||||
bool Overflow = false; |
|
||||||
for (; ThisTokBuf != ThisTokEnd; ++ThisTokBuf) { |
|
||||||
int CharVal = llvm::hexDigitValue(ThisTokBuf[0]); |
|
||||||
if (CharVal == -1) break; |
|
||||||
// About to shift out a digit?
|
|
||||||
if (ResultChar & 0xF0000000) |
|
||||||
Overflow = true; |
|
||||||
ResultChar <<= 4; |
|
||||||
ResultChar |= CharVal; |
|
||||||
} |
|
||||||
|
|
||||||
// See if any bits will be truncated when evaluated as a character.
|
|
||||||
if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) { |
|
||||||
Overflow = true; |
|
||||||
ResultChar &= ~0U >> (32 - CharWidth); |
|
||||||
} |
|
||||||
|
|
||||||
// Check for overflow.
|
|
||||||
break; |
|
||||||
} |
|
||||||
case '0': case '1': case '2': case '3': |
|
||||||
case '4': case '5': case '6': case '7': { |
|
||||||
// Octal escapes.
|
|
||||||
--ThisTokBuf; |
|
||||||
ResultChar = 0; |
|
||||||
|
|
||||||
// Octal escapes are a series of octal digits with maximum length 3.
|
|
||||||
// "\0123" is a two digit sequence equal to "\012" "3".
|
|
||||||
unsigned NumDigits = 0; |
|
||||||
do { |
|
||||||
ResultChar <<= 3; |
|
||||||
ResultChar |= *ThisTokBuf++ - '0'; |
|
||||||
++NumDigits; |
|
||||||
} while (ThisTokBuf != ThisTokEnd && NumDigits < 3 && |
|
||||||
ThisTokBuf[0] >= '0' && ThisTokBuf[0] <= '7'); |
|
||||||
|
|
||||||
// Check for overflow. Reject '\777', but not L'\777'.
|
|
||||||
if (CharWidth != 32 && (ResultChar >> CharWidth) != 0) { |
|
||||||
ResultChar &= ~0U >> (32 - CharWidth); |
|
||||||
} |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
// Otherwise, these are not valid escapes.
|
|
||||||
case '(': case '{': case '[': case '%': |
|
||||||
// GCC accepts these as extensions. We warn about them as such though.
|
|
||||||
break; |
|
||||||
default: |
|
||||||
break; |
|
||||||
} |
|
||||||
return ResultChar; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// This function is an direct adaptation from ProcessUCNEscape in llvm-3.7.1\src\tools\clang\lib\Lex\LiteralSupport.cpp (just removed the diag part)
|
|
||||||
bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, |
|
||||||
const char *ThisTokEnd, |
|
||||||
uint32_t &UcnVal, unsigned short &UcnLen, |
|
||||||
FullSourceLoc Loc, |
|
||||||
const LangOptions &Features, |
|
||||||
bool in_char_string_literal) { |
|
||||||
const char *UcnBegin = ThisTokBuf; |
|
||||||
|
|
||||||
// Skip the '\u' char's.
|
|
||||||
ThisTokBuf += 2; |
|
||||||
|
|
||||||
if (ThisTokBuf == ThisTokEnd || !isHexDigit(*ThisTokBuf)) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
UcnLen = (ThisTokBuf[-1] == 'u' ? 4 : 8); |
|
||||||
unsigned short UcnLenSave = UcnLen; |
|
||||||
for (; ThisTokBuf != ThisTokEnd && UcnLenSave; ++ThisTokBuf, UcnLenSave--) { |
|
||||||
int CharVal = llvm::hexDigitValue(ThisTokBuf[0]); |
|
||||||
if (CharVal == -1) break; |
|
||||||
UcnVal <<= 4; |
|
||||||
UcnVal |= CharVal; |
|
||||||
} |
|
||||||
// If we didn't consume the proper number of digits, there is a problem.
|
|
||||||
if (UcnLenSave) { |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
// Check UCN constraints (C99 6.4.3p2) [C++11 lex.charset p2]
|
|
||||||
if ((0xD800 <= UcnVal && UcnVal <= 0xDFFF) || // surrogate codepoints
|
|
||||||
UcnVal > 0x10FFFF) { // maximum legal UTF32 value
|
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
// C++11 allows UCNs that refer to control characters and basic source
|
|
||||||
// characters inside character and string literals
|
|
||||||
if (UcnVal < 0xa0 && |
|
||||||
(UcnVal != 0x24 && UcnVal != 0x40 && UcnVal != 0x60)) { // $, @, `
|
|
||||||
bool IsError = (!Features.CPlusPlus11 || !in_char_string_literal); |
|
||||||
if (IsError) |
|
||||||
return false; |
|
||||||
} |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
// This function is an direct adaptation from ProcessUCNEscape in llvm-3.7.1\src\tools\clang\lib\Lex\LiteralSupport.cpp (just removed the diag part)
|
|
||||||
int MeasureUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, |
|
||||||
const char *ThisTokEnd, unsigned CharByteWidth, |
|
||||||
const LangOptions &Features, bool &HadError) { |
|
||||||
// UTF-32: 4 bytes per escape.
|
|
||||||
if (CharByteWidth == 4) |
|
||||||
return 4; |
|
||||||
|
|
||||||
uint32_t UcnVal = 0; |
|
||||||
unsigned short UcnLen = 0; |
|
||||||
FullSourceLoc Loc; |
|
||||||
|
|
||||||
if (!ProcessUCNEscape(ThisTokBegin, ThisTokBuf, ThisTokEnd, UcnVal, |
|
||||||
UcnLen, Loc, Features, true)) { |
|
||||||
HadError = true; |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
// UTF-16: 2 bytes for BMP, 4 bytes otherwise.
|
|
||||||
if (CharByteWidth == 2) |
|
||||||
return UcnVal <= 0xFFFF ? 2 : 4; |
|
||||||
|
|
||||||
// UTF-8.
|
|
||||||
if (UcnVal < 0x80) |
|
||||||
return 1; |
|
||||||
if (UcnVal < 0x800) |
|
||||||
return 2; |
|
||||||
if (UcnVal < 0x10000) |
|
||||||
return 3; |
|
||||||
return 4; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// This function is just the same as convertUTF16ToUTF8String, but adapted to UTF32, since it did not exist in clang
|
|
||||||
bool convertUTF32ToUTF8String(ArrayRef<char> SrcBytes, std::string &Out) { |
|
||||||
assert(Out.empty()); |
|
||||||
|
|
||||||
// Error out on an uneven byte count.
|
|
||||||
if (SrcBytes.size() % 4) |
|
||||||
return false; |
|
||||||
|
|
||||||
// Avoid OOB by returning early on empty input.
|
|
||||||
if (SrcBytes.empty()) |
|
||||||
return true; |
|
||||||
|
|
||||||
const UTF32 *Src = reinterpret_cast<const UTF32 *>(SrcBytes.begin()); |
|
||||||
const UTF32 *SrcEnd = reinterpret_cast<const UTF32 *>(SrcBytes.end()); |
|
||||||
|
|
||||||
// Byteswap if necessary.
|
|
||||||
// Ignore any potential BOM: We won't have the here...
|
|
||||||
|
|
||||||
// Just allocate enough space up front. We'll shrink it later. Allocate
|
|
||||||
// enough that we can fit a null terminator without reallocating.
|
|
||||||
Out.resize(SrcBytes.size() * UNI_MAX_UTF8_BYTES_PER_CODE_POINT + 1); |
|
||||||
UTF8 *Dst = reinterpret_cast<UTF8 *>(&Out[0]); |
|
||||||
UTF8 *DstEnd = Dst + Out.size(); |
|
||||||
|
|
||||||
ConversionResult CR = |
|
||||||
ConvertUTF32toUTF8(&Src, SrcEnd, &Dst, DstEnd, strictConversion); |
|
||||||
assert(CR != targetExhausted); |
|
||||||
|
|
||||||
if (CR != conversionOK) { |
|
||||||
Out.clear(); |
|
||||||
return false; |
|
||||||
} |
|
||||||
|
|
||||||
Out.resize(reinterpret_cast<char *>(Dst)-&Out[0]); |
|
||||||
Out.push_back(0); |
|
||||||
Out.pop_back(); |
|
||||||
return true; |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
// This function is an adaptation from StringLiteral::getLocationOfByte in llvm-3.7.1\src\tools\clang\lib\AST\Expr.cpp
|
|
||||||
std::vector<std::string> |
|
||||||
splitStringLiteral(clang::StringLiteral *S, const SourceManager &SM, const LangOptions &Features, const TargetInfo &Target) |
|
||||||
{ |
|
||||||
// Loop over all of the tokens in this string until we find the one that
|
|
||||||
// contains the byte we're looking for.
|
|
||||||
unsigned TokNo = 0; |
|
||||||
|
|
||||||
std::vector<std::string> result; |
|
||||||
for (TokNo = 0; TokNo < S->getNumConcatenated(); ++TokNo) |
|
||||||
{ |
|
||||||
SourceLocation StrTokLoc = S->getStrTokenLoc(TokNo); |
|
||||||
|
|
||||||
// Get the spelling of the string so that we can get the data that makes up
|
|
||||||
// the string literal, not the identifier for the macro it is potentially
|
|
||||||
// expanded through.
|
|
||||||
SourceLocation StrTokSpellingLoc = SM.getSpellingLoc(StrTokLoc); |
|
||||||
|
|
||||||
// Re-lex the token to get its length and original spelling.
|
|
||||||
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(StrTokSpellingLoc); |
|
||||||
bool Invalid = false; |
|
||||||
StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); |
|
||||||
if (Invalid) |
|
||||||
continue; // We ignore this part
|
|
||||||
|
|
||||||
const char *StrData = Buffer.data() + LocInfo.second; |
|
||||||
|
|
||||||
// Create a lexer starting at the beginning of this token.
|
|
||||||
Lexer TheLexer(SM.getLocForStartOfFile(LocInfo.first), Features, |
|
||||||
Buffer.begin(), StrData, Buffer.end()); |
|
||||||
Token TheTok; |
|
||||||
TheLexer.LexFromRawLexer(TheTok); |
|
||||||
if (TheTok.isAnyIdentifier()) |
|
||||||
{ |
|
||||||
// It should not be, since we are parsing inside a string literal, but it can happen with special macros such as __func__
|
|
||||||
// of __PRETTY_FUNCTION__ that are not resolved at this time. In that case, we just ignore them...
|
|
||||||
continue; |
|
||||||
} |
|
||||||
// Get the spelling of the token.
|
|
||||||
SmallString<32> SpellingBuffer; |
|
||||||
SpellingBuffer.resize(TheTok.getLength()); |
|
||||||
|
|
||||||
bool StringInvalid = false; |
|
||||||
const char *SpellingPtr = &SpellingBuffer[0]; |
|
||||||
unsigned TokLen = Lexer::getSpelling(TheTok, SpellingPtr, SM, Features, &StringInvalid); |
|
||||||
if (StringInvalid) |
|
||||||
continue; |
|
||||||
|
|
||||||
const char *SpellingStart = SpellingPtr; |
|
||||||
const char *SpellingEnd = SpellingPtr + TokLen; |
|
||||||
result.push_back(std::string(SpellingStart, SpellingEnd)); |
|
||||||
|
|
||||||
} |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
} // namespace clang_utilities
|
|
@ -1,46 +0,0 @@ |
|||||||
#pragma once |
|
||||||
|
|
||||||
#include <vector> |
|
||||||
#include <string> |
|
||||||
#pragma warning (push) |
|
||||||
#pragma warning (disable:4100 4127 4800 4512 4245 4291 4510 4610 4324 4267 4244 4996 4146) |
|
||||||
#include <clang/AST/Decl.h> |
|
||||||
#include <clang/Lex/Lexer.h> |
|
||||||
#include <clang/Frontend/FrontendActions.h> |
|
||||||
#include <llvm/ADT/ArrayRef.h> |
|
||||||
#include <clang/Basic/LangOptions.h> |
|
||||||
#pragma warning (pop) |
|
||||||
|
|
||||||
|
|
||||||
namespace clang_utilities { |
|
||||||
|
|
||||||
// This function is an direct adaptation from ProcessCharEscape in llvm-3.7.1\src\tools\clang\lib\Lex\LiteralSupport.cpp (just removed the diag part)
|
|
||||||
unsigned ProcessCharEscape(const char *ThisTokBegin, |
|
||||||
const char *&ThisTokBuf, |
|
||||||
const char *ThisTokEnd, bool &HadError, |
|
||||||
clang::FullSourceLoc Loc, unsigned CharWidth, |
|
||||||
const clang::LangOptions &Features); |
|
||||||
|
|
||||||
// This function is an direct adaptation from ProcessUCNEscape in llvm-3.7.1\src\tools\clang\lib\Lex\LiteralSupport.cpp (just removed the diag part)
|
|
||||||
bool ProcessUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, |
|
||||||
const char *ThisTokEnd, |
|
||||||
uint32_t &UcnVal, unsigned short &UcnLen, |
|
||||||
clang::FullSourceLoc Loc, |
|
||||||
const clang::LangOptions &Features, |
|
||||||
bool in_char_string_literal = false); |
|
||||||
|
|
||||||
|
|
||||||
// This function is an direct adaptation from ProcessUCNEscape in llvm-3.7.1\src\tools\clang\lib\Lex\LiteralSupport.cpp (just removed the diag part)
|
|
||||||
int MeasureUCNEscape(const char *ThisTokBegin, const char *&ThisTokBuf, |
|
||||||
const char *ThisTokEnd, unsigned CharByteWidth, |
|
||||||
const clang::LangOptions &Features, bool &HadError); |
|
||||||
|
|
||||||
|
|
||||||
bool convertUTF32ToUTF8String(llvm::ArrayRef<char> SrcBytes, std::string &Out); |
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::string> |
|
||||||
splitStringLiteral(clang::StringLiteral *S, const clang::SourceManager &SM, const clang::LangOptions &Features, const clang::TargetInfo &Target); |
|
||||||
|
|
||||||
} // namespace clang_utilities
|
|
||||||
|
|
@ -1,287 +0,0 @@ |
|||||||
#include "TemplateUtilities.h" |
|
||||||
|
|
||||||
#pragma warning (push) |
|
||||||
#pragma warning (disable:4100 4127 4800 4512 4245 4291 4510 4610 4324 4267 4244 4996) |
|
||||||
#include <clang/Tooling/Tooling.h> |
|
||||||
#include <clang/AST/RecursiveASTVisitor.h> |
|
||||||
#include <clang/Frontend/FrontendActions.h> |
|
||||||
#include <clang/AST/Decl.h> |
|
||||||
#include <clang/Lex/Lexer.h> |
|
||||||
#include <clang/Basic/TargetInfo.h> |
|
||||||
#include <clang/Frontend/CompilerInstance.h> |
|
||||||
#include <clang/AST/Mangle.h> |
|
||||||
#pragma warning (pop) |
|
||||||
|
|
||||||
using namespace clang; |
|
||||||
namespace clang_utilities { |
|
||||||
|
|
||||||
|
|
||||||
void printDeclType(raw_ostream &out, PrintingPolicy const &policy, QualType T, StringRef DeclName, bool Pack) { |
|
||||||
// Normally, a PackExpansionType is written as T[3]... (for instance, as a
|
|
||||||
// template argument), but if it is the type of a declaration, the ellipsis
|
|
||||||
// is placed before the name being declared.
|
|
||||||
if (auto *PET = T->getAs<PackExpansionType>()) { |
|
||||||
Pack = true; |
|
||||||
T = PET->getPattern(); |
|
||||||
} |
|
||||||
T.print(out, policy, (Pack ? "..." : "") + DeclName); |
|
||||||
} |
|
||||||
|
|
||||||
void printTemplateParameters(raw_ostream &out, PrintingPolicy const &policy, TemplateParameterList const *params) |
|
||||||
{ |
|
||||||
if (params == nullptr) |
|
||||||
{ |
|
||||||
return; |
|
||||||
} |
|
||||||
|
|
||||||
out << "<"; |
|
||||||
for (unsigned i = 0, e = params->size(); i != e; ++i) { |
|
||||||
if (i != 0) |
|
||||||
out << ", "; |
|
||||||
|
|
||||||
auto param = params->getParam(i); |
|
||||||
printTemplateParameter(out, policy, param); |
|
||||||
} |
|
||||||
out << ">"; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
// Adapted from tools\clang\lib\AST\DeclPrinter.cpp DeclPrinter::PrintTemplateParameters
|
|
||||||
void printTemplateParameter(raw_ostream &out, PrintingPolicy const &policy, NamedDecl const *param) |
|
||||||
{ |
|
||||||
if (const TemplateTypeParmDecl *TTP = |
|
||||||
dyn_cast<TemplateTypeParmDecl>(param)) { |
|
||||||
|
|
||||||
if (TTP->wasDeclaredWithTypename()) |
|
||||||
out << "typename "; |
|
||||||
else |
|
||||||
out << "class "; |
|
||||||
|
|
||||||
if (TTP->isParameterPack()) |
|
||||||
out << "..."; |
|
||||||
|
|
||||||
out << *TTP; |
|
||||||
|
|
||||||
if (TTP->hasDefaultArgument()) { |
|
||||||
out << " = "; |
|
||||||
out << TTP->getDefaultArgument().getAsString(policy); |
|
||||||
}; |
|
||||||
} |
|
||||||
else if (const NonTypeTemplateParmDecl *NTTP = |
|
||||||
dyn_cast<NonTypeTemplateParmDecl>(param)) { |
|
||||||
StringRef Name; |
|
||||||
if (IdentifierInfo *II = NTTP->getIdentifier()) |
|
||||||
Name = II->getName(); |
|
||||||
printDeclType(out, policy, NTTP->getType(), Name, NTTP->isParameterPack()); |
|
||||||
|
|
||||||
if (NTTP->hasDefaultArgument()) { |
|
||||||
out << " = "; |
|
||||||
NTTP->getDefaultArgument()->printPretty(out, nullptr, policy, 0); |
|
||||||
} |
|
||||||
} |
|
||||||
else if (const TemplateTemplateParmDecl *TTPD = |
|
||||||
dyn_cast<TemplateTemplateParmDecl>(param)) { |
|
||||||
out << "template"; |
|
||||||
printTemplateParameters(out, policy, TTPD->getTemplateParameters()); |
|
||||||
out << " class " << TTPD->getNameAsString(); |
|
||||||
//VisitTemplateDecl(TTPD);
|
|
||||||
// FIXME: print the default argument, if present.
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
static void printIntegral(const TemplateArgument &TemplArg, |
|
||||||
raw_ostream &out, const PrintingPolicy& policy) { |
|
||||||
const ::clang::Type *T = TemplArg.getIntegralType().getTypePtr(); |
|
||||||
const llvm::APSInt &Val = TemplArg.getAsIntegral(); |
|
||||||
|
|
||||||
if (const EnumType *ET = T->getAs<EnumType>()) { |
|
||||||
for (const EnumConstantDecl* ECD : ET->getDecl()->enumerators()) { |
|
||||||
// In Sema::CheckTemplateArugment, enum template arguments value are
|
|
||||||
// extended to the size of the integer underlying the enum type. This
|
|
||||||
// may create a size difference between the enum value and template
|
|
||||||
// argument value, requiring isSameValue here instead of operator==.
|
|
||||||
if (llvm::APSInt::isSameValue(ECD->getInitVal(), Val)) { |
|
||||||
ECD->printQualifiedName(out, policy); |
|
||||||
return; |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
if (T->isBooleanType()) { |
|
||||||
out << (Val.getBoolValue() ? "true" : "false"); |
|
||||||
} |
|
||||||
else if (T->isCharType()) { |
|
||||||
const char Ch = Val.getZExtValue(); |
|
||||||
out << ((Ch == '\'') ? "'\\" : "'"); |
|
||||||
out.write_escaped(StringRef(&Ch, 1), /*UseHexEscapes=*/ true); |
|
||||||
out << "'"; |
|
||||||
} |
|
||||||
else { |
|
||||||
out << Val; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void printTemplateName(raw_ostream &OS, const PrintingPolicy &policy, TemplateName const &name, bool qualifyNames = false) |
|
||||||
{ |
|
||||||
if (auto Template = name.getAsTemplateDecl()) |
|
||||||
OS << (qualifyNames ? Template->getQualifiedNameAsString() : Template->getNameAsString()); |
|
||||||
else if (auto QTN = name.getAsQualifiedTemplateName()) { |
|
||||||
OS << (qualifyNames ? QTN->getDecl()->getQualifiedNameAsString() : QTN->getDecl()->getNameAsString()); |
|
||||||
} |
|
||||||
else if (auto DTN = name.getAsDependentTemplateName()) { |
|
||||||
if (qualifyNames && DTN->getQualifier()) |
|
||||||
DTN->getQualifier()->print(OS, policy); |
|
||||||
OS << "template "; |
|
||||||
|
|
||||||
if (DTN->isIdentifier()) |
|
||||||
OS << DTN->getIdentifier()->getName(); |
|
||||||
else |
|
||||||
OS << "operator " << getOperatorSpelling(DTN->getOperator()); |
|
||||||
} |
|
||||||
else if (auto subst = name.getAsSubstTemplateTemplateParm()) { |
|
||||||
subst->getReplacement().print(OS, policy, !qualifyNames); |
|
||||||
} |
|
||||||
else if (auto SubstPack = name.getAsSubstTemplateTemplateParmPack()) |
|
||||||
OS << *SubstPack->getParameterPack(); |
|
||||||
else { |
|
||||||
auto OTS = name.getAsOverloadedTemplate(); |
|
||||||
(*OTS->begin())->printName(OS); |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Adapted from tools\clang\lib\AST\TemplateBase.cpp TemplateArgument::print
|
|
||||||
void printTemplateArgument(raw_ostream &out, const PrintingPolicy &policy, TemplateArgument const &arg, bool qualifyNames) |
|
||||||
{ |
|
||||||
switch (arg.getKind()) { |
|
||||||
case TemplateArgument::Null: |
|
||||||
out << "(no value)"; |
|
||||||
break; |
|
||||||
|
|
||||||
case TemplateArgument::Type: { |
|
||||||
PrintingPolicy SubPolicy(policy); |
|
||||||
SubPolicy.SuppressStrongLifetime = true; |
|
||||||
arg.getAsType().print(out, SubPolicy); |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
case TemplateArgument::Declaration: { |
|
||||||
NamedDecl *ND = cast<NamedDecl>(arg.getAsDecl()); |
|
||||||
out << '&'; |
|
||||||
if (ND->getDeclName()) { |
|
||||||
// FIXME: distinguish between pointer and reference args?
|
|
||||||
ND->printQualifiedName(out); |
|
||||||
} |
|
||||||
else { |
|
||||||
out << "(anonymous)"; |
|
||||||
} |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
case TemplateArgument::NullPtr: |
|
||||||
out << "nullptr"; |
|
||||||
break; |
|
||||||
|
|
||||||
case TemplateArgument::Template: |
|
||||||
// Orig: arg.getAsTemplate().print(out, policy);
|
|
||||||
{ |
|
||||||
auto templateName = arg.getAsTemplate(); |
|
||||||
printTemplateName(out, policy, templateName, qualifyNames); |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
case TemplateArgument::TemplateExpansion: |
|
||||||
arg.getAsTemplateOrTemplatePattern().print(out, policy); |
|
||||||
out << "..."; |
|
||||||
break; |
|
||||||
|
|
||||||
case TemplateArgument::Integral: { |
|
||||||
printIntegral(arg, out, policy); |
|
||||||
break; |
|
||||||
} |
|
||||||
|
|
||||||
case TemplateArgument::Expression: |
|
||||||
arg.getAsExpr()->printPretty(out, nullptr, policy); |
|
||||||
break; |
|
||||||
|
|
||||||
case TemplateArgument::Pack: |
|
||||||
out << "<"; |
|
||||||
bool First = true; |
|
||||||
for (const auto &P : arg.pack_elements()) { |
|
||||||
if (First) |
|
||||||
First = false; |
|
||||||
else |
|
||||||
out << ", "; |
|
||||||
|
|
||||||
P.print(policy, out); |
|
||||||
} |
|
||||||
out << ">"; |
|
||||||
break; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void printTemplateArguments(raw_ostream &out, const PrintingPolicy &policy, TemplateArgumentList const *args, bool qualifyNames) |
|
||||||
{ |
|
||||||
if (args == nullptr) |
|
||||||
{ |
|
||||||
return; |
|
||||||
} |
|
||||||
out << "<"; |
|
||||||
for (unsigned i = 0, e = args->size(); i != e; ++i) { |
|
||||||
if (i != 0) |
|
||||||
out << ", "; |
|
||||||
|
|
||||||
auto arg = args->get(i); |
|
||||||
printTemplateArgument(out, policy, arg, qualifyNames); |
|
||||||
} |
|
||||||
out << ">"; |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
std::string getTypeName(QualType qualType, bool qualifyNames) |
|
||||||
{ |
|
||||||
auto langOptions = clang::LangOptions{}; |
|
||||||
auto printPolicy = PrintingPolicy{ langOptions }; |
|
||||||
printPolicy.SuppressSpecifiers = false; |
|
||||||
printPolicy.ConstantArraySizeAsWritten = false; |
|
||||||
return qualType.getAsString(printPolicy); |
|
||||||
|
|
||||||
} |
|
||||||
|
|
||||||
std::string getFunctionPrototype(FunctionDecl *f, bool qualifyNames) |
|
||||||
{ |
|
||||||
std::string prototypeBuf; |
|
||||||
llvm::raw_string_ostream os(prototypeBuf); |
|
||||||
PrintingPolicy policy(f->getASTContext().getLangOpts()); |
|
||||||
policy.TerseOutput = false; |
|
||||||
os << getTypeName(f->getReturnType(), qualifyNames) << ' ' << f->getNameAsString(); |
|
||||||
if (f->getTemplatedKind() == FunctionDecl::TK_FunctionTemplateSpecialization || |
|
||||||
// f->getTemplatedKind() == FunctionDecl::TK_MemberSpecialization ||
|
|
||||||
f->getTemplatedKind() == FunctionDecl::TK_DependentFunctionTemplateSpecialization) |
|
||||||
{ |
|
||||||
printTemplateArguments(os, policy, f->getTemplateSpecializationArgs(), qualifyNames); |
|
||||||
} |
|
||||||
if (f->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) |
|
||||||
{ |
|
||||||
printTemplateParameters(os, policy, f->getDescribedFunctionTemplate()->getTemplateParameters()); |
|
||||||
} |
|
||||||
os << '('; |
|
||||||
bool first = true; |
|
||||||
for (auto param : f->parameters()) |
|
||||||
{ |
|
||||||
if (!first) |
|
||||||
{ |
|
||||||
os << ", "; |
|
||||||
} |
|
||||||
first = false; |
|
||||||
|
|
||||||
os << getTypeName(param->getType(), qualifyNames) << ' ' << param->getNameAsString(); |
|
||||||
} |
|
||||||
os << ')'; |
|
||||||
return os.str(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
} // namespace clang_utilities
|
|
@ -1,27 +0,0 @@ |
|||||||
#pragma once |
|
||||||
|
|
||||||
#pragma warning (push) |
|
||||||
#pragma warning (disable:4100 4127 4800 4512 4245 4291 4510 4610 4324 4267 4244 4996) |
|
||||||
#include <llvm/Support/raw_ostream.h> |
|
||||||
#include <clang/AST/PrettyPrinter.h> |
|
||||||
#include <clang/AST/Decl.h> |
|
||||||
#include <clang/AST/DeclTemplate.h> |
|
||||||
#pragma warning (pop) |
|
||||||
|
|
||||||
namespace clang_utilities { |
|
||||||
|
|
||||||
// Adapted from tools\clang\lib\AST\DeclPrinter.cpp DeclPrinter::PrintTemplateParameters
|
|
||||||
void printTemplateParameters(llvm::raw_ostream &out, clang::PrintingPolicy const &policy, const clang::TemplateParameterList *params); |
|
||||||
void printTemplateParameter(llvm::raw_ostream &out, clang::PrintingPolicy const &policy, clang::NamedDecl const *param); |
|
||||||
|
|
||||||
|
|
||||||
void printTemplateArguments(llvm::raw_ostream &out, const clang::PrintingPolicy &policy, clang::TemplateArgumentList const *args, bool qualifyNames); |
|
||||||
// Adapted from tools\clang\lib\AST\TemplateBase.cpp TemplateArgument::print
|
|
||||||
void printTemplateArgument(llvm::raw_ostream &out, const clang::PrintingPolicy &policy, clang::TemplateArgument const &arg, bool qualifyNames); |
|
||||||
|
|
||||||
std::string getFunctionPrototype(clang::FunctionDecl *f, bool qualifyNames); |
|
||||||
std::string getTypeName(clang::QualType qualType, bool qualifyNames); |
|
||||||
|
|
||||||
|
|
||||||
} // namespace clang_utilities
|
|
||||||
|
|
@ -1,90 +0,0 @@ |
|||||||
#ifdef _WIN32 |
|
||||||
#include <windows.h> |
|
||||||
#else |
|
||||||
#include <wordexp.h> |
|
||||||
#endif |
|
||||||
|
|
||||||
#include <vector> |
|
||||||
#include <string> |
|
||||||
#include <cassert> |
|
||||||
|
|
||||||
std::vector<std::string> splitCommandLine(std::string const &cmdline) |
|
||||||
{ |
|
||||||
int i; |
|
||||||
char **argv = NULL; |
|
||||||
int argc; |
|
||||||
std::vector<std::string> result; |
|
||||||
// Posix.
|
|
||||||
#ifndef _WIN32 |
|
||||||
{ |
|
||||||
wordexp_t p; |
|
||||||
|
|
||||||
// Note! This expands shell variables.
|
|
||||||
if (wordexp(cmdline.c_str(), &p, 0)) |
|
||||||
{ |
|
||||||
return result; |
|
||||||
} |
|
||||||
|
|
||||||
argc = p.we_wordc; |
|
||||||
|
|
||||||
if (!(argv = (char**) calloc(argc, sizeof(char *)))) |
|
||||||
{ |
|
||||||
goto fail; |
|
||||||
} |
|
||||||
|
|
||||||
for (i = 0; i < p.we_wordc; i++) |
|
||||||
{ |
|
||||||
result.push_back(p.we_wordv[i]); |
|
||||||
} |
|
||||||
|
|
||||||
wordfree(&p); |
|
||||||
|
|
||||||
return result; |
|
||||||
fail: |
|
||||||
wordfree(&p); |
|
||||||
return result; |
|
||||||
} |
|
||||||
#else // WIN32
|
|
||||||
{ |
|
||||||
wchar_t **wargs = NULL; |
|
||||||
size_t needed = 0; |
|
||||||
wchar_t *cmdlinew = NULL; |
|
||||||
size_t len = cmdline.size() + 1; |
|
||||||
|
|
||||||
if (!(cmdlinew = static_cast<wchar_t*>(calloc(len, sizeof(wchar_t))))) |
|
||||||
goto fail; |
|
||||||
|
|
||||||
if (!MultiByteToWideChar(CP_ACP, 0, cmdline.c_str(), -1, cmdlinew, len)) |
|
||||||
goto fail; |
|
||||||
|
|
||||||
if (!(wargs = CommandLineToArgvW(cmdlinew, &argc))) |
|
||||||
goto fail; |
|
||||||
|
|
||||||
// Convert from wchar_t * to ANSI char *
|
|
||||||
for (i = 0; i < argc; i++) |
|
||||||
{ |
|
||||||
// Get the size needed for the target buffer.
|
|
||||||
// CP_ACP = Ansi Codepage.
|
|
||||||
needed = WideCharToMultiByte(CP_ACP, 0, wargs[i], -1, |
|
||||||
NULL, 0, NULL, NULL); |
|
||||||
char *argv; |
|
||||||
if (!(argv = static_cast<char*>(malloc(needed)))) |
|
||||||
goto fail; |
|
||||||
|
|
||||||
// Do the conversion.
|
|
||||||
needed = WideCharToMultiByte(CP_ACP, 0, wargs[i], -1, |
|
||||||
argv, needed, NULL, NULL); |
|
||||||
result.push_back(argv); |
|
||||||
free(argv); |
|
||||||
} |
|
||||||
|
|
||||||
if (wargs) LocalFree(wargs); |
|
||||||
if (cmdlinew) free(cmdlinew); |
|
||||||
return result; |
|
||||||
|
|
||||||
fail: |
|
||||||
if (wargs) LocalFree(wargs); |
|
||||||
if (cmdlinew) free(cmdlinew); |
|
||||||
} |
|
||||||
#endif // WIN32
|
|
||||||
} |
|
@ -1,6 +0,0 @@ |
|||||||
#pragma once |
|
||||||
|
|
||||||
#include <vector> |
|
||||||
#include <string> |
|
||||||
|
|
||||||
std::vector<std::string> splitCommandLine(std::string const &cmdline); |
|
@ -1,143 +0,0 @@ |
|||||||
/****************************************************************************
|
|
||||||
** |
|
||||||
** Copyright (C) 2015 The Qt Company Ltd. |
|
||||||
** Contact: http://www.qt.io/licensing/
|
|
||||||
** |
|
||||||
** This file is part of the examples of the Qt Toolkit. |
|
||||||
** |
|
||||||
** $QT_BEGIN_LICENSE:BSD$ |
|
||||||
** You may use this file under the terms of the BSD license as follows: |
|
||||||
** |
|
||||||
** "Redistribution and use in source and binary forms, with or without |
|
||||||
** modification, are permitted provided that the following conditions are |
|
||||||
** met: |
|
||||||
** * Redistributions of source code must retain the above copyright |
|
||||||
** notice, this list of conditions and the following disclaimer. |
|
||||||
** * Redistributions in binary form must reproduce the above copyright |
|
||||||
** notice, this list of conditions and the following disclaimer in |
|
||||||
** the documentation and/or other materials provided with the |
|
||||||
** distribution. |
|
||||||
** * Neither the name of The Qt Company Ltd nor the names of its |
|
||||||
** contributors may be used to endorse or promote products derived |
|
||||||
** from this software without specific prior written permission. |
|
||||||
** |
|
||||||
** |
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
|
||||||
** |
|
||||||
** $QT_END_LICENSE$ |
|
||||||
** |
|
||||||
****************************************************************************/ |
|
||||||
|
|
||||||
#include "Highlighter.h" |
|
||||||
|
|
||||||
//! [0]
|
|
||||||
Highlighter::Highlighter(QTextDocument *parent) |
|
||||||
: QSyntaxHighlighter(parent) |
|
||||||
{ |
|
||||||
HighlightingRule rule; |
|
||||||
|
|
||||||
keywordFormat.setForeground(Qt::darkBlue); |
|
||||||
QStringList keywordPatterns; |
|
||||||
keywordPatterns << "\\bchar\\b" << "\\bclass\\b" << "\\bconst\\b" |
|
||||||
<< "\\bdouble\\b" << "\\benum\\b" << "\\bexplicit\\b" |
|
||||||
<< "\\bfriend\\b" << "\\binline\\b" << "\\bint\\b" |
|
||||||
<< "\\blong\\b" << "\\bnamespace\\b" << "\\boperator\\b" |
|
||||||
<< "\\bprivate\\b" << "\\bprotected\\b" << "\\bpublic\\b" |
|
||||||
<< "\\bshort\\b" << "\\bsignals\\b" << "\\bsigned\\b" |
|
||||||
<< "\\bslots\\b" << "\\bstatic\\b" << "\\bstruct\\b" |
|
||||||
<< "\\btemplate\\b" << "\\btypedef\\b" << "\\btypename\\b" |
|
||||||
<< "\\bunion\\b" << "\\bunsigned\\b" << "\\bvirtual\\b" |
|
||||||
<< "\\bvoid\\b" << "\\bvolatile\\b"; |
|
||||||
foreach (const QString &pattern, keywordPatterns) { |
|
||||||
rule.pattern = QRegExp(pattern); |
|
||||||
rule.format = keywordFormat; |
|
||||||
highlightingRules.append(rule); |
|
||||||
//! [0] //! [1]
|
|
||||||
} |
|
||||||
//! [1]
|
|
||||||
|
|
||||||
//! [2]
|
|
||||||
classFormat.setFontWeight(QFont::Bold); |
|
||||||
classFormat.setForeground(Qt::darkMagenta); |
|
||||||
rule.pattern = QRegExp("\\bQ[A-Za-z]+\\b"); |
|
||||||
rule.format = classFormat; |
|
||||||
highlightingRules.append(rule); |
|
||||||
//! [2]
|
|
||||||
|
|
||||||
//! [3]
|
|
||||||
singleLineCommentFormat.setForeground(Qt::darkGreen); |
|
||||||
rule.pattern = QRegExp("//[^\n]*"); |
|
||||||
rule.format = singleLineCommentFormat; |
|
||||||
highlightingRules.append(rule); |
|
||||||
|
|
||||||
multiLineCommentFormat.setForeground(Qt::darkGreen); |
|
||||||
//! [3]
|
|
||||||
|
|
||||||
//! [4]
|
|
||||||
quotationFormat.setForeground(Qt::darkMagenta); |
|
||||||
rule.pattern = QRegExp("\".*\""); |
|
||||||
rule.format = quotationFormat; |
|
||||||
highlightingRules.append(rule); |
|
||||||
//! [4]
|
|
||||||
|
|
||||||
//! [5]
|
|
||||||
functionFormat.setForeground(Qt::blue); |
|
||||||
rule.pattern = QRegExp("\\b[A-Za-z0-9_]+(?=\\()"); |
|
||||||
rule.format = functionFormat; |
|
||||||
highlightingRules.append(rule); |
|
||||||
//! [5]
|
|
||||||
|
|
||||||
//! [6]
|
|
||||||
commentStartExpression = QRegExp("/\\*"); |
|
||||||
commentEndExpression = QRegExp("\\*/"); |
|
||||||
} |
|
||||||
//! [6]
|
|
||||||
|
|
||||||
//! [7]
|
|
||||||
void Highlighter::highlightBlock(const QString &text) |
|
||||||
{ |
|
||||||
foreach (const HighlightingRule &rule, highlightingRules) { |
|
||||||
QRegExp expression(rule.pattern); |
|
||||||
int index = expression.indexIn(text); |
|
||||||
while (index >= 0) { |
|
||||||
int length = expression.matchedLength(); |
|
||||||
setFormat(index, length, rule.format); |
|
||||||
index = expression.indexIn(text, index + length); |
|
||||||
} |
|
||||||
} |
|
||||||
//! [7] //! [8]
|
|
||||||
setCurrentBlockState(0); |
|
||||||
//! [8]
|
|
||||||
|
|
||||||
//! [9]
|
|
||||||
int startIndex = 0; |
|
||||||
if (previousBlockState() != 1) |
|
||||||
startIndex = commentStartExpression.indexIn(text); |
|
||||||
|
|
||||||
//! [9] //! [10]
|
|
||||||
while (startIndex >= 0) { |
|
||||||
//! [10] //! [11]
|
|
||||||
int endIndex = commentEndExpression.indexIn(text, startIndex); |
|
||||||
int commentLength; |
|
||||||
if (endIndex == -1) { |
|
||||||
setCurrentBlockState(1); |
|
||||||
commentLength = text.length() - startIndex; |
|
||||||
} else { |
|
||||||
commentLength = endIndex - startIndex |
|
||||||
+ commentEndExpression.matchedLength(); |
|
||||||
} |
|
||||||
setFormat(startIndex, commentLength, multiLineCommentFormat); |
|
||||||
startIndex = commentStartExpression.indexIn(text, startIndex + commentLength); |
|
||||||
} |
|
||||||
} |
|
||||||
//! [11]
|
|
@ -1,84 +0,0 @@ |
|||||||
#pragma once |
|
||||||
|
|
||||||
/****************************************************************************
|
|
||||||
** |
|
||||||
** Copyright (C) 2015 The Qt Company Ltd. |
|
||||||
** Contact: http://www.qt.io/licensing/
|
|
||||||
** |
|
||||||
** This file is part of the examples of the Qt Toolkit. |
|
||||||
** |
|
||||||
** $QT_BEGIN_LICENSE:BSD$ |
|
||||||
** You may use this file under the terms of the BSD license as follows: |
|
||||||
** |
|
||||||
** "Redistribution and use in source and binary forms, with or without |
|
||||||
** modification, are permitted provided that the following conditions are |
|
||||||
** met: |
|
||||||
** * Redistributions of source code must retain the above copyright |
|
||||||
** notice, this list of conditions and the following disclaimer. |
|
||||||
** * Redistributions in binary form must reproduce the above copyright |
|
||||||
** notice, this list of conditions and the following disclaimer in |
|
||||||
** the documentation and/or other materials provided with the |
|
||||||
** distribution. |
|
||||||
** * Neither the name of The Qt Company Ltd nor the names of its |
|
||||||
** contributors may be used to endorse or promote products derived |
|
||||||
** from this software without specific prior written permission. |
|
||||||
** |
|
||||||
** |
|
||||||
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
||||||
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
|
||||||
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
|
||||||
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
|
||||||
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
|
||||||
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
|
||||||
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
|
||||||
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
|
||||||
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
|
||||||
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
|
||||||
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." |
|
||||||
** |
|
||||||
** $QT_END_LICENSE$ |
|
||||||
** |
|
||||||
****************************************************************************/ |
|
||||||
|
|
||||||
#ifndef HIGHLIGHTER_H |
|
||||||
#define HIGHLIGHTER_H |
|
||||||
|
|
||||||
#include <QSyntaxHighlighter> |
|
||||||
#include <QTextCharFormat> |
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE |
|
||||||
class QTextDocument; |
|
||||||
QT_END_NAMESPACE |
|
||||||
|
|
||||||
//! [0]
|
|
||||||
class Highlighter : public QSyntaxHighlighter |
|
||||||
{ |
|
||||||
Q_OBJECT |
|
||||||
|
|
||||||
public: |
|
||||||
Highlighter(QTextDocument *parent = 0); |
|
||||||
|
|
||||||
protected: |
|
||||||
void highlightBlock(const QString &text) Q_DECL_OVERRIDE; |
|
||||||
|
|
||||||
private: |
|
||||||
struct HighlightingRule |
|
||||||
{ |
|
||||||
QRegExp pattern; |
|
||||||
QTextCharFormat format; |
|
||||||
}; |
|
||||||
QVector<HighlightingRule> highlightingRules; |
|
||||||
|
|
||||||
QRegExp commentStartExpression; |
|
||||||
QRegExp commentEndExpression; |
|
||||||
|
|
||||||
QTextCharFormat keywordFormat; |
|
||||||
QTextCharFormat classFormat; |
|
||||||
QTextCharFormat singleLineCommentFormat; |
|
||||||
QTextCharFormat multiLineCommentFormat; |
|
||||||
QTextCharFormat quotationFormat; |
|
||||||
QTextCharFormat functionFormat; |
|
||||||
}; |
|
||||||
//! [0]
|
|
||||||
|
|
||||||
#endif // HIGHLIGHTER_H
|
|
@ -1,165 +0,0 @@ |
|||||||
GNU LESSER GENERAL PUBLIC LICENSE |
|
||||||
Version 3, 29 June 2007 |
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> |
|
||||||
Everyone is permitted to copy and distribute verbatim copies |
|
||||||
of this license document, but changing it is not allowed. |
|
||||||
|
|
||||||
|
|
||||||
This version of the GNU Lesser General Public License incorporates |
|
||||||
the terms and conditions of version 3 of the GNU General Public |
|
||||||
License, supplemented by the additional permissions listed below. |
|
||||||
|
|
||||||
0. Additional Definitions. |
|
||||||
|
|
||||||
As used herein, "this License" refers to version 3 of the GNU Lesser |
|
||||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU |
|
||||||
General Public License. |
|
||||||
|
|
||||||
"The Library" refers to a covered work governed by this License, |
|
||||||
other than an Application or a Combined Work as defined below. |
|
||||||
|
|
||||||
An "Application" is any work that makes use of an interface provided |
|
||||||
by the Library, but which is not otherwise based on the Library. |
|
||||||
Defining a subclass of a class defined by the Library is deemed a mode |
|
||||||
of using an interface provided by the Library. |
|
||||||
|
|
||||||
A "Combined Work" is a work produced by combining or linking an |
|
||||||
Application with the Library. The particular version of the Library |
|
||||||
with which the Combined Work was made is also called the "Linked |
|
||||||
Version". |
|
||||||
|
|
||||||
The "Minimal Corresponding Source" for a Combined Work means the |
|
||||||
Corresponding Source for the Combined Work, excluding any source code |
|
||||||
for portions of the Combined Work that, considered in isolation, are |
|
||||||
based on the Application, and not on the Linked Version. |
|
||||||
|
|
||||||
The "Corresponding Application Code" for a Combined Work means the |
|
||||||
object code and/or source code for the Application, including any data |
|
||||||
and utility programs needed for reproducing the Combined Work from the |
|
||||||
Application, but excluding the System Libraries of the Combined Work. |
|
||||||
|
|
||||||
1. Exception to Section 3 of the GNU GPL. |
|
||||||
|
|
||||||
You may convey a covered work under sections 3 and 4 of this License |
|
||||||
without being bound by section 3 of the GNU GPL. |
|
||||||
|
|
||||||
2. Conveying Modified Versions. |
|
||||||
|
|
||||||
If you modify a copy of the Library, and, in your modifications, a |
|
||||||
facility refers to a function or data to be supplied by an Application |
|
||||||
that uses the facility (other than as an argument passed when the |
|
||||||
facility is invoked), then you may convey a copy of the modified |
|
||||||
version: |
|
||||||
|
|
||||||
a) under this License, provided that you make a good faith effort to |
|
||||||
ensure that, in the event an Application does not supply the |
|
||||||
function or data, the facility still operates, and performs |
|
||||||
whatever part of its purpose remains meaningful, or |
|
||||||
|
|
||||||
b) under the GNU GPL, with none of the additional permissions of |
|
||||||
this License applicable to that copy. |
|
||||||
|
|
||||||
3. Object Code Incorporating Material from Library Header Files. |
|
||||||
|
|
||||||
The object code form of an Application may incorporate material from |
|
||||||
a header file that is part of the Library. You may convey such object |
|
||||||
code under terms of your choice, provided that, if the incorporated |
|
||||||
material is not limited to numerical parameters, data structure |
|
||||||
layouts and accessors, or small macros, inline functions and templates |
|
||||||
(ten or fewer lines in length), you do both of the following: |
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the object code that the |
|
||||||
Library is used in it and that the Library and its use are |
|
||||||
covered by this License. |
|
||||||
|
|
||||||
b) Accompany the object code with a copy of the GNU GPL and this license |
|
||||||
document. |
|
||||||
|
|
||||||
4. Combined Works. |
|
||||||
|
|
||||||
You may convey a Combined Work under terms of your choice that, |
|
||||||
taken together, effectively do not restrict modification of the |
|
||||||
portions of the Library contained in the Combined Work and reverse |
|
||||||
engineering for debugging such modifications, if you also do each of |
|
||||||
the following: |
|
||||||
|
|
||||||
a) Give prominent notice with each copy of the Combined Work that |
|
||||||
the Library is used in it and that the Library and its use are |
|
||||||
covered by this License. |
|
||||||
|
|
||||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license |
|
||||||
document. |
|
||||||
|
|
||||||
c) For a Combined Work that displays copyright notices during |
|
||||||
execution, include the copyright notice for the Library among |
|
||||||
these notices, as well as a reference directing the user to the |
|
||||||
copies of the GNU GPL and this license document. |
|
||||||
|
|
||||||
d) Do one of the following: |
|
||||||
|
|
||||||
0) Convey the Minimal Corresponding Source under the terms of this |
|
||||||
License, and the Corresponding Application Code in a form |
|
||||||
suitable for, and under terms that permit, the user to |
|
||||||
recombine or relink the Application with a modified version of |
|
||||||
the Linked Version to produce a modified Combined Work, in the |
|
||||||
manner specified by section 6 of the GNU GPL for conveying |
|
||||||
Corresponding Source. |
|
||||||
|
|
||||||
1) Use a suitable shared library mechanism for linking with the |
|
||||||
Library. A suitable mechanism is one that (a) uses at run time |
|
||||||
a copy of the Library already present on the user's computer |
|
||||||
system, and (b) will operate properly with a modified version |
|
||||||
of the Library that is interface-compatible with the Linked |
|
||||||
Version. |
|
||||||
|
|
||||||
e) Provide Installation Information, but only if you would otherwise |
|
||||||
be required to provide such information under section 6 of the |
|
||||||
GNU GPL, and only to the extent that such information is |
|
||||||
necessary to install and execute a modified version of the |
|
||||||
Combined Work produced by recombining or relinking the |
|
||||||
Application with a modified version of the Linked Version. (If |
|
||||||
you use option 4d0, the Installation Information must accompany |
|
||||||
the Minimal Corresponding Source and Corresponding Application |
|
||||||
Code. If you use option 4d1, you must provide the Installation |
|
||||||
Information in the manner specified by section 6 of the GNU GPL |
|
||||||
for conveying Corresponding Source.) |
|
||||||
|
|
||||||
5. Combined Libraries. |
|
||||||
|
|
||||||
You may place library facilities that are a work based on the |
|
||||||
Library side by side in a single library together with other library |
|
||||||
facilities that are not Applications and are not covered by this |
|
||||||
License, and convey such a combined library under terms of your |
|
||||||
choice, if you do both of the following: |
|
||||||
|
|
||||||
a) Accompany the combined library with a copy of the same work based |
|
||||||
on the Library, uncombined with any other library facilities, |
|
||||||
conveyed under the terms of this License. |
|
||||||
|
|
||||||
b) Give prominent notice with the combined library that part of it |
|
||||||
is a work based on the Library, and explaining where to find the |
|
||||||
accompanying uncombined form of the same work. |
|
||||||
|
|
||||||
6. Revised Versions of the GNU Lesser General Public License. |
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions |
|
||||||
of the GNU Lesser General Public License from time to time. Such new |
|
||||||
versions will be similar in spirit to the present version, but may |
|
||||||
differ in detail to address new problems or concerns. |
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the |
|
||||||
Library as you received it specifies that a certain numbered version |
|
||||||
of the GNU Lesser General Public License "or any later version" |
|
||||||
applies to it, you have the option of following the terms and |
|
||||||
conditions either of that published version or of any later version |
|
||||||
published by the Free Software Foundation. If the Library as you |
|
||||||
received it does not specify a version number of the GNU Lesser |
|
||||||
General Public License, you may choose any version of the GNU Lesser |
|
||||||
General Public License ever published by the Free Software Foundation. |
|
||||||
|
|
||||||
If the Library as you received it specifies that a proxy can decide |
|
||||||
whether future versions of the GNU Lesser General Public License shall |
|
||||||
apply, that proxy's public statement of acceptance of any version is |
|
||||||
permanent authorization for you to choose that version for the |
|
||||||
Library. |
|
@ -1,169 +0,0 @@ |
|||||||
#include "MainWindow.h" |
|
||||||
#include <qmessagebox.h> |
|
||||||
#include <qwindow.h> |
|
||||||
#include <qfilesystemmodel.h> |
|
||||||
#include <qstringlist.h> |
|
||||||
#include "AstModel.h" |
|
||||||
|
|
||||||
class UpdateLock |
|
||||||
{ |
|
||||||
public: |
|
||||||
UpdateLock(bool &lock) : myLock(lock) |
|
||||||
{ |
|
||||||
myLock = true; |
|
||||||
} |
|
||||||
~UpdateLock() |
|
||||||
{ |
|
||||||
myLock = false; |
|
||||||
} |
|
||||||
bool & myLock; |
|
||||||
}; |
|
||||||
|
|
||||||
MainWindow::MainWindow(QWidget *parent) : |
|
||||||
QMainWindow(parent), |
|
||||||
isUpdateInProgress(false) |
|
||||||
{ |
|
||||||
myUi.setupUi(this); |
|
||||||
|
|
||||||
connect(myUi.actionRefresh, &QAction::triggered, this, &MainWindow::RefreshAst); |
|
||||||
|
|
||||||
myHighlighter = new Highlighter(myUi.codeViewer->document()); |
|
||||||
myUi.nodeProperties->setHeaderLabels({ "Property", "Value" }); |
|
||||||
connect(myUi.codeViewer, &QTextEdit::cursorPositionChanged, this, &MainWindow::HighlightNodeMatchingCode); |
|
||||||
connect(myUi.codeViewer, &QTextEdit::textChanged, this, &MainWindow::OnCodeChange); |
|
||||||
connect(myUi.showDetails, &QPushButton::clicked, this, &MainWindow::ShowNodeDetails); |
|
||||||
} |
|
||||||
|
|
||||||
void MainWindow::RefreshAst() |
|
||||||
{ |
|
||||||
auto ast = myReader.readAst(myUi.codeViewer->document()->toPlainText().toStdString(), |
|
||||||
myUi.commandLineArgs->document()->toPlainText().toStdString()); |
|
||||||
auto model = new AstModel(std::move(ast)); |
|
||||||
|
|
||||||
myUi.astTreeView->setModel(model); |
|
||||||
myUi.astTreeView->setRootIndex(model->rootIndex()); |
|
||||||
connect(myUi.astTreeView->selectionModel(), &QItemSelectionModel::currentChanged, |
|
||||||
this, &MainWindow::HighlightCodeMatchingNode); |
|
||||||
connect(myUi.astTreeView->selectionModel(), &QItemSelectionModel::currentChanged, |
|
||||||
this, &MainWindow::DisplayNodeProperties); |
|
||||||
myUi.astTreeView->setEnabled(myReader.ready()); |
|
||||||
} |
|
||||||
|
|
||||||
void MainWindow::HighlightCodeMatchingNode(const QModelIndex &newNode, const QModelIndex &previousNode) |
|
||||||
{ |
|
||||||
if (isUpdateInProgress) |
|
||||||
{ |
|
||||||
return; |
|
||||||
} |
|
||||||
auto lock = UpdateLock{ isUpdateInProgress }; |
|
||||||
auto node = myUi.astTreeView->model()->data(newNode, Qt::NodeRole).value<GenericAstNode*>(); |
|
||||||
auto &manager = myReader.getManager(); |
|
||||||
std::pair<int, int> location; |
|
||||||
if (!node->getRangeInMainFile(location, manager, myReader.getContext())) |
|
||||||
{ |
|
||||||
return; |
|
||||||
} |
|
||||||
auto cursor = myUi.codeViewer->textCursor(); |
|
||||||
cursor.setPosition(location.first); |
|
||||||
cursor.setPosition(location.second, QTextCursor::KeepAnchor); |
|
||||||
myUi.codeViewer->setTextCursor(cursor); |
|
||||||
} |
|
||||||
|
|
||||||
void MainWindow::DisplayNodeProperties(const QModelIndex &newNode, const QModelIndex &previousNode) |
|
||||||
{ |
|
||||||
myUi.nodeProperties->clear(); |
|
||||||
auto node = myUi.astTreeView->model()->data(newNode, Qt::NodeRole).value<GenericAstNode*>(); |
|
||||||
for (auto &prop : node->getProperties()) |
|
||||||
{ |
|
||||||
new QTreeWidgetItem(myUi.nodeProperties, QStringList{ QString::fromStdString(prop.first), QString::fromStdString(prop.second) }); |
|
||||||
} |
|
||||||
myUi.showDetails->setVisible(node->hasDetails); |
|
||||||
} |
|
||||||
|
|
||||||
void MainWindow::HighlightNodeMatchingCode() |
|
||||||
{ |
|
||||||
if (isUpdateInProgress || !myReader.ready()) |
|
||||||
{ |
|
||||||
return; |
|
||||||
} |
|
||||||
auto lock = UpdateLock{ isUpdateInProgress }; |
|
||||||
auto cursorPosition = myUi.codeViewer->textCursor().position(); |
|
||||||
auto nodePath = myReader.getBestNodeMatchingPosition(cursorPosition); |
|
||||||
auto model = myUi.astTreeView->model(); |
|
||||||
if (!nodePath.empty()) |
|
||||||
{ |
|
||||||
auto currentIndex = model->index(0, 0); // Returns the root
|
|
||||||
currentIndex = model->index(0, 0, currentIndex); // Returns the AST node
|
|
||||||
auto currentNode = nodePath.front(); |
|
||||||
bool first = true; |
|
||||||
for (auto node : nodePath) |
|
||||||
{ |
|
||||||
if (first) |
|
||||||
{ |
|
||||||
first = false; |
|
||||||
} |
|
||||||
else |
|
||||||
{ |
|
||||||
auto index = currentNode->findChildIndex(node); |
|
||||||
if (index == -1) |
|
||||||
{ |
|
||||||
// Something wrong, just silently return
|
|
||||||
return; |
|
||||||
} |
|
||||||
currentIndex = model->index(index, 0, currentIndex); |
|
||||||
currentNode = node; |
|
||||||
} |
|
||||||
} |
|
||||||
myUi.astTreeView->scrollTo(currentIndex, QAbstractItemView::EnsureVisible); |
|
||||||
auto selectionModel = myUi.astTreeView->selectionModel(); |
|
||||||
// selectionModel->select(currentIndex, QItemSelectionModel::ClearAndSelect);
|
|
||||||
selectionModel->setCurrentIndex(currentIndex, QItemSelectionModel::ClearAndSelect); |
|
||||||
DisplayNodeProperties(currentIndex, currentIndex); // Since we won't use the previous node, it's not an issue if it is wrong...
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void MainWindow::ShowNodeDetails() |
|
||||||
{ |
|
||||||
auto selectionModel = myUi.astTreeView->selectionModel(); |
|
||||||
auto model = myUi.astTreeView->model(); |
|
||||||
auto node = myUi.astTreeView->model()->data(selectionModel->currentIndex(), Qt::NodeRole).value<GenericAstNode*>(); |
|
||||||
if (! node || !node->hasDetails) |
|
||||||
{ |
|
||||||
QMessageBox::warning(this, windowTitle() + " - Error in details", |
|
||||||
"The currently selected node does not have details", QMessageBox::Ok); |
|
||||||
return; |
|
||||||
} |
|
||||||
if (node->details.empty()) |
|
||||||
{ |
|
||||||
node->details = node->detailsComputer(); |
|
||||||
} |
|
||||||
|
|
||||||
auto win = new QDialog(this); |
|
||||||
win->setLayout(new QGridLayout()); |
|
||||||
win->resize(size()); |
|
||||||
win->move(pos()); |
|
||||||
win->setWindowTitle(windowTitle() + " - " + QString::fromStdString(node->name) + " - " + QString::fromStdString(node->detailsTitle)); |
|
||||||
auto edit = new QTextEdit(win); |
|
||||||
win->layout()->addWidget(edit); |
|
||||||
edit->setText(QString::fromStdString(node->details)); |
|
||||||
edit->setReadOnly(true); |
|
||||||
myDetailWindows.push_back(win); |
|
||||||
win->show(); |
|
||||||
} |
|
||||||
|
|
||||||
|
|
||||||
void MainWindow::closeEvent(QCloseEvent *event) |
|
||||||
{ |
|
||||||
for (auto win : myDetailWindows) |
|
||||||
{ |
|
||||||
win->close(); |
|
||||||
} |
|
||||||
event->accept(); |
|
||||||
} |
|
||||||
|
|
||||||
void MainWindow::OnCodeChange() |
|
||||||
{ |
|
||||||
myUi.astTreeView->setEnabled(false); |
|
||||||
myReader.dirty(); |
|
||||||
} |
|
||||||
|
|
@ -1,27 +0,0 @@ |
|||||||
#pragma once |
|
||||||
|
|
||||||
#include "ui_MainWindow.h" |
|
||||||
#include "Highlighter.h" |
|
||||||
#include "AstReader.h" |
|
||||||
|
|
||||||
|
|
||||||
class MainWindow : public QMainWindow |
|
||||||
{ |
|
||||||
Q_OBJECT |
|
||||||
public: |
|
||||||
MainWindow(QWidget *parent = nullptr); |
|
||||||
public slots: |
|
||||||
void RefreshAst(); |
|
||||||
void HighlightCodeMatchingNode(const QModelIndex &newNode, const QModelIndex &previousNode); |
|
||||||
void DisplayNodeProperties(const QModelIndex &newNode, const QModelIndex &previousNode); |
|
||||||
void HighlightNodeMatchingCode(); |
|
||||||
void ShowNodeDetails(); |
|
||||||
void OnCodeChange(); |
|
||||||
void closeEvent(QCloseEvent *event) override; |
|
||||||
private: |
|
||||||
Ui::MainWindow myUi; |
|
||||||
Highlighter *myHighlighter; // No need to delete, since is will have a parent that will take care of that
|
|
||||||
AstReader myReader; |
|
||||||
std::vector<QDialog *> myDetailWindows; |
|
||||||
bool isUpdateInProgress; |
|
||||||
}; |
|
@ -1,151 +0,0 @@ |
|||||||
<?xml version="1.0" encoding="UTF-8"?> |
|
||||||
<ui version="4.0"> |
|
||||||
<class>MainWindow</class> |
|
||||||
<widget class="QMainWindow" name="MainWindow"> |
|
||||||
<property name="geometry"> |
|
||||||
<rect> |
|
||||||
<x>0</x> |
|
||||||
<y>0</y> |
|
||||||
<width>800</width> |
|
||||||
<height>600</height> |
|
||||||
</rect> |
|
||||||
</property> |
|
||||||
<property name="windowTitle"> |
|
||||||
<string>Clang AST viewer</string> |
|
||||||
</property> |
|
||||||
<widget class="QWidget" name="centralwidget"> |
|
||||||
<layout class="QGridLayout" name="gridLayout"> |
|
||||||
<item row="0" column="0"> |
|
||||||
<widget class="QTextEdit" name="codeViewer"> |
|
||||||
<property name="font"> |
|
||||||
<font> |
|
||||||
<family>Consolas</family> |
|
||||||
<pointsize>10</pointsize> |
|
||||||
</font> |
|
||||||
</property> |
|
||||||
<property name="styleSheet"> |
|
||||||
<string notr="true">selection-background-color: rgb(170, 85, 255); |
|
||||||
selection-color: white</string> |
|
||||||
</property> |
|
||||||
<property name="tabStopWidth"> |
|
||||||
<number>25</number> |
|
||||||
</property> |
|
||||||
</widget> |
|
||||||
</item> |
|
||||||
</layout> |
|
||||||
</widget> |
|
||||||
<widget class="QMenuBar" name="menubar"> |
|
||||||
<property name="geometry"> |
|
||||||
<rect> |
|
||||||
<x>0</x> |
|
||||||
<y>0</y> |
|
||||||
<width>800</width> |
|
||||||
<height>21</height> |
|
||||||
</rect> |
|
||||||
</property> |
|
||||||
</widget> |
|
||||||
<widget class="QStatusBar" name="statusbar"/> |
|
||||||
<widget class="QDockWidget" name="astDock"> |
|
||||||
<property name="windowTitle"> |
|
||||||
<string>Clang AST</string> |
|
||||||
</property> |
|
||||||
<attribute name="dockWidgetArea"> |
|
||||||
<number>2</number> |
|
||||||
</attribute> |
|
||||||
<widget class="QWidget" name="dockWidgetContents"> |
|
||||||
<layout class="QGridLayout" name="gridLayout_2"> |
|
||||||
<item row="0" column="0"> |
|
||||||
<widget class="QTreeView" name="astTreeView"> |
|
||||||
<property name="enabled"> |
|
||||||
<bool>false</bool> |
|
||||||
</property> |
|
||||||
<property name="styleSheet"> |
|
||||||
<string notr="true">QTreeView::item:selected { color:white; background:rgb(170, 85, 255); }</string> |
|
||||||
</property> |
|
||||||
<property name="indentation"> |
|
||||||
<number>10</number> |
|
||||||
</property> |
|
||||||
<property name="headerHidden"> |
|
||||||
<bool>true</bool> |
|
||||||
</property> |
|
||||||
</widget> |
|
||||||
</item> |
|
||||||
</layout> |
|
||||||
</widget> |
|
||||||
</widget> |
|
||||||
<widget class="QToolBar" name="toolBar"> |
|
||||||
<property name="windowTitle"> |
|
||||||
<string>toolBar</string> |
|
||||||
</property> |
|
||||||
<attribute name="toolBarArea"> |
|
||||||
<enum>TopToolBarArea</enum> |
|
||||||
</attribute> |
|
||||||
<attribute name="toolBarBreak"> |
|
||||||
<bool>false</bool> |
|
||||||
</attribute> |
|
||||||
<addaction name="actionRefresh"/> |
|
||||||
</widget> |
|
||||||
<widget class="QDockWidget" name="dockWidget"> |
|
||||||
<property name="windowTitle"> |
|
||||||
<string>Command line arguments</string> |
|
||||||
</property> |
|
||||||
<attribute name="dockWidgetArea"> |
|
||||||
<number>8</number> |
|
||||||
</attribute> |
|
||||||
<widget class="QWidget" name="dockWidgetContents_2"> |
|
||||||
<layout class="QGridLayout" name="gridLayout_3"> |
|
||||||
<item row="0" column="0"> |
|
||||||
<widget class="QPlainTextEdit" name="commandLineArgs"> |
|
||||||
<property name="plainText"> |
|
||||||
<string>-std=c++14 "-IC:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\include" -I"C:\Program Files (x86)\Windows Kits\10\Include\10.0.10150.0\ucrt" -fcxx-exceptions -fms-compatibility -fdelayed-template-parsing</string> |
|
||||||
</property> |
|
||||||
</widget> |
|
||||||
</item> |
|
||||||
</layout> |
|
||||||
</widget> |
|
||||||
</widget> |
|
||||||
<widget class="QDockWidget" name="dockWidget_2"> |
|
||||||
<property name="windowTitle"> |
|
||||||
<string>Properties</string> |
|
||||||
</property> |
|
||||||
<attribute name="dockWidgetArea"> |
|
||||||
<number>2</number> |
|
||||||
</attribute> |
|
||||||
<widget class="QWidget" name="dockWidgetContents_3"> |
|
||||||
<layout class="QGridLayout" name="gridLayout_4"> |
|
||||||
<item row="0" column="0"> |
|
||||||
<widget class="QTreeWidget" name="nodeProperties"> |
|
||||||
<property name="columnCount"> |
|
||||||
<number>2</number> |
|
||||||
</property> |
|
||||||
<column> |
|
||||||
<property name="text"> |
|
||||||
<string notr="true">1</string> |
|
||||||
</property> |
|
||||||
</column> |
|
||||||
<column> |
|
||||||
<property name="text"> |
|
||||||
<string notr="true">2</string> |
|
||||||
</property> |
|
||||||
</column> |
|
||||||
</widget> |
|
||||||
</item> |
|
||||||
<item row="1" column="0"> |
|
||||||
<widget class="QPushButton" name="showDetails"> |
|
||||||
<property name="text"> |
|
||||||
<string>Show details</string> |
|
||||||
</property> |
|
||||||
</widget> |
|
||||||
</item> |
|
||||||
</layout> |
|
||||||
</widget> |
|
||||||
</widget> |
|
||||||
<action name="actionRefresh"> |
|
||||||
<property name="text"> |
|
||||||
<string>Refresh</string> |
|
||||||
</property> |
|
||||||
</action> |
|
||||||
</widget> |
|
||||||
<resources/> |
|
||||||
<connections/> |
|
||||||
</ui> |
|
@ -1,7 +0,0 @@ |
|||||||
# Clang-ast-viewer |
|
||||||
## Introduction |
|
||||||
|
|
||||||
Fork of [https://github.com/CAST-projects/Clang-ast-viewer](https://github.com/CAST-projects/Clang-ast-viewer). |
|
||||||
|
|
||||||
## License |
|
||||||
This product is provided under LGPL. See the `LICENCE` file for more information. |
|
@ -1,14 +0,0 @@ |
|||||||
#include <QApplication> |
|
||||||
#include <QPushButton> |
|
||||||
#include "MainWindow.h" |
|
||||||
|
|
||||||
int main(int argc, char **argv) |
|
||||||
{ |
|
||||||
QApplication app (argc, argv); |
|
||||||
|
|
||||||
MainWindow mainWindow; |
|
||||||
mainWindow.show(); |
|
||||||
|
|
||||||
return app.exec(); |
|
||||||
} |
|
||||||
|
|
@ -1,32 +0,0 @@ |
|||||||
require("premake-qt/qt") |
|
||||||
local qt = premake.extensions.qt |
|
||||||
|
|
||||||
project "CppSharp.ASTViewer" |
|
||||||
SetupNativeProject() |
|
||||||
kind "ConsoleApp" |
|
||||||
systemversion("latest") |
|
||||||
cppdialect "C++17" |
|
||||||
|
|
||||||
qt.enable() |
|
||||||
|
|
||||||
filter { "system:linux" } |
|
||||||
buildoptions { "-fPIC" } |
|
||||||
links { "pthread" } |
|
||||||
qtincludepath "/usr/include/x86_64-linux-gnu/qt5" |
|
||||||
qtlibpath "/usr/lib/x86_64-linux-gnu" |
|
||||||
qtbinpath "/usr/lib/qt5/bin" |
|
||||||
|
|
||||||
filter { "system:windows" } |
|
||||||
qtpath "C:\\Qt\\5.12.0\\msvc2017" |
|
||||||
|
|
||||||
filter {} |
|
||||||
|
|
||||||
qtmodules { "core", "gui", "widgets" } |
|
||||||
qtprefix "Qt5" |
|
||||||
files { "**.h", "**.cpp", "**.ui", "**.qrc" } |
|
||||||
|
|
||||||
SetupLLVMIncludes() |
|
||||||
SetupLLVMLibs() |
|
||||||
|
|
||||||
filter { "toolset:msc*" } |
|
||||||
buildoptions { "/wd4141", "/wd4146", "/wd4996" } |
|
@ -1,11 +0,0 @@ |
|||||||
function SetupWrapper(name) |
|
||||||
if not EnabledManagedProjects() then |
|
||||||
return |
|
||||||
end |
|
||||||
|
|
||||||
SetupExternalManagedTestProject(name .. ".CSharp") |
|
||||||
end |
|
||||||
|
|
||||||
group "Tests/Namespaces" |
|
||||||
SetupTestNativeProject("NamespacesBase") |
|
||||||
targetdir (path.join(gendir, "NamespacesDerived")) |
|
@ -1,4 +1,7 @@ |
|||||||
<Project Sdk="Microsoft.NET.Sdk"> |
<Project Sdk="Microsoft.NET.Sdk"> |
||||||
|
<PropertyGroup> |
||||||
|
<NoWarn>0108</NoWarn> |
||||||
|
</PropertyGroup> |
||||||
<ItemGroup> |
<ItemGroup> |
||||||
<Compile Include="CSharpPartialMethods.cs" /> |
<Compile Include="CSharpPartialMethods.cs" /> |
||||||
</ItemGroup> |
</ItemGroup> |
@ -1,5 +1,5 @@ |
|||||||
<Project> |
<Project> |
||||||
<Import Project="../Directory.Build.props" /> |
<Import Project="../../Directory.Build.props" /> |
||||||
<Import Project="Test.Common.props" /> |
<Import Project="Test.Common.props" /> |
||||||
<Import Project="Test.Generator.props" Condition="$(IsTestGenerator)" /> |
<Import Project="Test.Generator.props" Condition="$(IsTestGenerator)" /> |
||||||
<Import Project="Test.Bindings.props" Condition="$(IsTestBindings)" /> |
<Import Project="Test.Bindings.props" Condition="$(IsTestBindings)" /> |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue