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 @@
@@ -1,3 +0,0 @@
|
||||
[submodule "build/modules/premake-qt"] |
||||
path = build/modules/premake-qt |
||||
url = https://github.com/dcourtois/premake-qt.git |
@ -1 +0,0 @@
@@ -1 +0,0 @@
|
||||
Subproject commit 0ddc49715c7892211774d4b5e705a7c5559aeed4 |
@ -1,141 +0,0 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -1,6 +0,0 @@
|
||||
#pragma once |
||||
|
||||
#include <vector> |
||||
#include <string> |
||||
|
||||
std::vector<std::string> splitCommandLine(std::string const &cmdline); |
@ -1,143 +0,0 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -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 @@
@@ -1,4 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk"> |
||||
<PropertyGroup> |
||||
<NoWarn>0108</NoWarn> |
||||
</PropertyGroup> |
||||
<ItemGroup> |
||||
<Compile Include="CSharpPartialMethods.cs" /> |
||||
</ItemGroup> |
@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
|
||||
<Project> |
||||
<Import Project="../Directory.Build.props" /> |
||||
<Import Project="../../Directory.Build.props" /> |
||||
<Import Project="Test.Common.props" /> |
||||
<Import Project="Test.Generator.props" Condition="$(IsTestGenerator)" /> |
||||
<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