зеркало из https://github.com/mono/CppSharp.git
Code cleanups and improvements (#1713)
* 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/.
This commit is contained in:
Родитель
117567d61f
Коммит
4417dd987a
|
@ -1,3 +0,0 @@
|
|||
[submodule "build/modules/premake-qt"]
|
||||
path = build/modules/premake-qt
|
||||
url = https://github.com/dcourtois/premake-qt.git
|
|
@ -34,7 +34,7 @@
|
|||
<GeneratorFileExtension>dll</GeneratorFileExtension>
|
||||
<DotNetCmd Condition="'$(PlatformTarget)' == 'x86' AND Exists('$(MSBuildProgramFiles32)\dotnet\dotnet.exe')">"$(MSBuildProgramFiles32)\dotnet\dotnet.exe"</DotNetCmd>
|
||||
<DotNetCmd Condition="'$(PlatformTarget)' == 'x64' AND Exists('$(ProgramW6432)\dotnet\dotnet.exe')">"$(ProgramW6432)\dotnet\dotnet.exe"</DotNetCmd>
|
||||
<RID Condition="$(IsWindows)">win</RID>
|
||||
<RID Condition="$(IsWindows)">win</RID>
|
||||
<RID Condition="$(IsLinux)">linux</RID>
|
||||
<RID Condition="$(IsMacOSX)">osx</RID>
|
||||
<RID>$(RID)-$(PlatformTarget)</RID>
|
||||
|
|
|
@ -47,7 +47,7 @@ rootdir = path.getabsolute("../")
|
|||
srcdir = path.join(rootdir, "src");
|
||||
incdir = path.join(rootdir, "include");
|
||||
examplesdir = path.join(rootdir, "examples");
|
||||
testsdir = path.join(rootdir, "tests");
|
||||
testsdir = path.join(rootdir, "tests/dotnet");
|
||||
builddir = path.join(rootdir, "build")
|
||||
bindir = path.join(rootdir, "bin")
|
||||
objsdir = path.join(builddir, "obj");
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
Subproject commit 0ddc49715c7892211774d4b5e705a7c5559aeed4
|
|
@ -44,7 +44,7 @@ workspace "CppSharp"
|
|||
workspacefiles(path.join(builddir, "premake5.lua"))
|
||||
workspacefiles(path.join(builddir, "*.sh"))
|
||||
workspacefiles(path.join(rootdir, ".github/workflows/*.yml"))
|
||||
workspacefiles(path.join(rootdir, "tests/Test*.props"))
|
||||
workspacefiles(path.join(testsdir, "Test*.props"))
|
||||
|
||||
group "Libraries"
|
||||
if EnableNativeProjects() then
|
||||
|
|
|
@ -22,109 +22,62 @@ namespace CppSharp.AST
|
|||
parameters.AddRange(property.Parameters);
|
||||
}
|
||||
|
||||
public Type Type
|
||||
{
|
||||
get { return QualifiedType.Type; }
|
||||
}
|
||||
public Type Type => QualifiedType.Type;
|
||||
|
||||
public QualifiedType QualifiedType { get; set; }
|
||||
|
||||
public bool IsStatic
|
||||
{
|
||||
get
|
||||
{
|
||||
return (GetMethod != null && GetMethod.IsStatic) ||
|
||||
(SetMethod != null && SetMethod.IsStatic);
|
||||
}
|
||||
}
|
||||
public bool IsStatic =>
|
||||
GetMethod is {IsStatic: true} ||
|
||||
SetMethod is {IsStatic: true};
|
||||
|
||||
public bool IsPure
|
||||
{
|
||||
get
|
||||
{
|
||||
return (GetMethod != null && GetMethod.IsPure) ||
|
||||
(SetMethod != null && SetMethod.IsPure);
|
||||
}
|
||||
}
|
||||
public bool IsPure =>
|
||||
GetMethod is {IsPure: true} ||
|
||||
SetMethod is {IsPure: true};
|
||||
|
||||
public bool IsVirtual
|
||||
{
|
||||
get
|
||||
{
|
||||
return (GetMethod != null && GetMethod.IsVirtual) ||
|
||||
(SetMethod != null && SetMethod.IsVirtual);
|
||||
}
|
||||
}
|
||||
public bool IsVirtual =>
|
||||
GetMethod is {IsVirtual: true} ||
|
||||
SetMethod is {IsVirtual: true};
|
||||
|
||||
public bool IsOverride
|
||||
{
|
||||
get
|
||||
{
|
||||
return (GetMethod != null && GetMethod.IsOverride) ||
|
||||
(SetMethod != null && SetMethod.IsOverride);
|
||||
}
|
||||
}
|
||||
public bool IsOverride =>
|
||||
GetMethod is {IsOverride: true} ||
|
||||
SetMethod is {IsOverride: true};
|
||||
|
||||
public Method GetMethod { get; set; }
|
||||
|
||||
public Method SetMethod { get; set; }
|
||||
|
||||
public bool HasGetter
|
||||
{
|
||||
get
|
||||
{
|
||||
return (GetMethod != null &&
|
||||
GetMethod.GenerationKind != GenerationKind.None) ||
|
||||
(Field != null &&
|
||||
Field.GenerationKind != GenerationKind.None);
|
||||
}
|
||||
}
|
||||
public bool HasGetter =>
|
||||
(GetMethod != null &&
|
||||
GetMethod.GenerationKind != GenerationKind.None) ||
|
||||
(Field != null &&
|
||||
Field.GenerationKind != GenerationKind.None);
|
||||
|
||||
public bool HasSetter
|
||||
{
|
||||
get
|
||||
{
|
||||
return (SetMethod != null &&
|
||||
SetMethod.GenerationKind != GenerationKind.None) ||
|
||||
(Field != null &&
|
||||
(!Field.QualifiedType.IsConst() ||
|
||||
Field.Type.IsConstCharString()) &&
|
||||
Field.GenerationKind != GenerationKind.None);
|
||||
}
|
||||
}
|
||||
public bool HasSetter =>
|
||||
(SetMethod != null &&
|
||||
SetMethod.GenerationKind != GenerationKind.None) ||
|
||||
(Field != null &&
|
||||
(!Field.QualifiedType.IsConst() ||
|
||||
Field.Type.IsConstCharString()) &&
|
||||
Field.GenerationKind != GenerationKind.None);
|
||||
|
||||
// The field that should be get and set by this property
|
||||
public Field Field { get; set; }
|
||||
|
||||
public Class ExplicitInterfaceImpl { get; set; }
|
||||
|
||||
private readonly List<Parameter> parameters = new List<Parameter>();
|
||||
private readonly List<Parameter> parameters = new();
|
||||
|
||||
/// <summary>
|
||||
/// Only applicable to index ([]) properties.
|
||||
/// </summary>
|
||||
public List<Parameter> Parameters
|
||||
{
|
||||
get { return parameters; }
|
||||
}
|
||||
public List<Parameter> Parameters => parameters;
|
||||
|
||||
public bool IsIndexer
|
||||
{
|
||||
get
|
||||
{
|
||||
return GetMethod != null &&
|
||||
GetMethod.OperatorKind == CXXOperatorKind.Subscript;
|
||||
}
|
||||
}
|
||||
public bool IsIndexer =>
|
||||
GetMethod is {OperatorKind: CXXOperatorKind.Subscript};
|
||||
|
||||
public bool IsSynthetized
|
||||
{
|
||||
get
|
||||
{
|
||||
return (GetMethod != null && GetMethod.IsSynthetized) ||
|
||||
(SetMethod != null && SetMethod.IsSynthetized);
|
||||
}
|
||||
}
|
||||
public bool IsSynthetized =>
|
||||
(GetMethod != null && GetMethod.IsSynthetized) ||
|
||||
(SetMethod != null && SetMethod.IsSynthetized);
|
||||
|
||||
public override T Visit<T>(IDeclVisitor<T> visitor)
|
||||
{
|
||||
|
|
|
@ -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" }
|
|
@ -138,7 +138,7 @@ namespace CppSharp
|
|||
parserOptions.UnityBuild = options.UnityBuild;
|
||||
parserOptions.EnableRTTI = options.EnableRTTI;
|
||||
|
||||
parserOptions.Setup();
|
||||
parserOptions.Setup(options.Platform ?? Platform.Host);
|
||||
|
||||
if (triple.Contains("linux"))
|
||||
SetupLinuxOptions(parserOptions);
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<ProduceReferenceAssembly>true</ProduceReferenceAssembly>
|
||||
<IsPackable>true</IsPackable>
|
||||
<NoWarn>0109</NoWarn>
|
||||
<PlatformParserFolder Condition="$(IsWindows) AND $(PlatformTarget) == x64">x86_64-pc-win32-msvc</PlatformParserFolder>
|
||||
<PlatformParserFolder Condition="$(IsLinux) AND $(PlatformTarget) == x64 AND $(UseCXX11ABI)">x86_64-linux-gnu-cxx11abi</PlatformParserFolder>
|
||||
<PlatformParserFolder Condition="$(IsLinux) AND $(PlatformTarget) == x64 AND !$(UseCXX11ABI)">x86_64-linux-gnu</PlatformParserFolder>
|
||||
|
|
|
@ -35,23 +35,21 @@ namespace CppSharp.Utils
|
|||
testModule.LibraryName, options.GeneratorKind.ToString());
|
||||
|
||||
if (Platform.IsMacOS)
|
||||
driver.ParserOptions.TargetTriple = Environment.Is64BitProcess ?
|
||||
"x86_64-apple-darwin" : "i686-apple-darwin";
|
||||
driver.ParserOptions.TargetTriple = "x86_64-apple-darwin";
|
||||
|
||||
var path = Path.GetFullPath(GetTestsDirectory(name));
|
||||
testModule.IncludeDirs.Add(path);
|
||||
testModule.LibraryDirs.Add(options.OutputDir);
|
||||
testModule.Libraries.Add($"{name}.Native");
|
||||
|
||||
Diagnostics.Message("Looking for tests in: {0}", path);
|
||||
var files = Directory.EnumerateFiles(path, "*.h", SearchOption.AllDirectories);
|
||||
foreach (var file in files)
|
||||
{
|
||||
string includeDir = Path.GetDirectoryName(file);
|
||||
var includeDir = Path.GetDirectoryName(file);
|
||||
|
||||
if (!testModule.IncludeDirs.Contains(includeDir))
|
||||
{
|
||||
testModule.IncludeDirs.Add(includeDir);
|
||||
}
|
||||
|
||||
testModule.Headers.Add(Path.GetFileName(file));
|
||||
}
|
||||
}
|
||||
|
@ -76,12 +74,12 @@ namespace CppSharp.Utils
|
|||
|
||||
while (directory != null)
|
||||
{
|
||||
var path = Path.Combine(directory.FullName, "tests", name);
|
||||
var path = Path.Combine(directory.FullName, "tests", "dotnet", name);
|
||||
|
||||
if (Directory.Exists(path))
|
||||
return path;
|
||||
|
||||
path = Path.Combine(directory.FullName, "external", "CppSharp", "tests", name);
|
||||
path = Path.Combine(directory.FullName, "external", "CppSharp", "tests", "dotnet", name);
|
||||
|
||||
if (Directory.Exists(path))
|
||||
return path;
|
||||
|
|
|
@ -85,7 +85,7 @@ namespace CppSharp
|
|||
public void Setup()
|
||||
{
|
||||
ValidateOptions();
|
||||
ParserOptions.Setup();
|
||||
ParserOptions.Setup(Platform.Host);
|
||||
Context = new BindingContext(Options, ParserOptions);
|
||||
Context.LinkerOptions.Setup(ParserOptions.TargetTriple, ParserOptions.LanguageVersion);
|
||||
Generator = CreateGeneratorFromKind(Options.GeneratorKind);
|
||||
|
@ -112,7 +112,8 @@ namespace CppSharp
|
|||
switch (result.Kind)
|
||||
{
|
||||
case ParserResultKind.Success:
|
||||
Diagnostics.Message("Parsed '{0}'", string.Join(", ", files));
|
||||
if (!Options.Quiet)
|
||||
Diagnostics.Message("Parsed '{0}'", string.Join(", ", files));
|
||||
break;
|
||||
case ParserResultKind.Error:
|
||||
Diagnostics.Error("Error parsing '{0}'", string.Join(", ", files));
|
||||
|
@ -183,27 +184,22 @@ namespace CppSharp
|
|||
ClangParser.LibraryParsed += OnFileParsed;
|
||||
foreach (var module in Options.Modules)
|
||||
{
|
||||
using (var linkerOptions = new LinkerOptions(Context.LinkerOptions))
|
||||
using var linkerOptions = new LinkerOptions(Context.LinkerOptions);
|
||||
foreach (var libraryDir in module.LibraryDirs)
|
||||
linkerOptions.AddLibraryDirs(libraryDir);
|
||||
|
||||
foreach (var library in module.Libraries.Where(library =>
|
||||
Context.Symbols.Libraries.All(l => l.FileName != library)))
|
||||
{
|
||||
foreach (var libraryDir in module.LibraryDirs)
|
||||
linkerOptions.AddLibraryDirs(libraryDir);
|
||||
|
||||
foreach (string library in module.Libraries)
|
||||
{
|
||||
if (Context.Symbols.Libraries.Any(l => l.FileName == library))
|
||||
continue;
|
||||
linkerOptions.AddLibraries(library);
|
||||
}
|
||||
|
||||
using (var res = ClangParser.ParseLibrary(linkerOptions))
|
||||
{
|
||||
if (res.Kind != ParserResultKind.Success)
|
||||
continue;
|
||||
|
||||
for (uint i = 0; i < res.LibrariesCount; i++)
|
||||
Context.Symbols.Libraries.Add(ClangParser.ConvertLibrary(res.GetLibraries(i)));
|
||||
}
|
||||
linkerOptions.AddLibraries(library);
|
||||
}
|
||||
|
||||
using var res = ClangParser.ParseLibrary(linkerOptions);
|
||||
if (res.Kind != ParserResultKind.Success)
|
||||
continue;
|
||||
|
||||
for (uint i = 0; i < res.LibrariesCount; i++)
|
||||
Context.Symbols.Libraries.Add(ClangParser.ConvertLibrary(res.GetLibraries(i)));
|
||||
}
|
||||
ClangParser.LibraryParsed -= OnFileParsed;
|
||||
|
||||
|
@ -215,95 +211,99 @@ namespace CppSharp
|
|||
|
||||
public void SetupPasses(ILibrary library)
|
||||
{
|
||||
var TranslationUnitPasses = Context.TranslationUnitPasses;
|
||||
var passes = Context.TranslationUnitPasses;
|
||||
|
||||
TranslationUnitPasses.AddPass(new ResolveIncompleteDeclsPass());
|
||||
TranslationUnitPasses.AddPass(new IgnoreSystemDeclarationsPass());
|
||||
TranslationUnitPasses.AddPass(new MatchParamNamesWithInstantiatedFromPass());
|
||||
passes.AddPass(new ResolveIncompleteDeclsPass());
|
||||
passes.AddPass(new IgnoreSystemDeclarationsPass());
|
||||
passes.AddPass(new MatchParamNamesWithInstantiatedFromPass());
|
||||
|
||||
if (Options.IsCSharpGenerator)
|
||||
TranslationUnitPasses.AddPass(new EqualiseAccessOfOverrideAndBasePass());
|
||||
passes.AddPass(new EqualiseAccessOfOverrideAndBasePass());
|
||||
|
||||
TranslationUnitPasses.AddPass(new FlattenAnonymousTypesToFields());
|
||||
TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass());
|
||||
TranslationUnitPasses.AddPass(new MarkUsedClassInternalsPass());
|
||||
passes.AddPass(new FlattenAnonymousTypesToFields());
|
||||
passes.AddPass(new CheckIgnoredDeclsPass());
|
||||
passes.AddPass(new MarkUsedClassInternalsPass());
|
||||
|
||||
if (Options.IsCSharpGenerator)
|
||||
{
|
||||
TranslationUnitPasses.AddPass(new TrimSpecializationsPass());
|
||||
TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions());
|
||||
TranslationUnitPasses.AddPass(new GenerateSymbolsPass());
|
||||
TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass());
|
||||
passes.AddPass(new TrimSpecializationsPass());
|
||||
passes.AddPass(new CheckAmbiguousFunctions());
|
||||
passes.AddPass(new GenerateSymbolsPass());
|
||||
passes.AddPass(new CheckIgnoredDeclsPass());
|
||||
}
|
||||
|
||||
if (Options.IsCLIGenerator || Options.IsCSharpGenerator)
|
||||
{
|
||||
TranslationUnitPasses.AddPass(new MoveFunctionToClassPass());
|
||||
TranslationUnitPasses.AddPass(new ValidateOperatorsPass());
|
||||
passes.AddPass(new MoveFunctionToClassPass());
|
||||
passes.AddPass(new ValidateOperatorsPass());
|
||||
}
|
||||
|
||||
library.SetupPasses(this);
|
||||
|
||||
TranslationUnitPasses.AddPass(new FindSymbolsPass());
|
||||
TranslationUnitPasses.AddPass(new CheckMacroPass());
|
||||
TranslationUnitPasses.AddPass(new CheckStaticClass());
|
||||
passes.AddPass(new FindSymbolsPass());
|
||||
passes.AddPass(new CheckMacroPass());
|
||||
passes.AddPass(new CheckStaticClass());
|
||||
|
||||
if (Options.IsCLIGenerator || Options.IsCSharpGenerator || Options.IsCppGenerator)
|
||||
{
|
||||
TranslationUnitPasses.AddPass(new CheckAmbiguousFunctions());
|
||||
passes.AddPass(new CheckAmbiguousFunctions());
|
||||
}
|
||||
|
||||
TranslationUnitPasses.AddPass(new ConstructorToConversionOperatorPass());
|
||||
TranslationUnitPasses.AddPass(new MarshalPrimitivePointersAsRefTypePass());
|
||||
passes.AddPass(new ConstructorToConversionOperatorPass());
|
||||
passes.AddPass(new MarshalPrimitivePointersAsRefTypePass());
|
||||
|
||||
if (Options.IsCLIGenerator || Options.IsCSharpGenerator)
|
||||
{
|
||||
TranslationUnitPasses.AddPass(new CheckOperatorsOverloadsPass());
|
||||
passes.AddPass(new CheckOperatorsOverloadsPass());
|
||||
}
|
||||
|
||||
TranslationUnitPasses.AddPass(new CheckVirtualOverrideReturnCovariance());
|
||||
TranslationUnitPasses.AddPass(new CleanCommentsPass());
|
||||
passes.AddPass(new CheckVirtualOverrideReturnCovariance());
|
||||
passes.AddPass(new CleanCommentsPass());
|
||||
|
||||
Generator.SetupPasses();
|
||||
|
||||
TranslationUnitPasses.AddPass(new CleanInvalidDeclNamesPass());
|
||||
TranslationUnitPasses.AddPass(new FastDelegateToDelegatesPass());
|
||||
TranslationUnitPasses.AddPass(new FieldToPropertyPass());
|
||||
TranslationUnitPasses.AddPass(new CheckIgnoredDeclsPass());
|
||||
TranslationUnitPasses.AddPass(new CheckFlagEnumsPass());
|
||||
TranslationUnitPasses.AddPass(new MakeProtectedNestedTypesPublicPass());
|
||||
passes.AddPass(new CleanInvalidDeclNamesPass());
|
||||
passes.AddPass(new FastDelegateToDelegatesPass());
|
||||
passes.AddPass(new FieldToPropertyPass());
|
||||
passes.AddPass(new CheckIgnoredDeclsPass());
|
||||
passes.AddPass(new CheckFlagEnumsPass());
|
||||
passes.AddPass(new MakeProtectedNestedTypesPublicPass());
|
||||
|
||||
if (Options.IsCSharpGenerator)
|
||||
{
|
||||
TranslationUnitPasses.AddPass(new GenerateAbstractImplementationsPass());
|
||||
TranslationUnitPasses.AddPass(new MultipleInheritancePass());
|
||||
passes.AddPass(new GenerateAbstractImplementationsPass());
|
||||
passes.AddPass(new MultipleInheritancePass());
|
||||
}
|
||||
|
||||
if (Options.IsCLIGenerator || Options.IsCSharpGenerator)
|
||||
{
|
||||
TranslationUnitPasses.AddPass(new DelegatesPass());
|
||||
TranslationUnitPasses.AddPass(new GetterSetterToPropertyPass());
|
||||
passes.AddPass(new DelegatesPass());
|
||||
}
|
||||
|
||||
TranslationUnitPasses.AddPass(new StripUnusedSystemTypesPass());
|
||||
if (Options.GeneratorKind != GeneratorKind.C)
|
||||
{
|
||||
passes.AddPass(new GetterSetterToPropertyPass());
|
||||
}
|
||||
|
||||
passes.AddPass(new StripUnusedSystemTypesPass());
|
||||
|
||||
if (Options.IsCSharpGenerator)
|
||||
{
|
||||
TranslationUnitPasses.AddPass(new SpecializationMethodsWithDependentPointersPass());
|
||||
TranslationUnitPasses.AddPass(new ParamTypeToInterfacePass());
|
||||
passes.AddPass(new SpecializationMethodsWithDependentPointersPass());
|
||||
passes.AddPass(new ParamTypeToInterfacePass());
|
||||
}
|
||||
|
||||
TranslationUnitPasses.AddPass(new CheckDuplicatedNamesPass());
|
||||
passes.AddPass(new CheckDuplicatedNamesPass());
|
||||
|
||||
if (Options.IsCLIGenerator || Options.IsCSharpGenerator)
|
||||
{
|
||||
TranslationUnitPasses.RenameDeclsUpperCase(RenameTargets.Any & ~RenameTargets.Parameter);
|
||||
TranslationUnitPasses.AddPass(new CheckKeywordNamesPass());
|
||||
passes.RenameDeclsUpperCase(RenameTargets.Any & ~RenameTargets.Parameter);
|
||||
passes.AddPass(new CheckKeywordNamesPass());
|
||||
}
|
||||
|
||||
Context.TranslationUnitPasses.AddPass(new HandleVariableInitializerPass());
|
||||
passes.AddPass(new HandleVariableInitializerPass());
|
||||
|
||||
TranslationUnitPasses.AddPass(new MarkEventsWithUniqueIdPass());
|
||||
passes.AddPass(new MarkEventsWithUniqueIdPass());
|
||||
}
|
||||
|
||||
public void ProcessCode()
|
||||
|
@ -345,10 +345,10 @@ namespace CppSharp
|
|||
var file = Path.Combine(outputPath, fileRelativePath);
|
||||
WriteGeneratedCodeToFile(file, template.Generate());
|
||||
|
||||
if (output.TranslationUnit.Module != null)
|
||||
output.TranslationUnit.Module.CodeFiles.Add(file);
|
||||
output.TranslationUnit.Module?.CodeFiles.Add(file);
|
||||
|
||||
Diagnostics.Message("Generated '{0}'", fileRelativePath);
|
||||
if (!Options.Quiet)
|
||||
Diagnostics.Message("Generated '{0}'", fileRelativePath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -367,7 +367,7 @@ namespace CppSharp
|
|||
|
||||
public bool CompileCode(Module module)
|
||||
{
|
||||
var msBuildGenerator = new MSBuildGenerator(Context, module, libraryMappings);
|
||||
var msBuildGenerator = new MSBuildGenerator(Context, module, LibraryMappings);
|
||||
msBuildGenerator.Process();
|
||||
string csproj = Path.Combine(Options.OutputDir,
|
||||
$"{module.LibraryName}.{msBuildGenerator.FileExtension}");
|
||||
|
@ -378,7 +378,7 @@ namespace CppSharp
|
|||
if (error == 0)
|
||||
{
|
||||
Diagnostics.Message($@"Compilation succeeded: {
|
||||
libraryMappings[module] = Path.Combine(
|
||||
LibraryMappings[module] = Path.Combine(
|
||||
Options.OutputDir, $"{module.LibraryName}.dll")}.");
|
||||
return true;
|
||||
}
|
||||
|
@ -407,7 +407,7 @@ namespace CppSharp
|
|||
}
|
||||
|
||||
private bool hasParsingErrors;
|
||||
private static readonly Dictionary<Module, string> libraryMappings = new Dictionary<Module, string>();
|
||||
private static readonly Dictionary<Module, string> LibraryMappings = new();
|
||||
}
|
||||
|
||||
public static class ConsoleDriver
|
||||
|
@ -415,67 +415,63 @@ namespace CppSharp
|
|||
public static void Run(ILibrary library)
|
||||
{
|
||||
var options = new DriverOptions();
|
||||
using (var driver = new Driver(options))
|
||||
using var driver = new Driver(options);
|
||||
library.Setup(driver);
|
||||
|
||||
driver.Setup();
|
||||
|
||||
if (driver.Options.Verbose)
|
||||
Diagnostics.Level = DiagnosticKind.Debug;
|
||||
|
||||
if (!options.Quiet)
|
||||
Diagnostics.Message("Parsing libraries...");
|
||||
|
||||
if (!driver.ParseLibraries())
|
||||
return;
|
||||
|
||||
if (!options.Quiet)
|
||||
Diagnostics.Message("Parsing code...");
|
||||
|
||||
if (!driver.ParseCode())
|
||||
{
|
||||
library.Setup(driver);
|
||||
|
||||
driver.Setup();
|
||||
|
||||
if (driver.Options.Verbose)
|
||||
Diagnostics.Level = DiagnosticKind.Debug;
|
||||
|
||||
if (!options.Quiet)
|
||||
Diagnostics.Message("Parsing libraries...");
|
||||
|
||||
if (!driver.ParseLibraries())
|
||||
return;
|
||||
|
||||
if (!options.Quiet)
|
||||
Diagnostics.Message("Parsing code...");
|
||||
|
||||
if (!driver.ParseCode())
|
||||
{
|
||||
Diagnostics.Error("CppSharp has encountered an error while parsing code.");
|
||||
return;
|
||||
}
|
||||
|
||||
new CleanUnitPass { Context = driver.Context }.VisitASTContext(driver.Context.ASTContext);
|
||||
options.Modules.RemoveAll(m => m != options.SystemModule && !m.Units.GetGenerated().Any());
|
||||
|
||||
if (!options.Quiet)
|
||||
Diagnostics.Message("Processing code...");
|
||||
|
||||
driver.SetupPasses(library);
|
||||
driver.SetupTypeMaps();
|
||||
driver.SetupDeclMaps();
|
||||
|
||||
library.Preprocess(driver, driver.Context.ASTContext);
|
||||
|
||||
driver.ProcessCode();
|
||||
library.Postprocess(driver, driver.Context.ASTContext);
|
||||
|
||||
if (!options.Quiet)
|
||||
Diagnostics.Message("Generating code...");
|
||||
|
||||
if (!options.DryRun)
|
||||
{
|
||||
var outputs = driver.GenerateCode();
|
||||
|
||||
library.GenerateCode(driver, outputs);
|
||||
|
||||
foreach (var output in outputs)
|
||||
{
|
||||
foreach (var pass in driver.Context.GeneratorOutputPasses.Passes)
|
||||
{
|
||||
pass.VisitGeneratorOutput(output);
|
||||
}
|
||||
}
|
||||
|
||||
driver.SaveCode(outputs);
|
||||
if (driver.Options.IsCSharpGenerator && driver.Options.CompileCode)
|
||||
driver.Options.Modules.Any(m => !driver.CompileCode(m));
|
||||
}
|
||||
Diagnostics.Error("CppSharp has encountered an error while parsing code.");
|
||||
return;
|
||||
}
|
||||
|
||||
new CleanUnitPass { Context = driver.Context }.VisitASTContext(driver.Context.ASTContext);
|
||||
options.Modules.RemoveAll(m => m != options.SystemModule && !m.Units.GetGenerated().Any());
|
||||
|
||||
if (!options.Quiet)
|
||||
Diagnostics.Message("Processing code...");
|
||||
|
||||
driver.SetupPasses(library);
|
||||
driver.SetupTypeMaps();
|
||||
driver.SetupDeclMaps();
|
||||
|
||||
library.Preprocess(driver, driver.Context.ASTContext);
|
||||
|
||||
driver.ProcessCode();
|
||||
library.Postprocess(driver, driver.Context.ASTContext);
|
||||
|
||||
if (!options.Quiet)
|
||||
Diagnostics.Message("Generating code...");
|
||||
|
||||
if (options.DryRun)
|
||||
return;
|
||||
|
||||
var outputs = driver.GenerateCode();
|
||||
|
||||
library.GenerateCode(driver, outputs);
|
||||
|
||||
foreach (var output in outputs)
|
||||
{
|
||||
foreach (var pass in driver.Context.GeneratorOutputPasses.Passes)
|
||||
pass.VisitGeneratorOutput(output);
|
||||
}
|
||||
|
||||
driver.SaveCode(outputs);
|
||||
if (driver.Options.IsCSharpGenerator && driver.Options.CompileCode)
|
||||
driver.Options.Modules.Any(m => !driver.CompileCode(m));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace CppSharp.Generators.Emscripten
|
|||
/// Generates Emscripten Embind C/C++ header files.
|
||||
/// Embind documentation: https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html
|
||||
/// </summary>
|
||||
public class EmscriptenHeaders : EmscriptenCodeGenerator
|
||||
public sealed class EmscriptenHeaders : EmscriptenCodeGenerator
|
||||
{
|
||||
public EmscriptenHeaders(BindingContext context, IEnumerable<TranslationUnit> units)
|
||||
: base(context, units)
|
||||
|
|
|
@ -62,7 +62,7 @@ namespace CppSharp.Passes
|
|||
}
|
||||
|
||||
if (function.IsAmbiguous)
|
||||
Diagnostics.Message($"Found ambiguous overload: {function.QualifiedOriginalName}");
|
||||
Diagnostics.Debug($"Found ambiguous overload: {function.QualifiedOriginalName}");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -33,8 +33,7 @@ namespace CppSharp.Passes
|
|||
return false;
|
||||
}
|
||||
|
||||
var @class = field.Namespace as Class;
|
||||
if (@class == null)
|
||||
if (field.Namespace is not Class @class)
|
||||
return false;
|
||||
|
||||
// Check if we already have a synthetized property.
|
||||
|
|
|
@ -21,19 +21,16 @@ namespace CppSharp.Passes
|
|||
private static void LoadVerbs()
|
||||
{
|
||||
var assembly = Assembly.GetAssembly(typeof(GetterSetterToPropertyPass));
|
||||
using (var resourceStream = GetResourceStream(assembly))
|
||||
{
|
||||
using (var streamReader = new StreamReader(resourceStream))
|
||||
while (!streamReader.EndOfStream)
|
||||
verbs.Add(streamReader.ReadLine());
|
||||
}
|
||||
using var resourceStream = GetResourceStream(assembly);
|
||||
using var streamReader = new StreamReader(resourceStream);
|
||||
while (!streamReader.EndOfStream)
|
||||
Verbs.Add(streamReader.ReadLine());
|
||||
}
|
||||
|
||||
private static Stream GetResourceStream(Assembly assembly)
|
||||
{
|
||||
var resources = assembly.GetManifestResourceNames();
|
||||
|
||||
if (resources.Count() == 0)
|
||||
if (!resources.Any())
|
||||
throw new Exception("Cannot find embedded verbs data resource.");
|
||||
|
||||
// We are relying on this fact that there is only one resource embedded.
|
||||
|
@ -54,13 +51,12 @@ namespace CppSharp.Passes
|
|||
return false;
|
||||
}
|
||||
|
||||
protected virtual List<Property> GetProperties(Class @class) =>
|
||||
new List<Property>();
|
||||
protected virtual List<Property> GetProperties() => new();
|
||||
|
||||
protected IEnumerable<Property> GenerateProperties(Class @class)
|
||||
{
|
||||
List<Property> properties = GetProperties(@class);
|
||||
foreach (Method method in @class.Methods.Where(
|
||||
var properties = GetProperties();
|
||||
foreach (var method in @class.Methods.Where(
|
||||
m => !m.IsConstructor && !m.IsDestructor && !m.IsOperator && m.IsGenerated &&
|
||||
(properties.All(p => p.GetMethod != m && p.SetMethod != m) ||
|
||||
m.OriginalFunction != null) &&
|
||||
|
@ -72,15 +68,16 @@ namespace CppSharp.Passes
|
|||
if (IsGetter(method))
|
||||
{
|
||||
string name = GetPropertyName(method.Name);
|
||||
GetProperty(properties, method, name, method.OriginalReturnType);
|
||||
CreateOrUpdateProperty(properties, method, name, method.OriginalReturnType);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsSetter(method))
|
||||
{
|
||||
string name = GetPropertyNameFromSetter(method.Name);
|
||||
QualifiedType type = method.Parameters.First(
|
||||
p => p.Kind == ParameterKind.Regular).QualifiedType;
|
||||
GetProperty(properties, method, name, type, true);
|
||||
CreateOrUpdateProperty(properties, method, name, type, true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,7 +101,7 @@ namespace CppSharp.Passes
|
|||
continue;
|
||||
|
||||
if (Match(firstWord, new[] { "to", "new", "on" }) ||
|
||||
verbs.Contains(firstWord))
|
||||
Verbs.Contains(firstWord))
|
||||
{
|
||||
property.GetMethod.GenerationKind = GenerationKind.Generate;
|
||||
@class.Properties.Remove(property);
|
||||
|
@ -115,12 +112,10 @@ namespace CppSharp.Passes
|
|||
return properties;
|
||||
}
|
||||
|
||||
private static void GetProperty(List<Property> properties, Method method,
|
||||
private static void CreateOrUpdateProperty(List<Property> properties, Method method,
|
||||
string name, QualifiedType type, bool isSetter = false)
|
||||
{
|
||||
Type underlyingType = GetUnderlyingType(type);
|
||||
Class @class = (Class)method.Namespace;
|
||||
|
||||
Property property = properties.Find(
|
||||
p => p.Field == null &&
|
||||
((!isSetter && p.SetMethod?.IsStatic == method.IsStatic) ||
|
||||
|
@ -255,14 +250,13 @@ namespace CppSharp.Passes
|
|||
|
||||
private static Type GetUnderlyingType(QualifiedType type)
|
||||
{
|
||||
TagType tagType = type.Type as TagType;
|
||||
if (tagType != null)
|
||||
if (type.Type is TagType)
|
||||
return type.Type;
|
||||
|
||||
// TODO: we should normally check pointer types for const;
|
||||
// however, there's some bug, probably in the parser, that returns IsConst = false for "const Type& arg"
|
||||
// so skip the check for the time being
|
||||
PointerType pointerType = type.Type as PointerType;
|
||||
return pointerType != null ? pointerType.Pointee : type.Type;
|
||||
return type.Type is PointerType pointerType ? pointerType.Pointee : type.Type;
|
||||
}
|
||||
|
||||
private static void CombineComments(Property property)
|
||||
|
@ -277,6 +271,7 @@ namespace CppSharp.Passes
|
|||
BriefText = getter.Comment.BriefText,
|
||||
Text = getter.Comment.Text
|
||||
};
|
||||
|
||||
if (getter.Comment.FullComment != null)
|
||||
{
|
||||
comment.FullComment = new FullComment();
|
||||
|
@ -295,20 +290,18 @@ namespace CppSharp.Passes
|
|||
private static string GetPropertyName(string name)
|
||||
{
|
||||
var firstWord = GetFirstWord(name);
|
||||
if (Match(firstWord, new[] { "get" }) &&
|
||||
(string.Compare(name, firstWord, StringComparison.InvariantCultureIgnoreCase) != 0) &&
|
||||
!char.IsNumber(name[3]))
|
||||
if (!Match(firstWord, new[] {"get"}) ||
|
||||
(string.Compare(name, firstWord, StringComparison.InvariantCultureIgnoreCase) == 0) ||
|
||||
char.IsNumber(name[3])) return name;
|
||||
|
||||
if (name.Length == 4)
|
||||
{
|
||||
if (name.Length == 4)
|
||||
{
|
||||
return char.ToLowerInvariant(
|
||||
name[3]).ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
return char.ToLowerInvariant(
|
||||
name[3]).ToString(CultureInfo.InvariantCulture) +
|
||||
name.Substring(4);
|
||||
name[3]).ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
return name;
|
||||
|
||||
return string.Concat(char.ToLowerInvariant(
|
||||
name[3]).ToString(CultureInfo.InvariantCulture), name.AsSpan(4));
|
||||
}
|
||||
|
||||
private static string GetPropertyNameFromSetter(string name)
|
||||
|
@ -327,8 +320,8 @@ namespace CppSharp.Passes
|
|||
|
||||
private bool IsGetter(Method method) =>
|
||||
!method.IsDestructor &&
|
||||
!method.OriginalReturnType.Type.IsPrimitiveType(PrimitiveType.Void) &&
|
||||
!method.Parameters.Any(p => p.Kind != ParameterKind.IndirectReturnType);
|
||||
!method.OriginalReturnType.Type.IsPrimitiveType(PrimitiveType.Void) &&
|
||||
method.Parameters.All(p => p.Kind == ParameterKind.IndirectReturnType);
|
||||
|
||||
private static bool IsSetter(Method method)
|
||||
{
|
||||
|
@ -365,6 +358,6 @@ namespace CppSharp.Passes
|
|||
return new string(firstWord.ToArray());
|
||||
}
|
||||
|
||||
private static readonly HashSet<string> verbs = new HashSet<string>();
|
||||
private static readonly HashSet<string> Verbs = new();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -227,8 +227,6 @@ namespace CppSharp.Types.Std
|
|||
return (Context.Options.Encoding, nameof(Encoding.ASCII));
|
||||
if (Context.Options.Encoding == Encoding.UTF8)
|
||||
return (Context.Options.Encoding, nameof(Encoding.UTF8));
|
||||
if (Context.Options.Encoding == Encoding.UTF7)
|
||||
return (Context.Options.Encoding, nameof(Encoding.UTF7));
|
||||
if (Context.Options.Encoding == Encoding.BigEndianUnicode)
|
||||
return (Context.Options.Encoding, nameof(Encoding.BigEndianUnicode));
|
||||
if (Context.Options.Encoding == Encoding.Unicode)
|
||||
|
|
|
@ -710,7 +710,6 @@ namespace Mono.Options
|
|||
get { return this.option; }
|
||||
}
|
||||
|
||||
[SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)]
|
||||
public override void GetObjectData(SerializationInfo info, StreamingContext context)
|
||||
{
|
||||
base.GetObjectData(info, context);
|
||||
|
|
|
@ -276,15 +276,21 @@ namespace CppSharp.Parser
|
|||
AddSystemIncludeDirs($"{headersPath}/usr/include/linux");
|
||||
}
|
||||
|
||||
public void Setup()
|
||||
private bool setupDone;
|
||||
|
||||
public void Setup(TargetPlatform targetPlatform)
|
||||
{
|
||||
SetupArguments();
|
||||
if (setupDone) return;
|
||||
|
||||
SetupArguments(targetPlatform);
|
||||
|
||||
if (!NoBuiltinIncludes)
|
||||
SetupIncludes();
|
||||
SetupIncludes(targetPlatform);
|
||||
|
||||
setupDone = true;
|
||||
}
|
||||
|
||||
private void SetupArguments()
|
||||
private void SetupArguments(TargetPlatform targetPlatform)
|
||||
{
|
||||
LanguageVersion ??= CppSharp.Parser.LanguageVersion.CPP14_GNU;
|
||||
|
||||
|
@ -296,7 +302,7 @@ namespace CppSharp.Parser
|
|||
// setup methods, below is generic fallback in case that logic was disabled.
|
||||
if (NoBuiltinIncludes)
|
||||
{
|
||||
switch (Platform.Host)
|
||||
switch (targetPlatform)
|
||||
{
|
||||
case TargetPlatform.MacOS:
|
||||
case TargetPlatform.Linux:
|
||||
|
@ -370,18 +376,21 @@ namespace CppSharp.Parser
|
|||
{
|
||||
get
|
||||
{
|
||||
var assemblyDir = Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);
|
||||
var assemblyDir = Path.GetDirectoryName(Assembly.GetEntryAssembly()?.Location);
|
||||
if (assemblyDir == null)
|
||||
throw new InvalidOperationException();
|
||||
|
||||
return Path.Combine(assemblyDir, "lib", "clang", ClangVersion, "include");
|
||||
}
|
||||
}
|
||||
|
||||
private void SetupIncludes()
|
||||
private void SetupIncludes(TargetPlatform targetPlatform)
|
||||
{
|
||||
// Check that the builtin includes folder exists.
|
||||
if (!Directory.Exists(BuiltinsDir))
|
||||
throw new Exception($"Clang resource folder 'lib/clang/{ClangVersion}/include' was not found.");
|
||||
|
||||
switch (Platform.Host)
|
||||
switch (targetPlatform)
|
||||
{
|
||||
case TargetPlatform.Windows:
|
||||
SetupMSVC();
|
||||
|
@ -392,6 +401,16 @@ namespace CppSharp.Parser
|
|||
case TargetPlatform.Linux:
|
||||
SetupLinux();
|
||||
break;
|
||||
case TargetPlatform.Android:
|
||||
throw new NotImplementedException();
|
||||
case TargetPlatform.iOS:
|
||||
case TargetPlatform.WatchOS:
|
||||
case TargetPlatform.TVOS:
|
||||
throw new NotImplementedException();
|
||||
case TargetPlatform.Emscripten:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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">
|
||||
<PropertyGroup>
|
||||
<NoWarn>0108</NoWarn>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="CSharpPartialMethods.cs" />
|
||||
</ItemGroup>
|
|
@ -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)" />
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче