diff --git a/.github/workflows/llvm-win.yml b/.github/workflows/llvm-win.yml index 6bf9e8c0e5..455c4f4dcf 100644 --- a/.github/workflows/llvm-win.yml +++ b/.github/workflows/llvm-win.yml @@ -9,8 +9,8 @@ jobs: fail-fast: false matrix: config: - - { os: windows-2019, platform: x86, vs: 2019 } - - { os: windows-2019, platform: x64, vs: 2019 } + - { os: windows-2022, platform: x86, vs: 2022 } + - { os: windows-2022, platform: x64, vs: 2022 } runs-on: ${{ matrix.config.os }} @@ -23,7 +23,7 @@ jobs: steps: - name: Inject slug/short variables - uses: rlespinasse/github-slug-action@v3.x + uses: rlespinasse/github-slug-action@v4 - name: Check out shell: cmd @@ -35,7 +35,7 @@ jobs: - name: Environment shell: cmd run: | - call "C:\Program Files (x86)\Microsoft Visual Studio\%VS_VERSION%\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" %PLATFORM% + call "C:\Program Files\Microsoft Visual Studio\%VS_VERSION%\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" %PLATFORM% :: Loop over all environment variables and make them global using set-env. :: See: https://stackoverflow.com/a/39184941 setlocal @@ -60,7 +60,7 @@ jobs: working-directory: C:\CppSharp - name: 'Upload Artifact' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: llvm path: C:\CppSharp\build\llvm\llvm-*-*.* \ No newline at end of file diff --git a/.github/workflows/llvm.yml b/.github/workflows/llvm.yml index aa3ffe278e..d8b3f10b82 100644 --- a/.github/workflows/llvm.yml +++ b/.github/workflows/llvm.yml @@ -9,9 +9,9 @@ jobs: fail-fast: false matrix: config: - - { os: ubuntu-20.04, platform: x64, cxx: g++-9, cc: gcc-9 } - - { os: ubuntu-20.04, platform: x64, cxx: g++-10, cc: gcc-10 } - - { os: macos-10.15, platform: x64, cxx: clang++, cc: clang } + - { os: ubuntu-22.04, platform: x64, cxx: g++-11, cc: gcc-11 } + - { os: macos-11, platform: x64, cxx: clang++, cc: clang } + - { os: macos-12, platform: x64, cxx: clang++, cc: clang } runs-on: ${{ matrix.config.os }} @@ -22,7 +22,7 @@ jobs: ACTIONS_ALLOW_UNSECURE_COMMANDS: true steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - uses: lukka/get-cmake@latest - name: Clone LLVM @@ -38,7 +38,7 @@ jobs: run: build/build.sh package_llvm -platform $PLATFORM - name: 'Upload Artifact' - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: llvm path: build/llvm/llvm-*-*.* \ No newline at end of file diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index ae538fd464..6756de7613 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -73,8 +73,8 @@ jobs: runs-on: windows-2019 needs: build if: | - (github.event_name == 'push' && (github.ref == 'refs/heads/main' || contains(github.ref, 'nuget'))) || - (github.event.pull_request.head.repo.full_name != github.repository && contains(github.event.pull_request.head.ref, 'nuget')) + (github.event_name == 'push' && (github.ref == 'refs/heads/main' || contains(github.ref, 'nuget') || startsWith(github.ref, 'refs/tags/v'))) || + (github.event.pull_request.head.repo.full_name != github.repository && (contains(github.event.pull_request.head.ref, 'nuget') || startsWith(github.event.pull_request.head.ref, 'refs/tags/v'))) env: DOTNET_NOLOGO: true @@ -111,3 +111,9 @@ jobs: run: | cd artifacts dotnet nuget push "*.nupkg" --api-key ${{ secrets.GITHUB_TOKEN }} --source "https://nuget.pkg.github.com/mono/index.json" --skip-duplicate + + - name: Publish package to nuget.org + if: startsWith(github.ref, 'refs/tags/v') + run: | + cd artifacts + dotnet nuget push "*.nupkg" --api-key ${{ secrets.NUGET_API_KEY }} --source "https://api.nuget.org/v3/index.json" --skip-duplicate diff --git a/.gitmodules b/.gitmodules index cababe3d56..e69de29bb2 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +0,0 @@ -[submodule "build/modules/premake-qt"] - path = build/modules/premake-qt - url = https://github.com/dcourtois/premake-qt.git diff --git a/Directory.Build.props b/Directory.Build.props index 69c39a4e28..3fe84b36b1 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -34,7 +34,7 @@ dll "$(MSBuildProgramFiles32)\dotnet\dotnet.exe" "$(ProgramW6432)\dotnet\dotnet.exe" - win + win linux osx $(RID)-$(PlatformTarget) diff --git a/README.md b/README.md index 259d97b950..b3b3a9495c 100644 --- a/README.md +++ b/README.md @@ -76,8 +76,6 @@ Please see the following resources for more information: Feel free to open up issues on Github for any problems you find. -You can also join us at our [#managed-interop](https://gitter.im/managed-interop) Gitter discussion channel. - ## Support For building wrappers and priority support please write to cppsharp@protonmail.com. diff --git a/build/Helpers.lua b/build/Helpers.lua index b68da9a261..68c4c91d3e 100644 --- a/build/Helpers.lua +++ b/build/Helpers.lua @@ -43,11 +43,16 @@ newoption { description = "Only generate configuration file", } +newoption { + trigger = "target-framework", + description = ".NET target framework version", +} + 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"); @@ -61,7 +66,17 @@ msvc_cpp_defines = { } default_gcc_version = "9.0.0" generate_build_config = true premake.path = premake.path .. ";" .. path.join(builddir, "modules") -targetframework = "netcoreapp3.1" + +function string.isempty(s) + return s == nil or s == '' +end + +local function target_framework() + local value = _OPTIONS["target-framework"] + return string.isempty(value) and "net6.0" or value +end + +targetframework = target_framework() function string.starts(str, start) if str == nil then return end diff --git a/build/build.sh b/build/build.sh index de1368dc90..6f7a086fee 100755 --- a/build/build.sh +++ b/build/build.sh @@ -6,6 +6,7 @@ vs=vs2019 configuration=Release build_only=false ci=false +target_framework= verbosity=minimal rootdir="$builddir/.." bindir="$rootdir/bin" @@ -46,7 +47,7 @@ build() generate_config() { - "$builddir/premake.sh" --file="$builddir/premake5.lua" $vs --os=$os --arch=$platform --configuration=$configuration --config_only + "$builddir/premake.sh" --file="$builddir/premake5.lua" $vs --os=$os --arch=$platform --configuration=$configuration --target-framework=$target_framework --config_only } generate() @@ -54,10 +55,10 @@ generate() download_llvm if [ "$os" = "linux" ] || [ "$os" = "macosx" ]; then - "$builddir/premake.sh" --file="$builddir/premake5.lua" gmake2 --os=$os --arch=$platform --configuration=$configuration "$@" + "$builddir/premake.sh" --file="$builddir/premake5.lua" gmake2 --os=$os --arch=$platform --configuration=$configuration --target-framework=$target_framework "$@" fi - "$builddir/premake.sh" --file="$builddir/premake5.lua" $vs --os=$os --arch=$platform --configuration=$configuration + "$builddir/premake.sh" --file="$builddir/premake5.lua" $vs --os=$os --arch=$platform --configuration=$configuration --target-framework=$target_framework } restore() @@ -194,6 +195,11 @@ while [[ $# > 0 ]]; do os=$2 shift ;; + -target-framework) + target_framework=$2 + echo $target_framework + shift + ;; -ci) ci=true export CI=true diff --git a/build/llvm/Directory.Build.props b/build/llvm/Directory.Build.props new file mode 100644 index 0000000000..8d7621c6b0 --- /dev/null +++ b/build/llvm/Directory.Build.props @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/build/llvm/LLVM.lua b/build/llvm/LLVM.lua index fc15650167..30a3943314 100644 --- a/build/llvm/LLVM.lua +++ b/build/llvm/LLVM.lua @@ -53,13 +53,15 @@ end function get_vs_version() local function map_msvc_to_vs_version(major, minor) - if major == "19" and minor >= "20" then return "vs2019" + if major == "19" and minor >= "30" then return "vs2022" + elseif major == "19" and minor >= "20" then return "vs2019" elseif major == "19" and minor >= "10" then return "vs2017" end end local function map_msbuild_to_vs_version(major, minor) - if major == "16" then return "vs2019" + if major == "17" then return "vs2022" + elseif major == "16" then return "vs2019" elseif major == "15" then return "vs2017" end end @@ -379,8 +381,6 @@ function cmake(gen, conf, builddir, options) .. ' -DCLANG_TOOL_C_INDEX_TEST_BUILD=false' .. ' -DCLANG_TOOL_DIAGTOOL_BUILD=false' .. ' -DCLANG_TOOL_DRIVER_BUILD=false' - .. ' -DCLANG_TOOL_HANDLE_CXX_BUILD=false' - .. ' -DCLANG_TOOL_HANDLE_LLVM_BUILD=false' .. ' -DCLANG_TOOL_LIBCLANG_BUILD=false' .. ' -DCLANG_TOOL_SCAN_BUILD_BUILD=false' .. ' -DCLANG_TOOL_SCAN_BUILD_PY_BUILD=false' @@ -399,7 +399,9 @@ end function get_cmake_generator() local vsver = get_vs_version() - if vsver == "vs2019" then + if vsver == "vs2022" then + return "Visual Studio 17 2022", (target_architecture() == "x86") and "-A Win32" or nil + elseif vsver == "vs2019" then return "Visual Studio 16 2019", (target_architecture() == "x86") and "-A Win32" or nil elseif vsver == "vs2017" then return "Visual Studio 15 2017" .. (target_architecture() == "x64" and " Win64" or ""), nil diff --git a/build/modules/premake-qt b/build/modules/premake-qt deleted file mode 160000 index 0ddc49715c..0000000000 --- a/build/modules/premake-qt +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 0ddc49715c7892211774d4b5e705a7c5559aeed4 diff --git a/build/premake5.lua b/build/premake5.lua index 7139ba02cd..f7b10fc24d 100644 --- a/build/premake5.lua +++ b/build/premake5.lua @@ -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 diff --git a/docs/GettingStarted.md b/docs/GettingStarted.md index ff8017b4a3..a6711727f0 100644 --- a/docs/GettingStarted.md +++ b/docs/GettingStarted.md @@ -35,27 +35,46 @@ make sure those are installed on your system. ## Compiling on Windows/Visual Studio +The following steps should be called from the VS developer command prompt. + 1. Generate the VS solution ```shell cd \build - ./build.sh generate -configuration Release -platform x64 + build.sh generate -configuration Release -platform x64 ``` +> :information_source: You can use the `-target-framework` option to target any valid .NET target framework. + 2. Compile the VS projects You can open `CppSharp.sln` and hit F5 or compile via the command line: ``` - ./build.sh -configuration Release -platform x64 + build.sh -configuration Release -platform x64 ``` Building in *Release* is recommended because else we will use the Clang parser debug configuration, which will be too slow for practical use beyond debugging. +The solution generated will be for Visual Studio 2019. + +If you have a more recent version of Visual Studio, you can either: +- install Visual Studio 2019 +- install Visual Studio 2019 build tools, from [Visual Studio Installer](https://visualstudio.microsoft.com/downloads/) + - select the payload *MSVC v142 - VS 2019 C++ x64/x86 build tools (v14.29-16.11)* + +Please note that Windows isn't natively able to run sh scripts, to remediate this, you can either: + +- use the one from Visual Studio if present + - e.g. `C:\Program Files\Microsoft Visual Studio\2022\Enterprise\Common7\IDE\CommonExtensions\Microsoft\TeamFoundation\Team Explorer\Git\usr\bin\sh.exe` +- use the one from [Git for Windows](https://gitforwindows.org/) + - e.g. `C:\Program Files\Git\bin\sh.exe` + +When opening the solution for the first time on a more recent version than Visual Studio 2019, you will be prompted to retarget projects to one of the platform toolset available on your system. + ## Compiling on macOS or Linux -The following steps should be called from the VS developer command prompt. 1. Generate the VS solution and makefiles @@ -65,6 +84,8 @@ The following steps should be called from the VS developer command prompt. ./build.sh generate -configuration Release -platform x64 ``` +> :information_source: You can use the `-target-framework` option to target any valid .NET target framework. + 2. Compile the csproj files and makefiles ``` diff --git a/docs/UsersManual.md b/docs/UsersManual.md index bd4865f93d..0c45a91acb 100644 --- a/docs/UsersManual.md +++ b/docs/UsersManual.md @@ -39,6 +39,7 @@ There is also experimental support for these JavaScript-related targets: - N-API (Node.js) - QuickJS - TypeScript +- Emscripten # 3. Native Targets diff --git a/examples/Parser/Parser.cs b/examples/Parser/Parser.cs index a39518cdd2..bbad7b6ce7 100644 --- a/examples/Parser/Parser.cs +++ b/examples/Parser/Parser.cs @@ -23,12 +23,12 @@ public static void Main(string[] args) ParseSourceFile(file); } - public static bool ParseSourceFile(string file) + private static bool ParseSourceFile(string file) { // Lets setup the options for parsing the file. var parserOptions = new ParserOptions { - LanguageVersion = LanguageVersion.CPP11, + LanguageVersion = LanguageVersion.CPP20_GNU, // Verbose here will make sure the parser outputs some extra debugging // information regarding include directories, which can be helpful when @@ -37,13 +37,10 @@ public static bool ParseSourceFile(string file) }; // This will setup the necessary system include paths and arguments for parsing. - // It will probe into the registry (on Windows) and filesystem to find the paths - // of the system toolchains and necessary include directories. - parserOptions.Setup(); + parserOptions.Setup(Platform.Host); // We create the Clang parser and parse the source code. - var parser = new ClangParser(); - var parserResult = parser.ParseSourceFile(file, parserOptions); + var parserResult = ClangParser.ParseSourceFile(file, parserOptions); // If there was some kind of error parsing, then lets print some diagnostics. if (parserResult.Kind != ParserResultKind.Success) diff --git a/src/AST/ASTContext.cs b/src/AST/ASTContext.cs index 9aafd38a23..827ce261f4 100644 --- a/src/AST/ASTContext.cs +++ b/src/AST/ASTContext.cs @@ -11,7 +11,8 @@ public enum CppAbi Microsoft, ARM, iOS, - iOS64 + iOS64, + WebAssembly } /// diff --git a/src/AST/Class.cs b/src/AST/Class.cs index 2b1206a7ff..535236e350 100644 --- a/src/AST/Class.cs +++ b/src/AST/Class.cs @@ -291,6 +291,11 @@ public Method FindMethodByUSR(string usr) .FirstOrDefault(m => m.USR == usr); } + public Variable FindVariable(string name) + { + return Variables.FirstOrDefault(m => m.Name == name); + } + public override T Visit(IDeclVisitor visitor) { return visitor.VisitClassDecl(this); diff --git a/src/AST/ClassLayout.cs b/src/AST/ClassLayout.cs index f22a278d92..06d97e47c8 100644 --- a/src/AST/ClassLayout.cs +++ b/src/AST/ClassLayout.cs @@ -31,14 +31,7 @@ public struct VTableComponent public Declaration Declaration; /// Method declaration (if Kind == FunctionPointer). - public Method Method - { - get - { - Debug.Assert(Kind == VTableComponentKind.FunctionPointer); - return Declaration as Method; - } - } + public Method Method => Declaration as Method; } /// diff --git a/src/AST/Declaration.cs b/src/AST/Declaration.cs index 02176d6a87..2fc50d3122 100644 --- a/src/AST/Declaration.cs +++ b/src/AST/Declaration.cs @@ -189,15 +189,16 @@ public virtual string Name public static string QualifiedNameSeparator = "::"; public string GetQualifiedName(Func getName, - Func getNamespace) + Func getNamespace, bool getOriginal) { - if (Namespace == null) + DeclarationContext @namespace = getNamespace(this); + if (@namespace == null) return getName(this); - if (Namespace.IsRoot) + if (@namespace.IsRoot) return getName(this); - var namespaces = GatherNamespaces(getNamespace(this)); + var namespaces = GatherNamespaces(@namespace, getOriginal); var names = namespaces.Select(getName).ToList(); names.Add(getName(this)); @@ -206,7 +207,7 @@ public string GetQualifiedName(Func getName, return string.Join(QualifiedNameSeparator, names); } - public static IEnumerable GatherNamespaces(DeclarationContext @namespace) + public static IEnumerable GatherNamespaces(DeclarationContext @namespace, bool getOriginal) { var namespaces = new Stack(); @@ -216,7 +217,7 @@ public static IEnumerable GatherNamespaces(DeclarationContext @name var isInlineNamespace = currentNamespace is Namespace { IsInline: true }; if (!isInlineNamespace) namespaces.Push(currentNamespace); - currentNamespace = currentNamespace.Namespace; + currentNamespace = getOriginal ? currentNamespace.OriginalNamespace : currentNamespace.Namespace; } return namespaces; @@ -226,7 +227,7 @@ public string QualifiedName { get { - return GetQualifiedName(decl => GetDeclName(decl, decl.Name), decl => decl.Namespace); + return GetQualifiedName(decl => GetDeclName(decl, decl.Name), decl => decl.Namespace, false); } } @@ -235,7 +236,7 @@ public string QualifiedOriginalName get { return GetQualifiedName( - decl => GetDeclName(decl, decl.OriginalName), decl => decl.OriginalNamespace); + decl => GetDeclName(decl, decl.OriginalName), decl => decl.OriginalNamespace, true); } } @@ -244,7 +245,7 @@ public string QualifiedLogicalName get { return GetQualifiedName( - decl => GetDeclName(decl, decl.LogicalName), decl => decl.Namespace); + decl => GetDeclName(decl, decl.LogicalName), decl => decl.Namespace, false); } } @@ -253,7 +254,7 @@ public string QualifiedLogicalOriginalName get { return GetQualifiedName( - decl => GetDeclName(decl, decl.LogicalOriginalName), decl => decl.OriginalNamespace); + decl => GetDeclName(decl, decl.LogicalOriginalName), decl => decl.OriginalNamespace, true); } } diff --git a/src/AST/Property.cs b/src/AST/Property.cs index 9b78ea7dee..f0c469a3cb 100644 --- a/src/AST/Property.cs +++ b/src/AST/Property.cs @@ -22,109 +22,62 @@ public Property(Property property) 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 parameters = new List(); + private readonly List parameters = new(); /// /// Only applicable to index ([]) properties. /// - public List Parameters - { - get { return parameters; } - } + public List 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(IDeclVisitor visitor) { diff --git a/src/AST/Template.cs b/src/AST/Template.cs index 062254ee80..e71ee5b815 100644 --- a/src/AST/Template.cs +++ b/src/AST/Template.cs @@ -124,6 +124,8 @@ public class NonTypeTemplateParameter : Declaration /// public bool IsExpandedParameterPack { get; set; } + public QualifiedType Type { get; set; } + public override T Visit(IDeclVisitor visitor) { return visitor.VisitNonTypeTemplateParameterDecl(this); diff --git a/src/AST/Type.cs b/src/AST/Type.cs index 831b9f677b..d686f5d9a3 100644 --- a/src/AST/Type.cs +++ b/src/AST/Type.cs @@ -30,7 +30,7 @@ public abstract T Visit(ITypeVisitor visitor, TypeQualifiers quals public override string ToString() { - return TypePrinterDelegate(this); + return TypePrinterDelegate == null ? base.ToString() : TypePrinterDelegate(this); } public abstract object Clone(); diff --git a/src/AST/TypeExtensions.cs b/src/AST/TypeExtensions.cs index eb447d09fa..32333d6e6b 100644 --- a/src/AST/TypeExtensions.cs +++ b/src/AST/TypeExtensions.cs @@ -92,6 +92,25 @@ public static bool IsPointerToPrimitiveType(this Type t, PrimitiveType primitive return ptr.Pointee.IsPrimitiveType(primitive); } + public static bool IsPointerToEnum(this Type t) + { + var ptr = t as PointerType; + if (ptr == null) + return false; + return ptr.Pointee.IsEnumType(); + } + + public static bool IsPointerToEnum(this Type t, out Enumeration @enum) + { + var ptr = t as PointerType; + if (ptr == null) + { + @enum = null; + return false; + } + return ptr.Pointee.TryGetEnum(out @enum); + } + public static bool IsPointerTo(this Type t, out T type) where T : Type { var pointee = t.GetPointee(); diff --git a/src/ASTViewer/AstModel.cpp b/src/ASTViewer/AstModel.cpp deleted file mode 100644 index e0d8a388d9..0000000000 --- a/src/ASTViewer/AstModel.cpp +++ /dev/null @@ -1,141 +0,0 @@ -#include "AstModel.h" -#include - - -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(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(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(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(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(parent.internalPointer()); - else - parentItem = rootItem; - - return !parentItem->myChidren.empty(); - -} - diff --git a/src/ASTViewer/AstModel.h b/src/ASTViewer/AstModel.h deleted file mode 100644 index 3c6c46a56b..0000000000 --- a/src/ASTViewer/AstModel.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include -#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; -}; \ No newline at end of file diff --git a/src/ASTViewer/AstReader.cpp b/src/ASTViewer/AstReader.cpp deleted file mode 100644 index 4b07a8edad..0000000000 --- a/src/ASTViewer/AstReader.cpp +++ /dev/null @@ -1,543 +0,0 @@ -#include "AstReader.h" -#include -#include "CommandLineSplitter.h" -#include -#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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#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(""; - } -} - - - -GenericAstNode::GenericAstNode() : -myParent(nullptr), hasDetails(false) -{ - -} - -int GenericAstNode::findChildIndex(GenericAstNode *node) -{ - auto it = std::find_if(myChidren.begin(), myChidren.end(), [node](std::unique_ptr const & n){return n.get() == node; }); - return it == myChidren.end() ? - -1 : - it - myChidren.begin(); -} - -void GenericAstNode::attach(std::unique_ptr child) -{ - child->myParent = this; - myChidren.push_back(std::move(child)); -} - -//struct SourceRangeVisitor : boost::static_visitor -//{ -// template -// 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 &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 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 -{ -public: - using PARENT = clang::RecursiveASTVisitor; - 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(ND->getDeclContext())) - { - if (funcContext->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) - { - return ""; - } - } - - std::vector containers; - auto currentElement = dyn_cast(ND->getDeclContext()); - while (currentElement) - { - containers.push_back(currentElement); - currentElement = dyn_cast(currentElement->getDeclContext()); - } - for (auto tag : containers) - { - if (auto partialSpe = dyn_cast(tag)) - { - return "getNameAsString() + ": " + ND->getNameAsString() + ">"; - } - else if (auto recContext = dyn_cast(tag)) - { - if (recContext->getDescribedClassTemplate() != nullptr) - { - return "getNameAsString() + ": " + ND->getNameAsString() + ">"; - } - } - } - - auto mangleContext = std::unique_ptr{ND->getASTContext().createMangleContext()}; - std::string FrontendBuf; - llvm::raw_string_ostream FrontendBufOS(FrontendBuf); - - if (auto ctor = dyn_cast(ND)) - { - mangleContext->mangleCXXCtor(ctor, CXXCtorType::Ctor_Complete, FrontendBufOS); - } - else if (auto dtor = dyn_cast(ND)) - { - mangleContext->mangleCXXDtor(dtor, CXXDtorType::Dtor_Complete, FrontendBufOS); - } - else if (mangleContext->shouldMangleDeclName(ND) && !isa(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(); - node->myAstNode = decl; - node->name = decl->getDeclKindName() + std::string("Decl"); // Try to mimick clang default dump - if (auto *FD = dyn_cast(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(FD); - containingClass = cast(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(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(decl)) - { - if (auto *PFD = dyn_cast_or_null(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(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(decl)) - { - node->setProperty(props::Name, ECD->getNameAsString()); - node->setProperty(props::Value, ECD->getInitVal().toString(10)); - } - else if (auto *tag = dyn_cast(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(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(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(); - 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(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(); - //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 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> const &candidates, int position) -{ - for (auto &candidate : candidates) - { - std::pair location; - if (!candidate->getRangeInMainFile(location, getManager(), getContext())) - { - continue; - } - if (location.first <= position && position <= location.second) - { - return candidate.get(); - } - } - return nullptr; -} - -std::vector AstReader::getBestNodeMatchingPosition(int position) -{ - std::vector 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(); - auto root = std::make_unique(); - 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; -} - diff --git a/src/ASTViewer/AstReader.h b/src/ASTViewer/AstReader.h deleted file mode 100644 index 3796aa9b22..0000000000 --- a/src/ASTViewer/AstReader.h +++ /dev/null @@ -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 -#include - - -class GenericAstNode -{ -public: - GenericAstNode(); - int findChildIndex(GenericAstNode *node); // Return -1 if not found - void attach(std::unique_ptr child); - std::string name; - std::vector> myChidren; - bool getRangeInMainFile(std::pair &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; - void setProperty(std::string const &propertyName, std::string const &value); - Properties const &getProperties() const; - std::variant myAstNode; - GenericAstNode *myParent; - - bool hasDetails; - std::string detailsTitle; - std::string details; - std::function 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 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> const &candidates, int position); - std::string args; - std::string mySourceCode; // Needs to stay alive while we navigate the tree - std::unique_ptr myAst; - std::unique_ptr myArtificialRoot; // We need an artificial root on top of the real root, because the root is not displayed by Qt - bool isReady; -}; - diff --git a/src/ASTViewer/ClangUtilities/StringLiteralExtractor.cpp b/src/ASTViewer/ClangUtilities/StringLiteralExtractor.cpp deleted file mode 100644 index 70f601270d..0000000000 --- a/src/ASTViewer/ClangUtilities/StringLiteralExtractor.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include -#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 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(SrcBytes.begin()); - const UTF32 *SrcEnd = reinterpret_cast(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(&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(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 -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 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 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 diff --git a/src/ASTViewer/ClangUtilities/StringLiteralExtractor.h b/src/ASTViewer/ClangUtilities/StringLiteralExtractor.h deleted file mode 100644 index 72d7ca264c..0000000000 --- a/src/ASTViewer/ClangUtilities/StringLiteralExtractor.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once - -#include -#include -#pragma warning (push) -#pragma warning (disable:4100 4127 4800 4512 4245 4291 4510 4610 4324 4267 4244 4996 4146) -#include -#include -#include -#include -#include -#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 SrcBytes, std::string &Out); - - -std::vector -splitStringLiteral(clang::StringLiteral *S, const clang::SourceManager &SM, const clang::LangOptions &Features, const clang::TargetInfo &Target); - -} // namespace clang_utilities - diff --git a/src/ASTViewer/ClangUtilities/TemplateUtilities.cpp b/src/ASTViewer/ClangUtilities/TemplateUtilities.cpp deleted file mode 100644 index 1aa554994f..0000000000 --- a/src/ASTViewer/ClangUtilities/TemplateUtilities.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#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()) { - 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(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(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(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()) { - 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(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 diff --git a/src/ASTViewer/ClangUtilities/TemplateUtilities.h b/src/ASTViewer/ClangUtilities/TemplateUtilities.h deleted file mode 100644 index 60b4fb113f..0000000000 --- a/src/ASTViewer/ClangUtilities/TemplateUtilities.h +++ /dev/null @@ -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 -#include -#include -#include -#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 - diff --git a/src/ASTViewer/CommandLineSplitter.cpp b/src/ASTViewer/CommandLineSplitter.cpp deleted file mode 100644 index a0ea6ccc58..0000000000 --- a/src/ASTViewer/CommandLineSplitter.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#ifdef _WIN32 -#include -#else -#include -#endif - -#include -#include -#include - -std::vector splitCommandLine(std::string const &cmdline) -{ - int i; - char **argv = NULL; - int argc; - std::vector 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(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(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 -} \ No newline at end of file diff --git a/src/ASTViewer/CommandLineSplitter.h b/src/ASTViewer/CommandLineSplitter.h deleted file mode 100644 index 0f59566b18..0000000000 --- a/src/ASTViewer/CommandLineSplitter.h +++ /dev/null @@ -1,6 +0,0 @@ -#pragma once - -#include -#include - -std::vector splitCommandLine(std::string const &cmdline); diff --git a/src/ASTViewer/Highlighter.cpp b/src/ASTViewer/Highlighter.cpp deleted file mode 100644 index a225857811..0000000000 --- a/src/ASTViewer/Highlighter.cpp +++ /dev/null @@ -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] diff --git a/src/ASTViewer/Highlighter.h b/src/ASTViewer/Highlighter.h deleted file mode 100644 index a034194dff..0000000000 --- a/src/ASTViewer/Highlighter.h +++ /dev/null @@ -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 -#include - -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 highlightingRules; - - QRegExp commentStartExpression; - QRegExp commentEndExpression; - - QTextCharFormat keywordFormat; - QTextCharFormat classFormat; - QTextCharFormat singleLineCommentFormat; - QTextCharFormat multiLineCommentFormat; - QTextCharFormat quotationFormat; - QTextCharFormat functionFormat; -}; -//! [0] - -#endif // HIGHLIGHTER_H diff --git a/src/ASTViewer/LICENSE b/src/ASTViewer/LICENSE deleted file mode 100644 index 65c5ca88a6..0000000000 --- a/src/ASTViewer/LICENSE +++ /dev/null @@ -1,165 +0,0 @@ - GNU LESSER GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - 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. diff --git a/src/ASTViewer/MainWindow.cpp b/src/ASTViewer/MainWindow.cpp deleted file mode 100644 index a9c489921d..0000000000 --- a/src/ASTViewer/MainWindow.cpp +++ /dev/null @@ -1,169 +0,0 @@ -#include "MainWindow.h" -#include -#include -#include -#include -#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(); - auto &manager = myReader.getManager(); - std::pair 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(); - 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(); - 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(); -} - diff --git a/src/ASTViewer/MainWindow.h b/src/ASTViewer/MainWindow.h deleted file mode 100644 index ed076e2504..0000000000 --- a/src/ASTViewer/MainWindow.h +++ /dev/null @@ -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 myDetailWindows; - bool isUpdateInProgress; -}; diff --git a/src/ASTViewer/MainWindow.ui b/src/ASTViewer/MainWindow.ui deleted file mode 100644 index eb716cc7f6..0000000000 --- a/src/ASTViewer/MainWindow.ui +++ /dev/null @@ -1,151 +0,0 @@ - - - MainWindow - - - - 0 - 0 - 800 - 600 - - - - Clang AST viewer - - - - - - - - Consolas - 10 - - - - selection-background-color: rgb(170, 85, 255); -selection-color: white - - - 25 - - - - - - - - - 0 - 0 - 800 - 21 - - - - - - - Clang AST - - - 2 - - - - - - - false - - - QTreeView::item:selected { color:white; background:rgb(170, 85, 255); } - - - 10 - - - true - - - - - - - - - toolBar - - - TopToolBarArea - - - false - - - - - - Command line arguments - - - 8 - - - - - - - -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 - - - - - - - - - Properties - - - 2 - - - - - - - 2 - - - - 1 - - - - - 2 - - - - - - - - Show details - - - - - - - - - Refresh - - - - - - diff --git a/src/ASTViewer/README.md b/src/ASTViewer/README.md deleted file mode 100644 index faa3af271f..0000000000 --- a/src/ASTViewer/README.md +++ /dev/null @@ -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. \ No newline at end of file diff --git a/src/ASTViewer/main.cpp b/src/ASTViewer/main.cpp deleted file mode 100644 index 14dfa7f717..0000000000 --- a/src/ASTViewer/main.cpp +++ /dev/null @@ -1,14 +0,0 @@ -#include -#include -#include "MainWindow.h" - -int main(int argc, char **argv) -{ - QApplication app (argc, argv); - - MainWindow mainWindow; - mainWindow.show(); - - return app.exec(); -} - diff --git a/src/ASTViewer/premake5.lua b/src/ASTViewer/premake5.lua deleted file mode 100644 index f27afaa992..0000000000 --- a/src/ASTViewer/premake5.lua +++ /dev/null @@ -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" } diff --git a/src/CLI/CLI.cs b/src/CLI/CLI.cs index 54b2ed6c5d..44889307cb 100644 --- a/src/CLI/CLI.cs +++ b/src/CLI/CLI.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using CppSharp.Generators; using Mono.Options; namespace CppSharp @@ -15,11 +16,11 @@ static bool ParseCommandLineArgs(string[] args, List errorMessages, ref { var showHelp = false; - optionSet.Add("I=", "the {PATH} of a folder to search for include files", (i) => { AddIncludeDirs(i, errorMessages); }); + optionSet.Add("I=", "the {PATH} of a folder to search for include files", i => { AddIncludeDirs(i, errorMessages); }); optionSet.Add("l=", "{LIBRARY} that that contains the symbols of the generated code", l => options.Libraries.Add(l)); optionSet.Add("L=", "the {PATH} of a folder to search for additional libraries", l => options.LibraryDirs.Add(l)); optionSet.Add("D:", "additional define with (optional) value to add to be used while parsing the given header files", (n, v) => AddDefine(n, v, errorMessages)); - optionSet.Add("A=", "additional Clang arguments to pass to the compiler while parsing the given header files", (v) => AddArgument(v, errorMessages)); + optionSet.Add("A=", "additional Clang arguments to pass to the compiler while parsing the given header files", v => AddArgument(v, errorMessages)); optionSet.Add("o=|output=", "the {PATH} for the generated bindings file (doesn't need the extension since it will depend on the generator)", v => HandleOutputArg(v, errorMessages)); optionSet.Add("on=|outputnamespace=", "the {NAMESPACE} that will be used for the generated code", on => options.OutputNamespace = on); @@ -30,8 +31,8 @@ static bool ParseCommandLineArgs(string[] args, List errorMessages, ref optionSet.Add("d|debug", "enables debug mode which generates more verbose code to aid debugging", v => options.Debug = true); optionSet.Add("c|compile", "enables automatic compilation of the generated code", v => options.Compile = true); optionSet.Add("g=|gen=|generator=", "the {TYPE} of generated code: 'csharp' or 'cli' ('cli' supported only for Windows)", g => { GetGeneratorKind(g, errorMessages); }); - optionSet.Add("p=|platform=", "the {PLATFORM} that the generated code will target: 'win', 'osx' or 'linux'", p => { GetDestinationPlatform(p, errorMessages); }); - optionSet.Add("a=|arch=", "the {ARCHITECTURE} that the generated code will target: 'x86' or 'x64'", a => { GetDestinationArchitecture(a, errorMessages); }); + optionSet.Add("p=|platform=", "the {PLATFORM} that the generated code will target: 'win', 'osx' or 'linux' or 'emscripten'", p => { GetDestinationPlatform(p, errorMessages); }); + optionSet.Add("a=|arch=", "the {ARCHITECTURE} that the generated code will target: 'x86' or 'x64' or 'wasm32' or 'wasm64'", a => { GetDestinationArchitecture(a, errorMessages); }); optionSet.Add("prefix=", "sets a string prefix to the names of generated files", a => { options.Prefix = a; }); optionSet.Add("exceptions", "enables support for C++ exceptions in the parser", v => { options.EnableExceptions = true; }); @@ -208,26 +209,29 @@ static void GetGeneratorKind(string generator, List errorMessages) switch (generator.ToLower()) { case "csharp": - options.Kind = CppSharp.Generators.GeneratorKind.CSharp; + options.Kind = GeneratorKind.CSharp; return; case "cli": - options.Kind = CppSharp.Generators.GeneratorKind.CLI; + options.Kind = GeneratorKind.CLI; return; case "c": - options.Kind = CppSharp.Generators.GeneratorKind.C; + options.Kind = GeneratorKind.C; return; case "cpp": - options.Kind = CppSharp.Generators.GeneratorKind.CPlusPlus; + options.Kind = GeneratorKind.CPlusPlus; return; case "napi": - options.Kind = CppSharp.Generators.GeneratorKind.NAPI; + options.Kind = GeneratorKind.NAPI; return; case "qjs": - options.Kind = CppSharp.Generators.GeneratorKind.QuickJS; + options.Kind = GeneratorKind.QuickJS; return; case "ts": case "typescript": - options.Kind = CppSharp.Generators.GeneratorKind.TypeScript; + options.Kind = GeneratorKind.TypeScript; + return; + case "emscripten": + options.Kind = GeneratorKind.Emscripten; return; } @@ -247,6 +251,9 @@ static void GetDestinationPlatform(string platform, List errorMessages) case "linux": options.Platform = TargetPlatform.Linux; return; + case "emscripten": + options.Platform = TargetPlatform.Emscripten; + return; } errorMessages.Add($"Unknown target platform: {platform}. Defaulting to {options.Platform}"); @@ -262,6 +269,12 @@ static void GetDestinationArchitecture(string architecture, List errorMe case "x64": options.Architecture = TargetArchitecture.x64; return; + case "wasm32": + options.Architecture = TargetArchitecture.WASM32; + return; + case "wasm64": + options.Architecture = TargetArchitecture.WASM64; + return; } errorMessages.Add($"Unknown target architecture: {architecture}. Defaulting to {options.Architecture}"); @@ -286,9 +299,9 @@ static void Main(string[] args) return; } - Generator gen = new Generator(options); + var gen = new Generator(options); - bool validOptions = gen.ValidateOptions(errorMessages); + var validOptions = gen.ValidateOptions(errorMessages); PrintErrorMessages(errorMessages); if (errorMessages.Any() || !validOptions) diff --git a/src/CLI/Generator.cs b/src/CLI/Generator.cs index 5c6f72be77..58db9ac72d 100644 --- a/src/CLI/Generator.cs +++ b/src/CLI/Generator.cs @@ -13,58 +13,64 @@ namespace CppSharp { class Generator : ILibrary { - private Options options = null; + private readonly Options options; private string triple = ""; private CppAbi abi = CppAbi.Microsoft; public Generator(Options options) { - if (options == null) - throw new ArgumentNullException(nameof(options)); - - this.options = options; - } - - static TargetPlatform GetCurrentPlatform() - { - if (Platform.IsWindows) - return TargetPlatform.Windows; - - if (Platform.IsMacOS) - return TargetPlatform.MacOS; - - if (Platform.IsLinux) - return TargetPlatform.Linux; - - throw new System.NotImplementedException("Unknown host platform"); + this.options = options ?? throw new ArgumentNullException(nameof(options)); } void SetupTargetTriple() { var tripleBuilder = new StringBuilder(); - if (options.Architecture == TargetArchitecture.x64) - tripleBuilder.Append("x86_64-"); - else if (options.Architecture == TargetArchitecture.x86) - tripleBuilder.Append("i686-"); - - if (options.Platform == TargetPlatform.Windows) - { - tripleBuilder.Append("pc-win32-msvc"); - abi = CppAbi.Microsoft; - } - else if (options.Platform == TargetPlatform.MacOS) + switch (options.Architecture) { - tripleBuilder.Append("apple-darwin12.4.0"); - abi = CppAbi.Itanium; + case TargetArchitecture.x64: + tripleBuilder.Append("x86_64-"); + break; + case TargetArchitecture.x86: + tripleBuilder.Append("i686-"); + break; + case TargetArchitecture.WASM32: + tripleBuilder.Append("wasm32-"); + break; + case TargetArchitecture.WASM64: + tripleBuilder.Append("wasm64-"); + break; } - else if (options.Platform == TargetPlatform.Linux) - { - tripleBuilder.Append("linux-gnu"); - abi = CppAbi.Itanium; - if (options.Cpp11ABI) - tripleBuilder.Append("-cxx11abi"); + switch (options.Platform) + { + case TargetPlatform.Windows: + tripleBuilder.Append("pc-win32-msvc"); + abi = CppAbi.Microsoft; + break; + case TargetPlatform.MacOS: + tripleBuilder.Append("apple-darwin12.4.0"); + abi = CppAbi.Itanium; + break; + case TargetPlatform.Linux: + { + tripleBuilder.Append("linux-gnu"); + abi = CppAbi.Itanium; + + if (options.Cpp11ABI) + tripleBuilder.Append("-cxx11abi"); + break; + } + case TargetPlatform.Emscripten: + { + if (options.Architecture != TargetArchitecture.WASM32 && + options.Architecture != TargetArchitecture.WASM64) + throw new Exception("Emscripten target is only compatible with WASM architectures"); + + tripleBuilder.Append("unknown-emscripten"); + abi = CppAbi.Itanium; + break; + } } triple = tripleBuilder.ToString(); @@ -78,8 +84,7 @@ public bool ValidateOptions(List messages) return false; } - if (!options.Platform.HasValue) - options.Platform = GetCurrentPlatform(); + options.Platform ??= Platform.Host; if (string.IsNullOrEmpty(options.OutputDir)) { @@ -103,6 +108,9 @@ public bool ValidateOptions(List messages) if (string.IsNullOrEmpty(options.OutputNamespace)) options.OutputNamespace = moduleName; + if (options.IncludeDirs.Count == 0) + options.IncludeDirs.Add(Path.GetDirectoryName(options.HeaderFiles.First())); + SetupTargetTriple(); return true; @@ -133,7 +141,7 @@ public void Setup(Driver driver) parserOptions.UnityBuild = options.UnityBuild; parserOptions.EnableRTTI = options.EnableRTTI; - parserOptions.Setup(); + parserOptions.Setup(options.Platform ?? Platform.Host); if (triple.Contains("linux")) SetupLinuxOptions(parserOptions); @@ -189,7 +197,7 @@ public void Postprocess(Driver driver, ASTContext ctx) public void Run() { - StringBuilder messageBuilder = new StringBuilder(); + var messageBuilder = new StringBuilder(); messageBuilder.Append($"Generating {GetGeneratorKindName(options.Kind)}"); messageBuilder.Append($" bindings for {GetPlatformName(options.Platform)} {options.Architecture}"); diff --git a/src/CLI/Options.cs b/src/CLI/Options.cs index f679287c0f..bbcb2f3894 100644 --- a/src/CLI/Options.cs +++ b/src/CLI/Options.cs @@ -6,7 +6,9 @@ namespace CppSharp enum TargetArchitecture { x86, - x64 + x64, + WASM32, + WASM64 } class Options diff --git a/src/Core/Platform.cs b/src/Core/Platform.cs index d0500f290f..90740dfc66 100644 --- a/src/Core/Platform.cs +++ b/src/Core/Platform.cs @@ -11,7 +11,8 @@ public enum TargetPlatform MacOS, iOS, WatchOS, - TVOS + TVOS, + Emscripten, } public static class Platform diff --git a/src/CppParser/AST.cpp b/src/CppParser/AST.cpp index d0442df015..ae9e176360 100644 --- a/src/CppParser/AST.cpp +++ b/src/CppParser/AST.cpp @@ -164,6 +164,7 @@ NonTypeTemplateParameter::NonTypeTemplateParameter(const NonTypeTemplateParamete , position(rhs.position) , isPackExpansion(rhs.isPackExpansion) , isExpandedParameterPack(rhs.isExpandedParameterPack) + , type(rhs.type) { } diff --git a/src/CppParser/Bindings/CLI/Decl.cpp b/src/CppParser/Bindings/CLI/Decl.cpp index 2465c7ef4e..3de0e48dec 100644 --- a/src/CppParser/Bindings/CLI/Decl.cpp +++ b/src/CppParser/Bindings/CLI/Decl.cpp @@ -4224,6 +4224,18 @@ void CppSharp::Parser::AST::NonTypeTemplateParameter::IsExpandedParameterPack::s ((class ::CppSharp::CppParser::AST::NonTypeTemplateParameter*)NativePtr)->isExpandedParameterPack = value; } +CppSharp::Parser::AST::QualifiedType^ CppSharp::Parser::AST::NonTypeTemplateParameter::Type::get() +{ + return (&((class ::CppSharp::CppParser::AST::NonTypeTemplateParameter*)NativePtr)->type == nullptr) ? nullptr : gcnew ::CppSharp::Parser::AST::QualifiedType((struct ::CppSharp::CppParser::AST::QualifiedType*)&((class ::CppSharp::CppParser::AST::NonTypeTemplateParameter*)NativePtr)->type); +} + +void CppSharp::Parser::AST::NonTypeTemplateParameter::Type::set(CppSharp::Parser::AST::QualifiedType^ value) +{ + if (ReferenceEquals(value, nullptr)) + throw gcnew ::System::ArgumentNullException("value", "Cannot be null because it is passed by value."); + ((class ::CppSharp::CppParser::AST::NonTypeTemplateParameter*)NativePtr)->type = *(struct ::CppSharp::CppParser::AST::QualifiedType*)value->NativePtr; +} + CppSharp::Parser::AST::ClassTemplate::ClassTemplate(class ::CppSharp::CppParser::AST::ClassTemplate* native) : CppSharp::Parser::AST::Template((::CppSharp::CppParser::AST::Template*)native) { diff --git a/src/CppParser/Bindings/CLI/Decl.h b/src/CppParser/Bindings/CLI/Decl.h index a96a160c8a..8c9044c774 100644 --- a/src/CppParser/Bindings/CLI/Decl.h +++ b/src/CppParser/Bindings/CLI/Decl.h @@ -256,7 +256,8 @@ namespace CppSharp Microsoft = 1, ARM = 2, iOS = 3, - iOS64 = 4 + iOS64 = 4, + WebAssembly = 5 }; public enum class RecordArgABI @@ -2097,6 +2098,12 @@ namespace CppSharp bool get(); void set(bool); } + + property CppSharp::Parser::AST::QualifiedType^ Type + { + CppSharp::Parser::AST::QualifiedType^ get(); + void set(CppSharp::Parser::AST::QualifiedType^); + } }; public ref class ClassTemplate : CppSharp::Parser::AST::Template diff --git a/src/CppParser/Bindings/CSharp/CppSharp.Parser.CSharp.csproj b/src/CppParser/Bindings/CSharp/CppSharp.Parser.CSharp.csproj index b026b257be..cb09d65642 100644 --- a/src/CppParser/Bindings/CSharp/CppSharp.Parser.CSharp.csproj +++ b/src/CppParser/Bindings/CSharp/CppSharp.Parser.CSharp.csproj @@ -5,6 +5,7 @@ true true true + 0109 x86_64-pc-win32-msvc x86_64-linux-gnu-cxx11abi x86_64-linux-gnu diff --git a/src/CppParser/Bindings/CSharp/i686-apple-darwin12.4.0/CppSharp.CppParser.cs b/src/CppParser/Bindings/CSharp/i686-apple-darwin12.4.0/CppSharp.CppParser.cs index f12e2fa508..5fcdfc4ebd 100644 --- a/src/CppParser/Bindings/CSharp/i686-apple-darwin12.4.0/CppSharp.CppParser.cs +++ b/src/CppParser/Bindings/CSharp/i686-apple-darwin12.4.0/CppSharp.CppParser.cs @@ -6301,7 +6301,8 @@ public enum CppAbi Microsoft = 1, ARM = 2, iOS = 3, - iOS64 = 4 + iOS64 = 4, + WebAssembly = 5 } public enum RecordArgABI @@ -13016,6 +13017,7 @@ public unsafe partial class NonTypeTemplateParameter : global::CppSharp.Parser.A internal uint position; internal byte isPackExpansion; internal byte isExpandedParameterPack; + internal global::CppSharp.Parser.AST.QualifiedType.__Internal type; [SuppressUnmanagedCodeSecurity, DllImport("CppSharp.CppParser", EntryPoint = "_ZN8CppSharp9CppParser3AST24NonTypeTemplateParameterC2Ev", CallingConvention = __CallingConvention.Cdecl)] internal static extern void ctor(__IntPtr __instance); @@ -13170,6 +13172,21 @@ public bool IsExpandedParameterPack ((__Internal*)__Instance)->isExpandedParameterPack = (byte) (value ? 1 : 0); } } + + public global::CppSharp.Parser.AST.QualifiedType Type + { + get + { + return global::CppSharp.Parser.AST.QualifiedType.__CreateInstance(new __IntPtr(&((__Internal*)__Instance)->type)); + } + + set + { + if (ReferenceEquals(value, null)) + throw new global::System.ArgumentNullException("value", "Cannot be null because it is passed by value."); + ((__Internal*)__Instance)->type = *(global::CppSharp.Parser.AST.QualifiedType.__Internal*) value.__Instance; + } + } } public unsafe partial class ClassTemplate : global::CppSharp.Parser.AST.Template, IDisposable diff --git a/src/CppParser/Bindings/CSharp/i686-pc-win32-msvc/CppSharp.CppParser.cs b/src/CppParser/Bindings/CSharp/i686-pc-win32-msvc/CppSharp.CppParser.cs index e6d43d9596..de89c3f760 100644 --- a/src/CppParser/Bindings/CSharp/i686-pc-win32-msvc/CppSharp.CppParser.cs +++ b/src/CppParser/Bindings/CSharp/i686-pc-win32-msvc/CppSharp.CppParser.cs @@ -6301,7 +6301,8 @@ public enum CppAbi Microsoft = 1, ARM = 2, iOS = 3, - iOS64 = 4 + iOS64 = 4, + WebAssembly = 5 } public enum RecordArgABI @@ -13016,6 +13017,7 @@ public unsafe partial class NonTypeTemplateParameter : global::CppSharp.Parser.A internal uint position; internal byte isPackExpansion; internal byte isExpandedParameterPack; + internal global::CppSharp.Parser.AST.QualifiedType.__Internal type; [SuppressUnmanagedCodeSecurity, DllImport("CppSharp.CppParser.dll", EntryPoint = "??0NonTypeTemplateParameter@AST@CppParser@CppSharp@@QAE@XZ", CallingConvention = __CallingConvention.ThisCall)] internal static extern __IntPtr ctor(__IntPtr __instance); @@ -13170,6 +13172,21 @@ public bool IsExpandedParameterPack ((__Internal*)__Instance)->isExpandedParameterPack = (byte) (value ? 1 : 0); } } + + public global::CppSharp.Parser.AST.QualifiedType Type + { + get + { + return global::CppSharp.Parser.AST.QualifiedType.__CreateInstance(new __IntPtr(&((__Internal*)__Instance)->type)); + } + + set + { + if (ReferenceEquals(value, null)) + throw new global::System.ArgumentNullException("value", "Cannot be null because it is passed by value."); + ((__Internal*)__Instance)->type = *(global::CppSharp.Parser.AST.QualifiedType.__Internal*) value.__Instance; + } + } } public unsafe partial class ClassTemplate : global::CppSharp.Parser.AST.Template, IDisposable diff --git a/src/CppParser/Bindings/CSharp/x86_64-apple-darwin12.4.0/CppSharp.CppParser.cs b/src/CppParser/Bindings/CSharp/x86_64-apple-darwin12.4.0/CppSharp.CppParser.cs index 4ce7bfff71..576edd3c17 100644 --- a/src/CppParser/Bindings/CSharp/x86_64-apple-darwin12.4.0/CppSharp.CppParser.cs +++ b/src/CppParser/Bindings/CSharp/x86_64-apple-darwin12.4.0/CppSharp.CppParser.cs @@ -6301,7 +6301,8 @@ public enum CppAbi Microsoft = 1, ARM = 2, iOS = 3, - iOS64 = 4 + iOS64 = 4, + WebAssembly = 5 } public enum RecordArgABI @@ -13015,6 +13016,7 @@ public unsafe partial class NonTypeTemplateParameter : global::CppSharp.Parser.A internal uint position; internal byte isPackExpansion; internal byte isExpandedParameterPack; + internal global::CppSharp.Parser.AST.QualifiedType.__Internal type; [SuppressUnmanagedCodeSecurity, DllImport("CppSharp.CppParser", EntryPoint = "_ZN8CppSharp9CppParser3AST24NonTypeTemplateParameterC2Ev", CallingConvention = __CallingConvention.Cdecl)] internal static extern void ctor(__IntPtr __instance); @@ -13169,6 +13171,21 @@ public bool IsExpandedParameterPack ((__Internal*)__Instance)->isExpandedParameterPack = (byte) (value ? 1 : 0); } } + + public global::CppSharp.Parser.AST.QualifiedType Type + { + get + { + return global::CppSharp.Parser.AST.QualifiedType.__CreateInstance(new __IntPtr(&((__Internal*)__Instance)->type)); + } + + set + { + if (ReferenceEquals(value, null)) + throw new global::System.ArgumentNullException("value", "Cannot be null because it is passed by value."); + ((__Internal*)__Instance)->type = *(global::CppSharp.Parser.AST.QualifiedType.__Internal*) value.__Instance; + } + } } public unsafe partial class ClassTemplate : global::CppSharp.Parser.AST.Template, IDisposable diff --git a/src/CppParser/Bindings/CSharp/x86_64-linux-gnu-cxx11abi/CppSharp.CppParser.cs b/src/CppParser/Bindings/CSharp/x86_64-linux-gnu-cxx11abi/CppSharp.CppParser.cs index 82844c1059..4c6201974c 100644 --- a/src/CppParser/Bindings/CSharp/x86_64-linux-gnu-cxx11abi/CppSharp.CppParser.cs +++ b/src/CppParser/Bindings/CSharp/x86_64-linux-gnu-cxx11abi/CppSharp.CppParser.cs @@ -6301,7 +6301,8 @@ public enum CppAbi Microsoft = 1, ARM = 2, iOS = 3, - iOS64 = 4 + iOS64 = 4, + WebAssembly = 5 } public enum RecordArgABI @@ -13015,6 +13016,7 @@ public unsafe partial class NonTypeTemplateParameter : global::CppSharp.Parser.A internal uint position; internal byte isPackExpansion; internal byte isExpandedParameterPack; + internal global::CppSharp.Parser.AST.QualifiedType.__Internal type; [SuppressUnmanagedCodeSecurity, DllImport("CppSharp.CppParser", EntryPoint = "_ZN8CppSharp9CppParser3AST24NonTypeTemplateParameterC2Ev", CallingConvention = __CallingConvention.Cdecl)] internal static extern void ctor(__IntPtr __instance); @@ -13169,6 +13171,21 @@ public bool IsExpandedParameterPack ((__Internal*)__Instance)->isExpandedParameterPack = (byte) (value ? 1 : 0); } } + + public global::CppSharp.Parser.AST.QualifiedType Type + { + get + { + return global::CppSharp.Parser.AST.QualifiedType.__CreateInstance(new __IntPtr(&((__Internal*)__Instance)->type)); + } + + set + { + if (ReferenceEquals(value, null)) + throw new global::System.ArgumentNullException("value", "Cannot be null because it is passed by value."); + ((__Internal*)__Instance)->type = *(global::CppSharp.Parser.AST.QualifiedType.__Internal*) value.__Instance; + } + } } public unsafe partial class ClassTemplate : global::CppSharp.Parser.AST.Template, IDisposable diff --git a/src/CppParser/Bindings/CSharp/x86_64-linux-gnu/CppSharp.CppParser.cs b/src/CppParser/Bindings/CSharp/x86_64-linux-gnu/CppSharp.CppParser.cs index 612f1f207f..2b7e1e837c 100644 --- a/src/CppParser/Bindings/CSharp/x86_64-linux-gnu/CppSharp.CppParser.cs +++ b/src/CppParser/Bindings/CSharp/x86_64-linux-gnu/CppSharp.CppParser.cs @@ -6301,7 +6301,8 @@ public enum CppAbi Microsoft = 1, ARM = 2, iOS = 3, - iOS64 = 4 + iOS64 = 4, + WebAssembly = 5 } public enum RecordArgABI @@ -13015,6 +13016,7 @@ public unsafe partial class NonTypeTemplateParameter : global::CppSharp.Parser.A internal uint position; internal byte isPackExpansion; internal byte isExpandedParameterPack; + internal global::CppSharp.Parser.AST.QualifiedType.__Internal type; [SuppressUnmanagedCodeSecurity, DllImport("CppSharp.CppParser", EntryPoint = "_ZN8CppSharp9CppParser3AST24NonTypeTemplateParameterC2Ev", CallingConvention = __CallingConvention.Cdecl)] internal static extern void ctor(__IntPtr __instance); @@ -13169,6 +13171,21 @@ public bool IsExpandedParameterPack ((__Internal*)__Instance)->isExpandedParameterPack = (byte) (value ? 1 : 0); } } + + public global::CppSharp.Parser.AST.QualifiedType Type + { + get + { + return global::CppSharp.Parser.AST.QualifiedType.__CreateInstance(new __IntPtr(&((__Internal*)__Instance)->type)); + } + + set + { + if (ReferenceEquals(value, null)) + throw new global::System.ArgumentNullException("value", "Cannot be null because it is passed by value."); + ((__Internal*)__Instance)->type = *(global::CppSharp.Parser.AST.QualifiedType.__Internal*) value.__Instance; + } + } } public unsafe partial class ClassTemplate : global::CppSharp.Parser.AST.Template, IDisposable diff --git a/src/CppParser/Bindings/CSharp/x86_64-pc-win32-msvc/CppSharp.CppParser.cs b/src/CppParser/Bindings/CSharp/x86_64-pc-win32-msvc/CppSharp.CppParser.cs index 85846584a7..5c6dadc5fe 100644 --- a/src/CppParser/Bindings/CSharp/x86_64-pc-win32-msvc/CppSharp.CppParser.cs +++ b/src/CppParser/Bindings/CSharp/x86_64-pc-win32-msvc/CppSharp.CppParser.cs @@ -6301,7 +6301,8 @@ public enum CppAbi Microsoft = 1, ARM = 2, iOS = 3, - iOS64 = 4 + iOS64 = 4, + WebAssembly = 5 } public enum RecordArgABI @@ -13017,6 +13018,7 @@ public unsafe partial class NonTypeTemplateParameter : global::CppSharp.Parser.A internal uint position; internal byte isPackExpansion; internal byte isExpandedParameterPack; + internal global::CppSharp.Parser.AST.QualifiedType.__Internal type; [SuppressUnmanagedCodeSecurity, DllImport("CppSharp.CppParser.dll", EntryPoint = "??0NonTypeTemplateParameter@AST@CppParser@CppSharp@@QEAA@XZ", CallingConvention = __CallingConvention.Cdecl)] internal static extern __IntPtr ctor(__IntPtr __instance); @@ -13171,6 +13173,21 @@ public bool IsExpandedParameterPack ((__Internal*)__Instance)->isExpandedParameterPack = (byte) (value ? 1 : 0); } } + + public global::CppSharp.Parser.AST.QualifiedType Type + { + get + { + return global::CppSharp.Parser.AST.QualifiedType.__CreateInstance(new __IntPtr(&((__Internal*)__Instance)->type)); + } + + set + { + if (ReferenceEquals(value, null)) + throw new global::System.ArgumentNullException("value", "Cannot be null because it is passed by value."); + ((__Internal*)__Instance)->type = *(global::CppSharp.Parser.AST.QualifiedType.__Internal*) value.__Instance; + } + } } public unsafe partial class ClassTemplate : global::CppSharp.Parser.AST.Template, IDisposable diff --git a/src/CppParser/Decl.h b/src/CppParser/Decl.h index 7132a11080..b51929c45d 100644 --- a/src/CppParser/Decl.h +++ b/src/CppParser/Decl.h @@ -1,9 +1,9 @@ /************************************************************************ -* -* CppSharp -* Licensed under the MIT license. -* -************************************************************************/ + * + * CppSharp + * Licensed under the MIT license. + * + ************************************************************************/ #pragma once @@ -12,823 +12,834 @@ #include "Types.h" #include -namespace CppSharp { namespace CppParser { namespace AST { - -enum class DeclarationKind +namespace CppSharp { - DeclarationContext, - Typedef, - TypeAlias, - Parameter, - Function, - Method, - Enumeration, - EnumerationItem, - Variable, - Field, - AccessSpecifier, - Class, - Template, - TypeAliasTemplate, - ClassTemplate, - ClassTemplateSpecialization, - ClassTemplatePartialSpecialization, - FunctionTemplate, - Namespace, - PreprocessedEntity, - MacroDefinition, - MacroExpansion, - TranslationUnit, - Friend, - TemplateTemplateParm, - TemplateTypeParm, - NonTypeTemplateParm, - VarTemplate, - VarTemplateSpecialization, - VarTemplatePartialSpecialization, - UnresolvedUsingTypename, -}; + namespace CppParser + { + namespace AST + { + + enum class DeclarationKind + { + DeclarationContext, + Typedef, + TypeAlias, + Parameter, + Function, + Method, + Enumeration, + EnumerationItem, + Variable, + Field, + AccessSpecifier, + Class, + Template, + TypeAliasTemplate, + ClassTemplate, + ClassTemplateSpecialization, + ClassTemplatePartialSpecialization, + FunctionTemplate, + Namespace, + PreprocessedEntity, + MacroDefinition, + MacroExpansion, + TranslationUnit, + Friend, + TemplateTemplateParm, + TemplateTypeParm, + NonTypeTemplateParm, + VarTemplate, + VarTemplateSpecialization, + VarTemplatePartialSpecialization, + UnresolvedUsingTypename, + }; #define DECLARE_DECL_KIND(klass, kind) \ klass(); -enum class AccessSpecifier -{ - Private, - Protected, - Public -}; - -class DeclarationContext; -class RawComment; -class PreprocessedEntity; - -class ExpressionObsolete; -class CS_API Declaration -{ -public: - Declaration(DeclarationKind kind); - Declaration(const Declaration&); - ~Declaration(); - - DeclarationKind kind; - int alignAs; - int maxFieldAlignment; - AccessSpecifier access; - DeclarationContext* _namespace; - SourceLocation location; - int lineNumberStart; - int lineNumberEnd; - std::string name; - std::string USR; - std::string debugText; - bool isIncomplete; - bool isDependent; - bool isImplicit; - bool isInvalid; - bool isDeprecated; - Declaration* completeDeclaration; - unsigned definitionOrder; - VECTOR(PreprocessedEntity*, PreprocessedEntities) - VECTOR(Declaration*, Redeclarations) - void* originalPtr; - RawComment* comment; -}; - -class Class; -class Enumeration; -class Function; -class TypedefDecl; -class TypeAlias; -class Namespace; -class Template; -class TypeAliasTemplate; -class ClassTemplate; -class FunctionTemplate; -class Variable; -class Friend; - -class CS_API DeclarationContext : public Declaration -{ -public: - DeclarationContext(DeclarationKind kind); - - CS_IGNORE Declaration* FindAnonymous(const std::string& USR); - - CS_IGNORE Namespace* FindNamespace(const std::string& Name); - CS_IGNORE Namespace* FindNamespace(const std::vector&); - CS_IGNORE Namespace* FindCreateNamespace(const std::string& Name); - - CS_IGNORE Class* CreateClass(const std::string& Name, bool IsComplete); - CS_IGNORE Class* FindClass(const void* OriginalPtr, const std::string& Name, bool IsComplete); - CS_IGNORE Class* FindClass(const void* OriginalPtr, const std::string& Name, bool IsComplete, - bool Create); - - CS_IGNORE template T* FindTemplate(const std::string& USR); - - CS_IGNORE Enumeration* FindEnum(const void* OriginalPtr); - CS_IGNORE Enumeration* FindEnum(const std::string& Name, bool Create = false); - CS_IGNORE Enumeration* FindEnumWithItem(const std::string& Name); - - CS_IGNORE Function* FindFunction(const std::string& USR); - - CS_IGNORE TypedefDecl* FindTypedef(const std::string& Name, bool Create = false); - - CS_IGNORE TypeAlias* FindTypeAlias(const std::string& Name, bool Create = false); - - CS_IGNORE Variable* FindVariable(const std::string& USR); - - CS_IGNORE Friend* FindFriend(const std::string& USR); - - VECTOR(Namespace*, Namespaces) - VECTOR(Enumeration*, Enums) - VECTOR(Function*, Functions) - VECTOR(Class*, Classes) - VECTOR(Template*, Templates) - VECTOR(TypedefDecl*, Typedefs) - VECTOR(TypeAlias*, TypeAliases) - VECTOR(Variable*, Variables) - VECTOR(Friend*, Friends) - - std::map anonymous; - - bool isAnonymous; -}; - -class CS_API TypedefNameDecl : public Declaration -{ -public: - TypedefNameDecl(DeclarationKind kind); - ~TypedefNameDecl(); - QualifiedType qualifiedType; -}; - -class CS_API TypedefDecl : public TypedefNameDecl -{ -public: - DECLARE_DECL_KIND(TypedefDecl, Typedef) - ~TypedefDecl(); -}; - -class CS_API TypeAlias : public TypedefNameDecl -{ -public: - TypeAlias(); - ~TypeAlias(); - TypeAliasTemplate* describedAliasTemplate; -}; - -class CS_API Friend : public Declaration -{ -public: - DECLARE_DECL_KIND(Friend, Friend) - ~Friend(); - Declaration* declaration; -}; - -enum class StatementClassObsolete -{ - Any, - BinaryOperator, - CallExprClass, - DeclRefExprClass, - CXXConstructExprClass, - CXXOperatorCallExpr, - ImplicitCastExpr, - ExplicitCastExpr, -}; - -class CS_API StatementObsolete -{ -public: - StatementObsolete(const std::string& str, StatementClassObsolete Class = StatementClassObsolete::Any, Declaration* decl = 0); - StatementClassObsolete _class; - Declaration* decl; - std::string string; -}; - -class CS_API ExpressionObsolete : public StatementObsolete -{ -public: - ExpressionObsolete(const std::string& str, StatementClassObsolete Class = StatementClassObsolete::Any, Declaration* decl = 0); -}; - -class Expr; - -class CS_API BinaryOperatorObsolete : public ExpressionObsolete -{ -public: - BinaryOperatorObsolete(const std::string& str, ExpressionObsolete* lhs, ExpressionObsolete* rhs, const std::string& opcodeStr); - ~BinaryOperatorObsolete(); - ExpressionObsolete* LHS; - ExpressionObsolete* RHS; - std::string opcodeStr; -}; - -class CS_API CallExprObsolete : public ExpressionObsolete -{ -public: - CallExprObsolete(const std::string& str, Declaration* decl); - ~CallExprObsolete(); - VECTOR(ExpressionObsolete*, Arguments) -}; - -class CS_API CXXConstructExprObsolete : public ExpressionObsolete -{ -public: - CXXConstructExprObsolete(const std::string& str, Declaration* decl = 0); - ~CXXConstructExprObsolete(); - VECTOR(ExpressionObsolete*, Arguments) -}; - -class CS_API Parameter : public Declaration -{ -public: - Parameter(); - ~Parameter(); - - QualifiedType qualifiedType; - bool isIndirect; - bool hasDefaultValue; - unsigned int index; - ExpressionObsolete* defaultArgument; - Expr* defaultValue; -}; - -enum class CXXMethodKind -{ - Normal, - Constructor, - Destructor, - Conversion, - Operator, - UsingDirective -}; - -enum class CXXOperatorKind -{ - None, - New, - Delete, - Array_New, - Array_Delete, - Plus, - Minus, - Star, - Slash, - Percent, - Caret, - Amp, - Pipe, - Tilde, - Exclaim, - Equal, - Less, - Greater, - PlusEqual, - MinusEqual, - StarEqual, - SlashEqual, - PercentEqual, - CaretEqual, - AmpEqual, - PipeEqual, - LessLess, - GreaterGreater, - LessLessEqual, - GreaterGreaterEqual, - EqualEqual, - ExclaimEqual, - LessEqual, - GreaterEqual, - Spaceship, - AmpAmp, - PipePipe, - PlusPlus, - MinusMinus, - Comma, - ArrowStar, - Arrow, - Call, - Subscript, - Conditional, - Coawait -}; - -class FunctionTemplateSpecialization; - -enum class FriendKind -{ - None, - Declared, - Undeclared -}; - -class Stmt; - -class CS_API Function : public DeclarationContext -{ -public: - Function(); - ~Function(); - - QualifiedType returnType; - bool isReturnIndirect; - bool hasThisReturn; - - bool isConstExpr; - bool isVariadic; - bool isInline; - bool isPure; - bool isDeleted; - bool isDefaulted; - FriendKind friendKind; - CXXOperatorKind operatorKind; - std::string mangled; - std::string signature; - std::string body; - Stmt* bodyStmt; - CallingConvention callingConvention; - VECTOR(Parameter*, Parameters) - FunctionTemplateSpecialization* specializationInfo; - Function* instantiatedFrom; - QualifiedType qualifiedType; -}; - -class AccessSpecifierDecl; - -enum class RefQualifierKind -{ - None, - LValue, - RValue -}; - -class CS_API Method : public Function -{ -public: - Method(); - ~Method(); - - bool isVirtual; - bool isStatic; - bool isConst; - bool isExplicit; - - CXXMethodKind methodKind; - - bool isDefaultConstructor; - bool isCopyConstructor; - bool isMoveConstructor; - - QualifiedType conversionType; - RefQualifierKind refQualifier; - VECTOR(Method*, OverriddenMethods) -}; - -class CS_API Enumeration : public DeclarationContext -{ -public: - DECLARE_DECL_KIND(Enumeration, Enumeration) - ~Enumeration(); - - class CS_API Item : public Declaration - { - public: - DECLARE_DECL_KIND(Item, EnumerationItem) - Item(const Item&); - ~Item(); - std::string expression; - uint64_t value; - }; - - enum class CS_FLAGS EnumModifiers - { - Anonymous = 1 << 0, - Scoped = 1 << 1, - Flags = 1 << 2, - }; - - EnumModifiers modifiers; - Type* type; - BuiltinType* builtinType; - VECTOR(Item*, Items) - - Item* FindItemByName(const std::string& Name); -}; - -class CS_API Variable : public Declaration -{ -public: - DECLARE_DECL_KIND(Variable, Variable) - ~Variable(); - bool isConstExpr; - std::string mangled; - QualifiedType qualifiedType; - ExpressionObsolete* initializer; -}; - -class PreprocessedEntity; - -struct CS_API BaseClassSpecifier -{ - BaseClassSpecifier(); - AccessSpecifier access; - bool isVirtual; - Type* type; - int offset; -}; - -class Class; - -class CS_API Field : public Declaration -{ -public: - DECLARE_DECL_KIND(Field, Field) - ~Field(); - QualifiedType qualifiedType; - Class* _class; - bool isBitField; - unsigned bitWidth; -}; - -class CS_API AccessSpecifierDecl : public Declaration -{ -public: - DECLARE_DECL_KIND(AccessSpecifierDecl, AccessSpecifier) - ~AccessSpecifierDecl(); -}; - -enum class CppAbi -{ - Itanium, - Microsoft, - ARM, - iOS, - iOS64 -}; - -enum class VTableComponentKind -{ - VCallOffset, - VBaseOffset, - OffsetToTop, - RTTI, - FunctionPointer, - CompleteDtorPointer, - DeletingDtorPointer, - UnusedFunctionPointer, -}; - -struct CS_API VTableComponent -{ - VTableComponent(); - VTableComponentKind kind; - unsigned offset; - Declaration* declaration; -}; - -struct CS_API VTableLayout -{ - VTableLayout(); - VTableLayout(const VTableLayout&); - ~VTableLayout(); - VECTOR(VTableComponent, Components) -}; - -struct CS_API VFTableInfo -{ - VFTableInfo(); - VFTableInfo(const VFTableInfo&); - uint64_t VBTableIndex; - uint32_t VFPtrOffset; - uint32_t VFPtrFullOffset; - VTableLayout layout; -}; - -class CS_API LayoutField -{ -public: - LayoutField(); - LayoutField(const LayoutField& other); - ~LayoutField(); - unsigned offset; - std::string name; - QualifiedType qualifiedType; - void* fieldPtr; -}; - -class Class; - -class CS_API LayoutBase -{ -public: - LayoutBase(); - LayoutBase(const LayoutBase& other); - ~LayoutBase(); - unsigned offset; - Class* _class; -}; - -enum class RecordArgABI -{ - /// Pass it using the normal C aggregate rules for the ABI, - /// potentially introducing extra copies and passing some - /// or all of it in registers. - Default = 0, - /// Pass it on the stack using its defined layout. - /// The argument must be evaluated directly into the correct - /// stack position in the arguments area, and the call machinery - /// must not move it or introduce extra copies. - DirectInMemory, - /// Pass it as a pointer to temporary memory. - Indirect -}; - -struct CS_API ClassLayout -{ - ClassLayout(); - CppAbi ABI; - RecordArgABI argABI; - VECTOR(VFTableInfo, VFTables) - VTableLayout layout; - bool hasOwnVFPtr; - long VBPtrOffset; - int alignment; - int size; - int dataSize; - VECTOR(LayoutField, Fields) - VECTOR(LayoutBase, Bases) -}; - -enum class TagKind -{ - Struct, - Interface, - Union, - Class, - Enum -}; - -class CS_API Class : public DeclarationContext -{ -public: - Class(); - ~Class(); - - VECTOR(BaseClassSpecifier*, Bases) - VECTOR(Field*, Fields) - VECTOR(Method*, Methods) - VECTOR(AccessSpecifierDecl*, Specifiers) - - bool isPOD; - bool isAbstract; - bool isUnion; - bool isDynamic; - bool isPolymorphic; - bool hasNonTrivialDefaultConstructor; - bool hasNonTrivialCopyConstructor; - bool hasNonTrivialDestructor; - bool isExternCContext; - bool isInjected; - TagKind tagKind; - - ClassLayout* layout; -}; - -class CS_API Template : public Declaration -{ -public: - Template(DeclarationKind kind); - DECLARE_DECL_KIND(Template, Template) - Declaration* TemplatedDecl; - VECTOR(Declaration*, Parameters) -}; - -template -T* DeclarationContext::FindTemplate(const std::string& USR) -{ - auto foundTemplate = std::find_if(Templates.begin(), Templates.end(), - [&](Template* t) { return t->USR == USR; }); - - if (foundTemplate != Templates.end()) - return static_cast(*foundTemplate); - - return nullptr; -} - -class CS_API TypeAliasTemplate : public Template -{ -public: - TypeAliasTemplate(); - ~TypeAliasTemplate(); -}; - -class CS_API TemplateParameter : public Declaration -{ -public: - TemplateParameter(DeclarationKind kind); - ~TemplateParameter(); - unsigned int depth; - unsigned int index; - bool isParameterPack; -}; - -class CS_API TemplateTemplateParameter : public Template -{ -public: - TemplateTemplateParameter(); - ~TemplateTemplateParameter(); - - bool isParameterPack; - bool isPackExpansion; - bool isExpandedParameterPack; -}; - -class CS_API TypeTemplateParameter : public TemplateParameter -{ -public: - TypeTemplateParameter(); - TypeTemplateParameter(const TypeTemplateParameter&); - ~TypeTemplateParameter(); - - QualifiedType defaultArgument; -}; - -class CS_API NonTypeTemplateParameter : public TemplateParameter -{ -public: - NonTypeTemplateParameter(); - NonTypeTemplateParameter(const NonTypeTemplateParameter&); - ~NonTypeTemplateParameter(); - ExpressionObsolete* defaultArgument; - Expr* defaultArgumentNew; - unsigned int position; - bool isPackExpansion; - bool isExpandedParameterPack; -}; - -class ClassTemplateSpecialization; -class ClassTemplatePartialSpecialization; - -class CS_API ClassTemplate : public Template -{ -public: - ClassTemplate(); - ~ClassTemplate(); - VECTOR(ClassTemplateSpecialization*, Specializations) - ClassTemplateSpecialization* FindSpecialization(const std::string& usr); - ClassTemplatePartialSpecialization* FindPartialSpecialization(const std::string& usr); -}; - -enum class TemplateSpecializationKind -{ - Undeclared, - ImplicitInstantiation, - ExplicitSpecialization, - ExplicitInstantiationDeclaration, - ExplicitInstantiationDefinition -}; - -class CS_API ClassTemplateSpecialization : public Class -{ -public: - ClassTemplateSpecialization(); - ~ClassTemplateSpecialization(); - ClassTemplate* templatedDecl; - VECTOR(TemplateArgument, Arguments) - TemplateSpecializationKind specializationKind; -}; - -class CS_API ClassTemplatePartialSpecialization : public ClassTemplateSpecialization -{ -public: - ClassTemplatePartialSpecialization(); - ~ClassTemplatePartialSpecialization(); -}; - -class CS_API FunctionTemplate : public Template -{ -public: - FunctionTemplate(); - ~FunctionTemplate(); - VECTOR(FunctionTemplateSpecialization*, Specializations) - FunctionTemplateSpecialization* FindSpecialization(const std::string& usr); -}; - -class CS_API FunctionTemplateSpecialization -{ -public: - FunctionTemplateSpecialization(); - ~FunctionTemplateSpecialization(); - FunctionTemplate* _template; - VECTOR(TemplateArgument, Arguments) - Function* specializedFunction; - TemplateSpecializationKind specializationKind; -}; - -class VarTemplateSpecialization; -class VarTemplatePartialSpecialization; - -class CS_API VarTemplate : public Template -{ -public: - VarTemplate(); - ~VarTemplate(); - VECTOR(VarTemplateSpecialization*, Specializations) - VarTemplateSpecialization* FindSpecialization(const std::string& usr); - VarTemplatePartialSpecialization* FindPartialSpecialization(const std::string& usr); -}; - -class CS_API VarTemplateSpecialization : public Variable -{ -public: - VarTemplateSpecialization(); - ~VarTemplateSpecialization(); - VarTemplate* templatedDecl; - VECTOR(TemplateArgument, Arguments) - TemplateSpecializationKind specializationKind; -}; - -class CS_API VarTemplatePartialSpecialization : public VarTemplateSpecialization -{ -public: - VarTemplatePartialSpecialization(); - ~VarTemplatePartialSpecialization(); -}; - -class CS_API UnresolvedUsingTypename : public Declaration -{ -public: - UnresolvedUsingTypename(); - ~UnresolvedUsingTypename(); -}; - -class CS_API Namespace : public DeclarationContext -{ -public: - Namespace(); - ~Namespace(); - bool isInline; -}; - -enum class MacroLocation -{ - Unknown, - ClassHead, - ClassBody, - FunctionHead, - FunctionParameters, - FunctionBody, -}; - -class CS_API PreprocessedEntity -{ -public: - PreprocessedEntity(); - MacroLocation macroLocation; - void* originalPtr; - DeclarationKind kind; -}; - -class CS_API MacroDefinition : public PreprocessedEntity -{ -public: - MacroDefinition(); - ~MacroDefinition(); - std::string name; - std::string expression; - int lineNumberStart; - int lineNumberEnd; -}; - -class CS_API MacroExpansion : public PreprocessedEntity -{ -public: - MacroExpansion(); - ~MacroExpansion(); - std::string name; - std::string text; - MacroDefinition* definition; -}; - -class CS_API TranslationUnit : public Namespace -{ -public: - TranslationUnit(); - ~TranslationUnit(); - std::string fileName; - bool isSystemHeader; - VECTOR(MacroDefinition*, Macros) -}; - -class CS_API ASTContext -{ -public: - ASTContext(); - ~ASTContext(); - TranslationUnit* FindOrCreateModule(std::string File); - VECTOR(TranslationUnit*, TranslationUnits) -}; - -} } } \ No newline at end of file + enum class AccessSpecifier + { + Private, + Protected, + Public + }; + + class DeclarationContext; + class RawComment; + class PreprocessedEntity; + + class ExpressionObsolete; + class CS_API Declaration + { + public: + Declaration(DeclarationKind kind); + Declaration(const Declaration &); + ~Declaration(); + + DeclarationKind kind; + int alignAs; + int maxFieldAlignment; + AccessSpecifier access; + DeclarationContext *_namespace; + SourceLocation location; + int lineNumberStart; + int lineNumberEnd; + std::string name; + std::string USR; + std::string debugText; + bool isIncomplete; + bool isDependent; + bool isImplicit; + bool isInvalid; + bool isDeprecated; + Declaration *completeDeclaration; + unsigned definitionOrder; + VECTOR(PreprocessedEntity *, PreprocessedEntities) + VECTOR(Declaration *, Redeclarations) + void *originalPtr; + RawComment *comment; + }; + + class Class; + class Enumeration; + class Function; + class TypedefDecl; + class TypeAlias; + class Namespace; + class Template; + class TypeAliasTemplate; + class ClassTemplate; + class FunctionTemplate; + class Variable; + class Friend; + + class CS_API DeclarationContext : public Declaration + { + public: + DeclarationContext(DeclarationKind kind); + + CS_IGNORE Declaration *FindAnonymous(const std::string &USR); + + CS_IGNORE Namespace *FindNamespace(const std::string &Name); + CS_IGNORE Namespace *FindNamespace(const std::vector &); + CS_IGNORE Namespace *FindCreateNamespace(const std::string &Name); + + CS_IGNORE Class *CreateClass(const std::string &Name, bool IsComplete); + CS_IGNORE Class *FindClass(const void *OriginalPtr, const std::string &Name, bool IsComplete); + CS_IGNORE Class *FindClass(const void *OriginalPtr, const std::string &Name, bool IsComplete, + bool Create); + + CS_IGNORE template + T *FindTemplate(const std::string &USR); + + CS_IGNORE Enumeration *FindEnum(const void *OriginalPtr); + CS_IGNORE Enumeration *FindEnum(const std::string &Name, bool Create = false); + CS_IGNORE Enumeration *FindEnumWithItem(const std::string &Name); + + CS_IGNORE Function *FindFunction(const std::string &USR); + + CS_IGNORE TypedefDecl *FindTypedef(const std::string &Name, bool Create = false); + + CS_IGNORE TypeAlias *FindTypeAlias(const std::string &Name, bool Create = false); + + CS_IGNORE Variable *FindVariable(const std::string &USR); + + CS_IGNORE Friend *FindFriend(const std::string &USR); + + VECTOR(Namespace *, Namespaces) + VECTOR(Enumeration *, Enums) + VECTOR(Function *, Functions) + VECTOR(Class *, Classes) + VECTOR(Template *, Templates) + VECTOR(TypedefDecl *, Typedefs) + VECTOR(TypeAlias *, TypeAliases) + VECTOR(Variable *, Variables) + VECTOR(Friend *, Friends) + + std::map anonymous; + + bool isAnonymous; + }; + + class CS_API TypedefNameDecl : public Declaration + { + public: + TypedefNameDecl(DeclarationKind kind); + ~TypedefNameDecl(); + QualifiedType qualifiedType; + }; + + class CS_API TypedefDecl : public TypedefNameDecl + { + public: + DECLARE_DECL_KIND(TypedefDecl, Typedef) + ~TypedefDecl(); + }; + + class CS_API TypeAlias : public TypedefNameDecl + { + public: + TypeAlias(); + ~TypeAlias(); + TypeAliasTemplate *describedAliasTemplate; + }; + + class CS_API Friend : public Declaration + { + public: + DECLARE_DECL_KIND(Friend, Friend) + ~Friend(); + Declaration *declaration; + }; + + enum class StatementClassObsolete + { + Any, + BinaryOperator, + CallExprClass, + DeclRefExprClass, + CXXConstructExprClass, + CXXOperatorCallExpr, + ImplicitCastExpr, + ExplicitCastExpr, + }; + + class CS_API StatementObsolete + { + public: + StatementObsolete(const std::string &str, StatementClassObsolete Class = StatementClassObsolete::Any, Declaration *decl = 0); + StatementClassObsolete _class; + Declaration *decl; + std::string string; + }; + + class CS_API ExpressionObsolete : public StatementObsolete + { + public: + ExpressionObsolete(const std::string &str, StatementClassObsolete Class = StatementClassObsolete::Any, Declaration *decl = 0); + }; + + class Expr; + + class CS_API BinaryOperatorObsolete : public ExpressionObsolete + { + public: + BinaryOperatorObsolete(const std::string &str, ExpressionObsolete *lhs, ExpressionObsolete *rhs, const std::string &opcodeStr); + ~BinaryOperatorObsolete(); + ExpressionObsolete *LHS; + ExpressionObsolete *RHS; + std::string opcodeStr; + }; + + class CS_API CallExprObsolete : public ExpressionObsolete + { + public: + CallExprObsolete(const std::string &str, Declaration *decl); + ~CallExprObsolete(); + VECTOR(ExpressionObsolete *, Arguments) + }; + + class CS_API CXXConstructExprObsolete : public ExpressionObsolete + { + public: + CXXConstructExprObsolete(const std::string &str, Declaration *decl = 0); + ~CXXConstructExprObsolete(); + VECTOR(ExpressionObsolete *, Arguments) + }; + + class CS_API Parameter : public Declaration + { + public: + Parameter(); + ~Parameter(); + + QualifiedType qualifiedType; + bool isIndirect; + bool hasDefaultValue; + unsigned int index; + ExpressionObsolete *defaultArgument; + Expr *defaultValue; + }; + + enum class CXXMethodKind + { + Normal, + Constructor, + Destructor, + Conversion, + Operator, + UsingDirective + }; + + enum class CXXOperatorKind + { + None, + New, + Delete, + Array_New, + Array_Delete, + Plus, + Minus, + Star, + Slash, + Percent, + Caret, + Amp, + Pipe, + Tilde, + Exclaim, + Equal, + Less, + Greater, + PlusEqual, + MinusEqual, + StarEqual, + SlashEqual, + PercentEqual, + CaretEqual, + AmpEqual, + PipeEqual, + LessLess, + GreaterGreater, + LessLessEqual, + GreaterGreaterEqual, + EqualEqual, + ExclaimEqual, + LessEqual, + GreaterEqual, + Spaceship, + AmpAmp, + PipePipe, + PlusPlus, + MinusMinus, + Comma, + ArrowStar, + Arrow, + Call, + Subscript, + Conditional, + Coawait + }; + + class FunctionTemplateSpecialization; + + enum class FriendKind + { + None, + Declared, + Undeclared + }; + + class Stmt; + + class CS_API Function : public DeclarationContext + { + public: + Function(); + ~Function(); + + QualifiedType returnType; + bool isReturnIndirect; + bool hasThisReturn; + + bool isConstExpr; + bool isVariadic; + bool isInline; + bool isPure; + bool isDeleted; + bool isDefaulted; + FriendKind friendKind; + CXXOperatorKind operatorKind; + std::string mangled; + std::string signature; + std::string body; + Stmt *bodyStmt; + CallingConvention callingConvention; + VECTOR(Parameter *, Parameters) + FunctionTemplateSpecialization *specializationInfo; + Function *instantiatedFrom; + QualifiedType qualifiedType; + }; + + class AccessSpecifierDecl; + + enum class RefQualifierKind + { + None, + LValue, + RValue + }; + + class CS_API Method : public Function + { + public: + Method(); + ~Method(); + + bool isVirtual; + bool isStatic; + bool isConst; + bool isExplicit; + + CXXMethodKind methodKind; + + bool isDefaultConstructor; + bool isCopyConstructor; + bool isMoveConstructor; + + QualifiedType conversionType; + RefQualifierKind refQualifier; + VECTOR(Method *, OverriddenMethods) + }; + + class CS_API Enumeration : public DeclarationContext + { + public: + DECLARE_DECL_KIND(Enumeration, Enumeration) + ~Enumeration(); + + class CS_API Item : public Declaration + { + public: + DECLARE_DECL_KIND(Item, EnumerationItem) + Item(const Item &); + ~Item(); + std::string expression; + uint64_t value; + }; + + enum class CS_FLAGS EnumModifiers + { + Anonymous = 1 << 0, + Scoped = 1 << 1, + Flags = 1 << 2, + }; + + EnumModifiers modifiers; + Type *type; + BuiltinType *builtinType; + VECTOR(Item *, Items) + + Item *FindItemByName(const std::string &Name); + }; + + class CS_API Variable : public Declaration + { + public: + DECLARE_DECL_KIND(Variable, Variable) + ~Variable(); + bool isConstExpr; + std::string mangled; + QualifiedType qualifiedType; + ExpressionObsolete *initializer; + }; + + class PreprocessedEntity; + + struct CS_API BaseClassSpecifier + { + BaseClassSpecifier(); + AccessSpecifier access; + bool isVirtual; + Type *type; + int offset; + }; + + class Class; + + class CS_API Field : public Declaration + { + public: + DECLARE_DECL_KIND(Field, Field) + ~Field(); + QualifiedType qualifiedType; + Class *_class; + bool isBitField; + unsigned bitWidth; + }; + + class CS_API AccessSpecifierDecl : public Declaration + { + public: + DECLARE_DECL_KIND(AccessSpecifierDecl, AccessSpecifier) + ~AccessSpecifierDecl(); + }; + + enum class CppAbi + { + Itanium, + Microsoft, + ARM, + iOS, + iOS64, + WebAssembly + }; + + enum class VTableComponentKind + { + VCallOffset, + VBaseOffset, + OffsetToTop, + RTTI, + FunctionPointer, + CompleteDtorPointer, + DeletingDtorPointer, + UnusedFunctionPointer, + }; + + struct CS_API VTableComponent + { + VTableComponent(); + VTableComponentKind kind; + unsigned offset; + Declaration *declaration; + }; + + struct CS_API VTableLayout + { + VTableLayout(); + VTableLayout(const VTableLayout &); + ~VTableLayout(); + VECTOR(VTableComponent, Components) + }; + + struct CS_API VFTableInfo + { + VFTableInfo(); + VFTableInfo(const VFTableInfo &); + uint64_t VBTableIndex; + uint32_t VFPtrOffset; + uint32_t VFPtrFullOffset; + VTableLayout layout; + }; + + class CS_API LayoutField + { + public: + LayoutField(); + LayoutField(const LayoutField &other); + ~LayoutField(); + unsigned offset; + std::string name; + QualifiedType qualifiedType; + void *fieldPtr; + }; + + class Class; + + class CS_API LayoutBase + { + public: + LayoutBase(); + LayoutBase(const LayoutBase &other); + ~LayoutBase(); + unsigned offset; + Class *_class; + }; + + enum class RecordArgABI + { + /// Pass it using the normal C aggregate rules for the ABI, + /// potentially introducing extra copies and passing some + /// or all of it in registers. + Default = 0, + /// Pass it on the stack using its defined layout. + /// The argument must be evaluated directly into the correct + /// stack position in the arguments area, and the call machinery + /// must not move it or introduce extra copies. + DirectInMemory, + /// Pass it as a pointer to temporary memory. + Indirect + }; + + struct CS_API ClassLayout + { + ClassLayout(); + CppAbi ABI; + RecordArgABI argABI; + VECTOR(VFTableInfo, VFTables) + VTableLayout layout; + bool hasOwnVFPtr; + long VBPtrOffset; + int alignment; + int size; + int dataSize; + VECTOR(LayoutField, Fields) + VECTOR(LayoutBase, Bases) + }; + + enum class TagKind + { + Struct, + Interface, + Union, + Class, + Enum + }; + + class CS_API Class : public DeclarationContext + { + public: + Class(); + ~Class(); + + VECTOR(BaseClassSpecifier *, Bases) + VECTOR(Field *, Fields) + VECTOR(Method *, Methods) + VECTOR(AccessSpecifierDecl *, Specifiers) + + bool isPOD; + bool isAbstract; + bool isUnion; + bool isDynamic; + bool isPolymorphic; + bool hasNonTrivialDefaultConstructor; + bool hasNonTrivialCopyConstructor; + bool hasNonTrivialDestructor; + bool isExternCContext; + bool isInjected; + TagKind tagKind; + + ClassLayout *layout; + }; + + class CS_API Template : public Declaration + { + public: + Template(DeclarationKind kind); + DECLARE_DECL_KIND(Template, Template) + Declaration *TemplatedDecl; + VECTOR(Declaration *, Parameters) + }; + + template + T *DeclarationContext::FindTemplate(const std::string &USR) + { + auto foundTemplate = std::find_if(Templates.begin(), Templates.end(), + [&](Template *t) + { return t->USR == USR; }); + + if (foundTemplate != Templates.end()) + return static_cast(*foundTemplate); + + return nullptr; + } + + class CS_API TypeAliasTemplate : public Template + { + public: + TypeAliasTemplate(); + ~TypeAliasTemplate(); + }; + + class CS_API TemplateParameter : public Declaration + { + public: + TemplateParameter(DeclarationKind kind); + ~TemplateParameter(); + unsigned int depth; + unsigned int index; + bool isParameterPack; + }; + + class CS_API TemplateTemplateParameter : public Template + { + public: + TemplateTemplateParameter(); + ~TemplateTemplateParameter(); + + bool isParameterPack; + bool isPackExpansion; + bool isExpandedParameterPack; + }; + + class CS_API TypeTemplateParameter : public TemplateParameter + { + public: + TypeTemplateParameter(); + TypeTemplateParameter(const TypeTemplateParameter &); + ~TypeTemplateParameter(); + + QualifiedType defaultArgument; + }; + + class CS_API NonTypeTemplateParameter : public TemplateParameter + { + public: + NonTypeTemplateParameter(); + NonTypeTemplateParameter(const NonTypeTemplateParameter &); + ~NonTypeTemplateParameter(); + ExpressionObsolete *defaultArgument; + Expr *defaultArgumentNew; + unsigned int position; + bool isPackExpansion; + bool isExpandedParameterPack; + QualifiedType type; + }; + + class ClassTemplateSpecialization; + class ClassTemplatePartialSpecialization; + + class CS_API ClassTemplate : public Template + { + public: + ClassTemplate(); + ~ClassTemplate(); + VECTOR(ClassTemplateSpecialization *, Specializations) + ClassTemplateSpecialization *FindSpecialization(const std::string &usr); + ClassTemplatePartialSpecialization *FindPartialSpecialization(const std::string &usr); + }; + + enum class TemplateSpecializationKind + { + Undeclared, + ImplicitInstantiation, + ExplicitSpecialization, + ExplicitInstantiationDeclaration, + ExplicitInstantiationDefinition + }; + + class CS_API ClassTemplateSpecialization : public Class + { + public: + ClassTemplateSpecialization(); + ~ClassTemplateSpecialization(); + ClassTemplate *templatedDecl; + VECTOR(TemplateArgument, Arguments) + TemplateSpecializationKind specializationKind; + }; + + class CS_API ClassTemplatePartialSpecialization : public ClassTemplateSpecialization + { + public: + ClassTemplatePartialSpecialization(); + ~ClassTemplatePartialSpecialization(); + }; + + class CS_API FunctionTemplate : public Template + { + public: + FunctionTemplate(); + ~FunctionTemplate(); + VECTOR(FunctionTemplateSpecialization *, Specializations) + FunctionTemplateSpecialization *FindSpecialization(const std::string &usr); + }; + + class CS_API FunctionTemplateSpecialization + { + public: + FunctionTemplateSpecialization(); + ~FunctionTemplateSpecialization(); + FunctionTemplate *_template; + VECTOR(TemplateArgument, Arguments) + Function *specializedFunction; + TemplateSpecializationKind specializationKind; + }; + + class VarTemplateSpecialization; + class VarTemplatePartialSpecialization; + + class CS_API VarTemplate : public Template + { + public: + VarTemplate(); + ~VarTemplate(); + VECTOR(VarTemplateSpecialization *, Specializations) + VarTemplateSpecialization *FindSpecialization(const std::string &usr); + VarTemplatePartialSpecialization *FindPartialSpecialization(const std::string &usr); + }; + + class CS_API VarTemplateSpecialization : public Variable + { + public: + VarTemplateSpecialization(); + ~VarTemplateSpecialization(); + VarTemplate *templatedDecl; + VECTOR(TemplateArgument, Arguments) + TemplateSpecializationKind specializationKind; + }; + + class CS_API VarTemplatePartialSpecialization : public VarTemplateSpecialization + { + public: + VarTemplatePartialSpecialization(); + ~VarTemplatePartialSpecialization(); + }; + + class CS_API UnresolvedUsingTypename : public Declaration + { + public: + UnresolvedUsingTypename(); + ~UnresolvedUsingTypename(); + }; + + class CS_API Namespace : public DeclarationContext + { + public: + Namespace(); + ~Namespace(); + bool isInline; + }; + + enum class MacroLocation + { + Unknown, + ClassHead, + ClassBody, + FunctionHead, + FunctionParameters, + FunctionBody, + }; + + class CS_API PreprocessedEntity + { + public: + PreprocessedEntity(); + MacroLocation macroLocation; + void *originalPtr; + DeclarationKind kind; + }; + + class CS_API MacroDefinition : public PreprocessedEntity + { + public: + MacroDefinition(); + ~MacroDefinition(); + std::string name; + std::string expression; + int lineNumberStart; + int lineNumberEnd; + }; + + class CS_API MacroExpansion : public PreprocessedEntity + { + public: + MacroExpansion(); + ~MacroExpansion(); + std::string name; + std::string text; + MacroDefinition *definition; + }; + + class CS_API TranslationUnit : public Namespace + { + public: + TranslationUnit(); + ~TranslationUnit(); + std::string fileName; + bool isSystemHeader; + VECTOR(MacroDefinition *, Macros) + }; + + class CS_API ASTContext + { + public: + ASTContext(); + ~ASTContext(); + TranslationUnit *FindOrCreateModule(std::string File); + VECTOR(TranslationUnit *, TranslationUnits) + }; + + } + } +} \ No newline at end of file diff --git a/src/CppParser/Parser.cpp b/src/CppParser/Parser.cpp index a64b091c95..97d7736643 100644 --- a/src/CppParser/Parser.cpp +++ b/src/CppParser/Parser.cpp @@ -104,6 +104,8 @@ static CppAbi GetClassLayoutAbi(clang::TargetCXXABI::Kind abi) return CppAbi::iOS; case clang::TargetCXXABI::AppleARM64: return CppAbi::iOS64; + case clang::TargetCXXABI::WebAssembly: + return CppAbi::WebAssembly; default: llvm_unreachable("Unsupported C++ ABI kind"); } @@ -872,14 +874,31 @@ static bool IsRecordValid(const clang::RecordDecl* RC) return IsRecordValid(RC, Visited); } -static clang::CXXRecordDecl* GetCXXRecordDeclFromBaseType(const clang::QualType& Ty) { +static clang::CXXRecordDecl* GetCXXRecordDeclFromTemplateName(const clang::TemplateName& Name) +{ + using namespace clang; + + switch (Name.getKind()) { + case clang::TemplateName::Template: + return dyn_cast( + Name.getAsTemplateDecl()->getTemplatedDecl()); + case clang::TemplateName::QualifiedTemplate: + return dyn_cast( + Name.getAsQualifiedTemplateName()->getTemplateDecl()->getTemplatedDecl()); + default: + assert(0 && "Unknown template name kind"); + return nullptr; + } +} + +static clang::CXXRecordDecl* GetCXXRecordDeclFromBaseType(const clang::QualType& Ty) +{ using namespace clang; if (auto RT = Ty->getAs()) return dyn_cast(RT->getDecl()); else if (auto TST = Ty->getAs()) - return dyn_cast( - TST->getTemplateName().getAsTemplateDecl()->getTemplatedDecl()); + return GetCXXRecordDeclFromTemplateName(TST->getTemplateName()); else if (auto Injected = Ty->getAs()) return Injected->getDecl(); @@ -1428,6 +1447,7 @@ NonTypeTemplateParameter* Parser::WalkNonTypeTemplateParameter(const clang::NonT HandleDeclaration(NTTPD, NTP); if (NTTPD->hasDefaultArgument()) NTP->defaultArgument = WalkExpressionObsolete(NTTPD->getDefaultArgument()); + NTP->type = GetQualifiedType(NTTPD->getType()); NTP->depth = NTTPD->getDepth(); NTP->index = NTTPD->getIndex(); NTP->isParameterPack = NTTPD->isParameterPack(); diff --git a/src/Generator.Tests/GeneratorTest.cs b/src/Generator.Tests/GeneratorTest.cs index feff986fb8..3805353ad7 100644 --- a/src/Generator.Tests/GeneratorTest.cs +++ b/src/Generator.Tests/GeneratorTest.cs @@ -35,23 +35,21 @@ public virtual void Setup(Driver driver) 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)); } } @@ -72,16 +70,16 @@ public virtual void SetupPasses(Driver driver) public static string GetTestsDirectory(string name) { var directory = new DirectoryInfo( - Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)); + Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location) ?? string.Empty); 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; @@ -89,15 +87,12 @@ public static string GetTestsDirectory(string name) directory = directory.Parent; } - throw new Exception(string.Format( - "Tests directory for project '{0}' was not found", name)); + throw new Exception($"Tests directory for project '{name}' was not found"); } static string GetOutputDirectory() { - string exePath = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath; - var directory = Directory.GetParent(exePath); - + var directory = Directory.GetParent(Assembly.GetExecutingAssembly().Location); while (directory != null) { var path = Path.Combine(directory.FullName, "build"); diff --git a/src/Generator/AST/VTables.cs b/src/Generator/AST/VTables.cs index 13add5b8fc..93e59ed9dc 100644 --- a/src/Generator/AST/VTables.cs +++ b/src/Generator/AST/VTables.cs @@ -34,6 +34,7 @@ private static List GatherVTableMethodEntries(VTableLayout layo where component.Kind != VTableComponentKind.CompleteDtorPointer && component.Kind != VTableComponentKind.RTTI && component.Kind != VTableComponentKind.UnusedFunctionPointer && + component.Kind != VTableComponentKind.OffsetToTop && component.Method != null select component); diff --git a/src/Generator/Driver.cs b/src/Generator/Driver.cs index 3f9a847ec5..82780bfa2c 100644 --- a/src/Generator/Driver.cs +++ b/src/Generator/Driver.cs @@ -8,6 +8,7 @@ using CppSharp.Generators.CLI; using CppSharp.Generators.Cpp; using CppSharp.Generators.CSharp; +using CppSharp.Generators.Emscripten; using CppSharp.Generators.TS; using CppSharp.Parser; using CppSharp.Passes; @@ -43,6 +44,8 @@ Generator CreateGeneratorFromKind(GeneratorKind kind) return new CLIGenerator(Context); case GeneratorKind.CSharp: return new CSharpGenerator(Context); + case GeneratorKind.Emscripten: + return new EmscriptenGenerator(Context); case GeneratorKind.QuickJS: return new QuickJSGenerator(Context); case GeneratorKind.NAPI: @@ -82,7 +85,7 @@ void ValidateOptions() 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); @@ -109,7 +112,8 @@ void OnFileParsed(IEnumerable files, ParserResult result) 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)); @@ -180,27 +184,22 @@ public bool ParseLibraries() 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; @@ -212,95 +211,99 @@ public bool ParseLibraries() 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() @@ -342,10 +345,10 @@ public void SaveCode(IEnumerable outputs) 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); } } } @@ -364,7 +367,7 @@ private void WriteGeneratedCodeToFile(string file, string generatedCode) 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}"); @@ -375,7 +378,7 @@ public bool CompileCode(Module module) if (error == 0) { Diagnostics.Message($@"Compilation succeeded: { - libraryMappings[module] = Path.Combine( + LibraryMappings[module] = Path.Combine( Options.OutputDir, $"{module.LibraryName}.dll")}."); return true; } @@ -404,7 +407,7 @@ public void Dispose() } private bool hasParsingErrors; - private static readonly Dictionary libraryMappings = new Dictionary(); + private static readonly Dictionary LibraryMappings = new(); } public static class ConsoleDriver @@ -412,67 +415,68 @@ public static class ConsoleDriver public static void Run(ILibrary library) { var options = new DriverOptions(); - using (var driver = new Driver(options)) - { - library.Setup(driver); + using var driver = new Driver(options); + library.Setup(driver); - driver.Setup(); + driver.Setup(); - if (driver.Options.Verbose) - Diagnostics.Level = DiagnosticKind.Debug; + if (driver.Options.Verbose) + Diagnostics.Level = DiagnosticKind.Debug; - if (!options.Quiet) - Diagnostics.Message("Parsing libraries..."); + if (!options.Quiet) + Diagnostics.Message("Parsing libraries..."); - if (!driver.ParseLibraries()) - return; + if (!driver.ParseLibraries()) + return; - if (!options.Quiet) - Diagnostics.Message("Parsing code..."); + if (!options.Quiet) + Diagnostics.Message("Parsing code..."); - if (!driver.ParseCode()) - { - Diagnostics.Error("CppSharp has encountered an error while parsing code."); - return; - } + 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()); + new CleanUnitPass { Context = driver.Context }.VisitASTContext(driver.Context.ASTContext); + foreach (var module in options.Modules.Where( + m => m != options.SystemModule && !m.Units.GetGenerated().Any())) + { + Diagnostics.Message($"Removing module {module} because no translation units are generated..."); + options.Modules.Remove(module); + } - if (!options.Quiet) - Diagnostics.Message("Processing code..."); + if (!options.Quiet) + Diagnostics.Message("Processing code..."); - driver.SetupPasses(library); - driver.SetupTypeMaps(); - driver.SetupDeclMaps(); + driver.SetupPasses(library); + driver.SetupTypeMaps(); + driver.SetupDeclMaps(); - library.Preprocess(driver, driver.Context.ASTContext); + library.Preprocess(driver, driver.Context.ASTContext); - driver.ProcessCode(); - library.Postprocess(driver, driver.Context.ASTContext); + driver.ProcessCode(); + library.Postprocess(driver, driver.Context.ASTContext); - if (!options.Quiet) - Diagnostics.Message("Generating code..."); + if (!options.Quiet) + Diagnostics.Message("Generating code..."); - if (!options.DryRun) - { - var outputs = driver.GenerateCode(); + if (options.DryRun) + return; - library.GenerateCode(driver, outputs); + var outputs = driver.GenerateCode(); - foreach (var output in outputs) - { - foreach (var pass in driver.Context.GeneratorOutputPasses.Passes) - { - pass.VisitGeneratorOutput(output); - } - } + library.GenerateCode(driver, outputs); - driver.SaveCode(outputs); - if (driver.Options.IsCSharpGenerator && driver.Options.CompileCode) - driver.Options.Modules.Any(m => !driver.CompileCode(m)); - } + 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)); } } } diff --git a/src/Generator/Generator.cs b/src/Generator/Generator.cs index e9bcc3e818..cf414b4823 100644 --- a/src/Generator/Generator.cs +++ b/src/Generator/Generator.cs @@ -14,6 +14,7 @@ public enum GeneratorKind CSharp = 2, C, CPlusPlus, + Emscripten, ObjectiveC, Java, Swift, diff --git a/src/Generator/Generators/C/CppTypePrinter.cs b/src/Generator/Generators/C/CppTypePrinter.cs index 8acd62c7cf..f289705f76 100644 --- a/src/Generator/Generators/C/CppTypePrinter.cs +++ b/src/Generator/Generators/C/CppTypePrinter.cs @@ -584,7 +584,8 @@ public override TypePrinterResult VisitClassTemplateSpecializationDecl( args.Add(arg.Type.Visit(this)); break; case TemplateArgument.ArgumentKind.Declaration: - args.Add(arg.Declaration.Visit(this)); + if (arg.Declaration != null) + args.Add(arg.Declaration.Visit(this)); break; case TemplateArgument.ArgumentKind.Integral: ClassTemplate template = specialization.TemplatedDecl; @@ -596,6 +597,7 @@ public override TypePrinterResult VisitClassTemplateSpecializationDecl( { args.Add(arg.Integral.ToString(CultureInfo.InvariantCulture)); } + break; } } @@ -634,7 +636,7 @@ public override TypePrinterResult VisitFunctionDecl(Function function) CppSharp.AST.Type desugared = function.FunctionType.Type.Desugar(); if (!desugared.IsPointerTo(out functionType)) functionType = (FunctionType)desugared; - string exceptionType = Print(functionType.ExceptionSpecType); + string exceptionType = functionType != null ? Print(functionType.ExceptionSpecType) : ""; var @return = function.OriginalReturnType.Visit(this); @return.Name = @class + name; diff --git a/src/Generator/Generators/CLI/CLIMarshal.cs b/src/Generator/Generators/CLI/CLIMarshal.cs index 1376592c92..c641651754 100644 --- a/src/Generator/Generators/CLI/CLIMarshal.cs +++ b/src/Generator/Generators/CLI/CLIMarshal.cs @@ -61,7 +61,8 @@ public override bool VisitArrayType(ArrayType array, TypeQualifiers quals) break; case ArrayType.ArraySize.Incomplete: // const char* and const char[] are the same so we can use a string - if (array.Type.Desugar().IsPrimitiveType(PrimitiveType.Char) && + if (Context.Context.Options.MarshalConstCharArrayAsString && + array.Type.Desugar().IsPrimitiveType(PrimitiveType.Char) && array.QualifiedType.Qualifiers.IsConst) { var pointer = new PointerType { QualifiedPointee = array.QualifiedType }; diff --git a/src/Generator/Generators/CLI/CLITypePrinter.cs b/src/Generator/Generators/CLI/CLITypePrinter.cs index 50ff8d46d4..69077affe2 100644 --- a/src/Generator/Generators/CLI/CLITypePrinter.cs +++ b/src/Generator/Generators/CLI/CLITypePrinter.cs @@ -35,7 +35,8 @@ public override TypePrinterResult VisitArrayType(ArrayType array, TypeQualifiers quals) { // const char* and const char[] are the same so we can use a string - if (array.SizeType == ArrayType.ArraySize.Incomplete && + if (Context.Options.MarshalConstCharArrayAsString && + array.SizeType == ArrayType.ArraySize.Incomplete && array.Type.Desugar().IsPrimitiveType(PrimitiveType.Char) && array.QualifiedType.Qualifiers.IsConst) return VisitCILType(new CILType(typeof(string)), quals); diff --git a/src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs b/src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs index c4c2f1d5d7..3884d1694c 100644 --- a/src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs +++ b/src/Generator/Generators/CSharp/CSharpExpressionPrinter.cs @@ -27,11 +27,11 @@ public string VisitParameter(Parameter parameter) if (desugared.IsPrimitiveType() && (parameter.DefaultArgument.Declaration != null || parameter.DefaultArgument.Class == StatementClass.BinaryOperator)) - return $"({desugared.Visit(typePrinter)}) {expression}"; + return $"({desugared.Visit(typePrinter)}) ({expression})"; var finalType = (desugared.GetFinalPointee() ?? desugared).Desugar(); if (finalType.TryGetClass(out var @class) && @class.IsInterface) return $@"({@class.Visit(typePrinter)}) ({ - @class.OriginalClass.Visit(typePrinter)}) {expression}"; + @class.OriginalClass.Visit(typePrinter)}) ({expression})"; return expression; } @@ -61,20 +61,15 @@ public string VisitExpression(ExpressionObsolete expr) case StatementClass.BinaryOperator: var binaryOperator = (BinaryOperatorObsolete)expr; - var lhsResult = binaryOperator.LHS.String; - if (binaryOperator.LHS.Declaration is Enumeration.Item) - lhsResult = binaryOperator.LHS.Declaration.Visit(typePrinter).Type; - - var rhsResult = binaryOperator.RHS.String; - if (binaryOperator.RHS.Declaration is Enumeration.Item) - rhsResult = binaryOperator.RHS.Declaration.Visit(typePrinter).Type; + var lhsResult = VisitExpression(binaryOperator.LHS); + var rhsResult = VisitExpression(binaryOperator.RHS); return $"{lhsResult} {binaryOperator.OpcodeStr} {rhsResult}"; case StatementClass.ConstructorReference: var constructorExpr = (CXXConstructExprObsolete)expr; if (constructorExpr.Arguments.Count == 1 && - constructorExpr.Arguments[0].Declaration is Enumeration.Item) - return constructorExpr.Arguments[0].Declaration.Visit(typePrinter).Type; + constructorExpr.Arguments[0].Class != StatementClass.Any) + return VisitExpression(constructorExpr.Arguments[0]); goto default; default: return expr.String; @@ -88,4 +83,4 @@ public string ToString(Type type) private readonly TypePrinter typePrinter; } -} \ No newline at end of file +} diff --git a/src/Generator/Generators/CSharp/CSharpMarshal.cs b/src/Generator/Generators/CSharp/CSharpMarshal.cs index 8f64f72b27..21d7279ca7 100644 --- a/src/Generator/Generators/CSharp/CSharpMarshal.cs +++ b/src/Generator/Generators/CSharp/CSharpMarshal.cs @@ -116,7 +116,8 @@ public override bool VisitArrayType(ArrayType array, TypeQualifiers quals) break; case ArrayType.ArraySize.Incomplete: // const char* and const char[] are the same so we can use a string - if (array.Type.Desugar().IsPrimitiveType(PrimitiveType.Char) && + if (Context.Context.Options.MarshalConstCharArrayAsString && + array.Type.Desugar().IsPrimitiveType(PrimitiveType.Char) && array.QualifiedType.Qualifiers.IsConst) { var pointer = new PointerType { QualifiedPointee = array.QualifiedType }; @@ -906,7 +907,8 @@ private void MarshalArray(ArrayType arrayType) var elementType = arrayType.Type.Desugar(); - if (elementType.IsPrimitiveType() || + if ((elementType.IsPrimitiveType() && + !(elementType.IsPrimitiveType(PrimitiveType.Char) && Context.Context.Options.MarshalCharAsManagedChar)) || elementType.IsPointerToPrimitiveType()) { if (Context.Context.Options.UseSpan && !elementType.IsConstCharString()) @@ -948,6 +950,10 @@ private void MarshalArray(ArrayType arrayType) Context.Before.WriteLine($@"{intermediateArray}[i] = { element} is null ? {intPtrZero} : {element}.{Helpers.InstanceIdentifier};"); } + else if (elementType.IsPrimitiveType(PrimitiveType.Char) && + Context.Context.Options.MarshalCharAsManagedChar) + Context.Before.WriteLine($@"{intermediateArray}[i] = global::System.Convert.ToSByte({ + element});"); else Context.Before.WriteLine($@"{intermediateArray}[i] = { element} is null ? new {intermediateArrayType}() : *({ diff --git a/src/Generator/Generators/CSharp/CSharpSources.cs b/src/Generator/Generators/CSharp/CSharpSources.cs index d9da8b46c6..3ee9104b1a 100644 --- a/src/Generator/Generators/CSharp/CSharpSources.cs +++ b/src/Generator/Generators/CSharp/CSharpSources.cs @@ -256,9 +256,9 @@ public virtual void GenerateNamespaceFunctionsAndVariables(DeclarationContext co .Any(); using (PushWriteBlock(BlockKind.Functions, $"public unsafe partial {(isStruct ? "struct" : "class")} {parentName}", NewLineKind.BeforeNextBlock)) - { + { using (PushWriteBlock(BlockKind.InternalsClass, GetClassInternalHead(new Class { Name = parentName }), NewLineKind.BeforeNextBlock)) - { + { // Generate all the internal function declarations. foreach (var function in context.Functions) { @@ -301,7 +301,7 @@ template.OriginalNamespace is Class && template.Name); using (PushWriteBlock(BlockKind.Namespace, namespaceName, NewLineKind.BeforeNextBlock)) - { + { var generated = GetGeneratedClasses(template, specializations); foreach (var nestedTemplate in template.Classes.Where( @@ -972,7 +972,7 @@ private string GeneratePointerTo(Variable var) string ptr = Generator.GeneratedIdentifier("ptr"); if (arrayType != null) { - if (arrayType.Type.IsPrimitiveType(PrimitiveType.Char) && arrayType.SizeType != ArrayType.ArraySize.Constant) + if (Context.Options.MarshalConstCharArrayAsString && arrayType.Type.IsPrimitiveType(PrimitiveType.Char) && arrayType.SizeType != ArrayType.ArraySize.Constant) WriteLine($"var {ptr} = {location};"); else WriteLine($"var {ptr} = ({arrayType.Type.Visit(TypePrinter)}*){location};"); @@ -1310,6 +1310,17 @@ private bool GenerateVariableGetter(Variable var) }; ctx.PushMarshalKind(MarshalKind.ReturnVariableArray); + if (var.Type.Desugar().IsPointer()) + { + var pointerType = var.Type.Desugar() as PointerType; + while (pointerType != null && !pointerType.Pointee.Desugar().IsPrimitiveType(PrimitiveType.Char)) + { + ptr = $"*{ptr}"; + pointerType = pointerType.Pointee.Desugar() as PointerType; + } + ptr = $"({TypePrinter.IntPtrType}*)({ptr})"; + } + var arrayType = var.Type.Desugar() as ArrayType; var isRefTypeArray = arrayType != null && var.Namespace is Class context && context.IsRefType; var elementType = arrayType?.Type.Desugar(); @@ -1645,19 +1656,27 @@ private void GenerateVariable(Class @class, Variable variable) var variableType = variable.Type.Visit(TypePrinter); TypePrinter.PopMarshalKind(); - var signature = $"public static {variableType} {variable.Name}"; + bool hasInitializer = variable.Initializer != null && !string.IsNullOrWhiteSpace(variable.Initializer.String); - if (variable.Initializer != null && !string.IsNullOrWhiteSpace(variable.Initializer.String)) - GeneratePropertyGetterForVariableWithInitializer(variable, signature); + if (hasInitializer && variable.QualifiedType.Qualifiers.IsConst && + (variable.Type.Desugar() is BuiltinType || variableType.ToString() == "string")) + Write($"public const {variableType} {variable.Name} = {variable.Initializer.String};"); else { - using (WriteBlock(signature)) + var signature = $"public static {variableType} {variable.Name}"; + + if (hasInitializer) + GeneratePropertyGetterForVariableWithInitializer(variable, signature); + else { - GeneratePropertyGetter(variable, @class); + using (WriteBlock(signature)) + { + GeneratePropertyGetter(variable, @class); - if (!variable.QualifiedType.Qualifiers.IsConst && - !(variable.Type.Desugar() is ArrayType)) - GeneratePropertySetter(variable, @class); + if (!variable.QualifiedType.Qualifiers.IsConst && + !(variable.Type.Desugar() is ArrayType)) + GeneratePropertySetter(variable, @class); + } } } @@ -1810,7 +1829,7 @@ public void GenerateVTable(Class @class) return __vtables; }} - set {{ + set {{ __vtables = value; }}", trimIndentation: true); } @@ -2326,13 +2345,13 @@ private void GenerateDisposeMethods(Class @class) // Normally, calling the native dtor should be controlled by whether or not we // we own the underlying instance. (i.e. Helpers.OwnsNativeInstanceIdentifier). // However, there are 2 situations when the caller needs to have direct control - // + // // 1. When we have a virtual dtor on the native side we detour the vtable entry // even when we don't own the underlying native instance. I think we do this // so that the managed side can null out the __Instance pointer and remove the // instance from the NativeToManagedMap. Of course, this is somewhat half-hearted // since we can't/don't do this when there's no virtual dtor available to detour. - // Anyway, we must be able to call the native dtor in this case even if we don't + // Anyway, we must be able to call the native dtor in this case even if we don't /// own the underlying native instance. // // 2. When we we pass a disposable object to a function "by value" then the callee @@ -2343,7 +2362,7 @@ private void GenerateDisposeMethods(Class @class) // .... // compiler generates call to f.dtor() at the end of function // } - // + // // IDisposable.Dispose() and Object.Finalize() set callNativeDtor = Helpers.OwnsNativeInstanceIdentifier WriteLine("if (callNativeDtor)"); if (@class.IsDependent || dtor.IsVirtual) @@ -2364,7 +2383,7 @@ c is ClassTemplateSpecialization ? } // If we have any fields holding references to unmanaged memory allocated here, free the - // referenced memory. Don't rely on testing if the field's IntPtr is IntPtr.Zero since + // referenced memory. Don't rely on testing if the field's IntPtr is IntPtr.Zero since // unmanaged memory isn't always initialized and/or a reference may be owned by the // native side. // @@ -2616,7 +2635,7 @@ private void Generate__CopyValue(Class @class, string @internal) using (WriteBlock($"private static void* __CopyValue({@internal} native)")) { var copyCtorMethod = @class.Methods.FirstOrDefault(method => method.IsCopyConstructor); - + if (@class.HasNonTrivialCopyConstructor && copyCtorMethod != null && copyCtorMethod.IsGenerated) { // Allocate memory for a new native object and call the ctor. @@ -2851,7 +2870,7 @@ private bool GenerateMethodBody(Class @class, Method method, private string OverloadParamNameWithDefValue(Parameter p, ref int index) { - return p.Type.IsPointerToPrimitiveType() && p.Usage == ParameterUsage.InOut && p.HasDefaultValue + return (p.Type.IsPointerToPrimitiveType() || p.Type.IsPointerToEnum()) && p.Usage == ParameterUsage.InOut && p.HasDefaultValue ? "ref param" + index++ : ExpressionPrinter.VisitParameter(p); } @@ -2870,13 +2889,15 @@ private void GenerateOverloadCall(Function function) for (int i = 0, j = 0; i < function.Parameters.Count; i++) { var parameter = function.Parameters[i]; - PrimitiveType primitiveType; + PrimitiveType primitiveType = PrimitiveType.Null; + Enumeration enumeration = null; if (parameter.Kind == ParameterKind.Regular && parameter.Ignore && - parameter.Type.IsPointerToPrimitiveType(out primitiveType) && + (parameter.Type.IsPointerToPrimitiveType(out primitiveType) || + parameter.Type.IsPointerToEnum(out enumeration)) && parameter.Usage == ParameterUsage.InOut && parameter.HasDefaultValue) { var pointeeType = ((PointerType)parameter.Type).Pointee.ToString(); - WriteLine($@"{pointeeType} param{j++} = {(primitiveType == PrimitiveType.Bool ? "false" : "0")};"); + WriteLine($@"{pointeeType} param{j++} = {(primitiveType == PrimitiveType.Bool ? "false" : $"({pointeeType})0")};"); } } @@ -2924,7 +2945,7 @@ private void GenerateEquals(Class @class) private void GenerateGetHashCode(Class @class) { using (WriteBlock("public override int GetHashCode()")) - { + { if (!@class.IsRefType) WriteLine($"return {Helpers.InstanceIdentifier}.GetHashCode();"); else @@ -3075,7 +3096,7 @@ private void GenerateClassConstructor(Method method, Class @class) // Copy any string references owned by the source to the new instance so we // don't have to ref count them. // If there is no property or no setter then this instance can never own the native - // memory. Worry about the case where there's only a setter (write-only) when we + // memory. Worry about the case where there's only a setter (write-only) when we // understand the use case and how it can occur. foreach (var prop in @class.GetConstCharFieldProperties()) { diff --git a/src/Generator/Generators/CSharp/CSharpTypePrinter.cs b/src/Generator/Generators/CSharp/CSharpTypePrinter.cs index c31a0df833..7271179569 100644 --- a/src/Generator/Generators/CSharp/CSharpTypePrinter.cs +++ b/src/Generator/Generators/CSharp/CSharpTypePrinter.cs @@ -111,7 +111,8 @@ public override TypePrinterResult VisitArrayType(ArrayType array, } // const char* and const char[] are the same so we can use a string - if (array.SizeType == ArrayType.ArraySize.Incomplete && + if (Context.Options.MarshalConstCharArrayAsString && + array.SizeType == ArrayType.ArraySize.Incomplete && arrayType.IsPrimitiveType(PrimitiveType.Char) && array.QualifiedType.Qualifiers.IsConst) return "string"; @@ -123,6 +124,13 @@ public override TypePrinterResult VisitArrayType(ArrayType array, return $"{prefix}string[]"; } + if (arrayType.IsPrimitiveType(PrimitiveType.Bool)) + { + var prefix = ContextKind == TypePrinterContextKind.Managed ? string.Empty : + "[MarshalAs(UnmanagedType.LPArray, ArraySubType = UnmanagedType.I1)] "; + return $"{prefix}bool[]"; + } + if (Context.Options.UseSpan && !(array.SizeType != ArrayType.ArraySize.Constant && MarshalKind == MarshalKind.ReturnVariableArray)) { diff --git a/src/Generator/Generators/CodeGenerator.cs b/src/Generator/Generators/CodeGenerator.cs index 39eb7e4984..e0057a13d1 100644 --- a/src/Generator/Generators/CodeGenerator.cs +++ b/src/Generator/Generators/CodeGenerator.cs @@ -316,7 +316,7 @@ public virtual bool VisitClassDeclContext(Class @class) property.Visit(this); } - VisitClassConstructors(@class); + VisitClassConstructors(@class.Constructors.Where(c => !ASTUtils.CheckIgnoreMethod(c))); VisitClassMethods(@class); return true; @@ -333,9 +333,9 @@ public virtual void VisitClassMethods(Class @class) } } - public virtual void VisitClassConstructors(Class @class) + public virtual void VisitClassConstructors(IEnumerable constructors) { - foreach (var ctor in @class.Constructors.Where(c => !ASTUtils.CheckIgnoreMethod(c))) + foreach (var ctor in constructors) { ctor.Visit(this); } diff --git a/src/Generator/Generators/Emscripten/EmscriptenGenerator.cs b/src/Generator/Generators/Emscripten/EmscriptenGenerator.cs new file mode 100644 index 0000000000..f2f7e71a14 --- /dev/null +++ b/src/Generator/Generators/Emscripten/EmscriptenGenerator.cs @@ -0,0 +1,73 @@ +using System.Collections.Generic; +using System.Linq; +using CppSharp.AST; +using CppSharp.Generators.Cpp; + +namespace CppSharp.Generators.Emscripten +{ + /// + /// Emscripten generator responsible for driving the generation of binding files. + /// Embind documentation: https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html + /// + public class EmscriptenGenerator : CppGenerator + { + public EmscriptenGenerator(BindingContext context) : base(context) + { + } + + public override List Generate() + { + var outputs = base.Generate(); + + foreach (var module in Context.Options.Modules) + { + if (module == Context.Options.SystemModule) + continue; + + var output = GenerateModule(module); + if (output != null) + { + OnUnitGenerated(output); + outputs.Add(output); + } + } + + return outputs; + } + + public override List Generate(IEnumerable units) + { + var outputs = new List(); + + var header = new EmscriptenHeaders(Context, units); + outputs.Add(header); + + var source = new EmscriptenSources(Context, units); + outputs.Add(source); + + return outputs; + } + + public override GeneratorOutput GenerateModule(Module module) + { + if (module == Context.Options.SystemModule) + return null; + + var moduleGen = new EmscriptenModule(Context, module); + + var output = new GeneratorOutput + { + TranslationUnit = new TranslationUnit + { + FilePath = $"{module.LibraryName}_embind_module.cpp", + Module = module + }, + Outputs = new List { moduleGen } + }; + + output.Outputs[0].Process(); + + return output; + } + } +} diff --git a/src/Generator/Generators/Emscripten/EmscriptenHeaders.cs b/src/Generator/Generators/Emscripten/EmscriptenHeaders.cs new file mode 100644 index 0000000000..2cd8a3e400 --- /dev/null +++ b/src/Generator/Generators/Emscripten/EmscriptenHeaders.cs @@ -0,0 +1,48 @@ +using System.Collections.Generic; +using CppSharp.AST; + +namespace CppSharp.Generators.Emscripten +{ + /// + /// Generates Emscripten Embind C/C++ header files. + /// Embind documentation: https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html + /// + public sealed class EmscriptenHeaders : EmscriptenCodeGenerator + { + public EmscriptenHeaders(BindingContext context, IEnumerable units) + : base(context, units) + { + CTypePrinter.PushContext(TypePrinterContextKind.Managed); + } + + //public override bool ShouldGenerateNamespaces => false; + + public override void Process() + { + GenerateFilePreamble(CommentKind.BCPL); + + PushBlock(BlockKind.Includes); + WriteLine("#pragma once"); + NewLine(); + PopBlock(); + + var name = GetTranslationUnitName(TranslationUnit); + WriteLine($"extern \"C\" void embind_init_{name}();"); + } + + public override bool VisitClassDecl(Class @class) + { + return true; + } + + public override bool VisitEvent(Event @event) + { + return true; + } + + public override bool VisitFieldDecl(Field field) + { + return true; + } + } +} diff --git a/src/Generator/Generators/Emscripten/EmscriptenMarshal.cs b/src/Generator/Generators/Emscripten/EmscriptenMarshal.cs new file mode 100644 index 0000000000..0e05a74042 --- /dev/null +++ b/src/Generator/Generators/Emscripten/EmscriptenMarshal.cs @@ -0,0 +1,21 @@ +using CppSharp.Generators.C; + +namespace CppSharp.Generators.Emscripten +{ + public class EmscriptenMarshalNativeToManagedPrinter : MarshalPrinter + { + public EmscriptenMarshalNativeToManagedPrinter(MarshalContext marshalContext) + : base(marshalContext) + { + } + } + + public class EmscriptenMarshalManagedToNativePrinter : MarshalPrinter + { + public EmscriptenMarshalManagedToNativePrinter(MarshalContext ctx) + : base(ctx) + { + Context.MarshalToNative = this; + } + } +} diff --git a/src/Generator/Generators/Emscripten/EmscriptenModule.cs b/src/Generator/Generators/Emscripten/EmscriptenModule.cs new file mode 100644 index 0000000000..e92c4bcf7c --- /dev/null +++ b/src/Generator/Generators/Emscripten/EmscriptenModule.cs @@ -0,0 +1,89 @@ +using System.IO; +using System.Linq; +using CppSharp.AST; +using CppSharp.Generators.C; + +namespace CppSharp.Generators.Emscripten +{ + /// + /// Generates Emscripten module init files. + /// Embind documentation: https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html + /// + public class EmscriptenModule : EmscriptenCodeGenerator + { + private readonly Module module; + + public EmscriptenModule(BindingContext context, Module module) + : base(context, module.Units.GetGenerated()) + { + this.module = module; + } + + public override string FileExtension { get; } = "cpp"; + + public override void Process() + { + GenerateFilePreamble(CommentKind.BCPL); + NewLine(); + + PushBlock(BlockKind.Includes); + { + WriteInclude(new CInclude() + { + File = "emscripten/bind.h", + Kind = CInclude.IncludeKind.Angled + }); + + foreach (var unit in TranslationUnits) + WriteInclude(GetIncludeFileName(Context, unit), CInclude.IncludeKind.Quoted); + } + PopBlock(NewLineKind.Always); + + WriteLine("extern \"C\" {"); + NewLine(); + + PushBlock(BlockKind.ForwardReferences); + { + foreach (var unit in TranslationUnits.Where(unit => unit.IsGenerated)) + { + var name = GetTranslationUnitName(unit); + WriteLine($"void embind_init_{name}();"); + } + } + PopBlock(NewLineKind.Always); + + var moduleName = module.LibraryName; + WriteLine($"void embind_init_{moduleName}()"); + WriteOpenBraceAndIndent(); + + foreach (var unit in TranslationUnits) + { + var name = GetTranslationUnitName(unit); + WriteLine($"embind_init_{name}();"); + } + + UnindentAndWriteCloseBrace(); + + NewLine(); + WriteLine("}"); + NewLine(); + + WriteLine($"static struct EmBindInit_{moduleName} : emscripten::internal::InitFunc {{"); + WriteLineIndent($"EmBindInit_{moduleName}() : InitFunc(embind_init_{moduleName}) {{}}"); + WriteLine($"}} EmBindInit_{moduleName}_instance;"); + } + + public static string GetIncludeFileName(BindingContext context, TranslationUnit unit) + { + // TODO: Replace with GetIncludePath + string file; + if (context.Options.GenerateName != null) + file = context.Options.GenerateName(unit); + else + file = Path.GetFileNameWithoutExtension(unit.FileName) + .Replace('\\', '/'); + + return $"{file}.h"; + } + } +} diff --git a/src/Generator/Generators/Emscripten/EmscriptenSources.cs b/src/Generator/Generators/Emscripten/EmscriptenSources.cs new file mode 100644 index 0000000000..4e786b0400 --- /dev/null +++ b/src/Generator/Generators/Emscripten/EmscriptenSources.cs @@ -0,0 +1,202 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using CppSharp.AST; +using CppSharp.AST.Extensions; +using CppSharp.Generators.C; +using CppSharp.Generators.Cpp; + +namespace CppSharp.Generators.Emscripten +{ + public class EmscriptenCodeGenerator : MethodGroupCodeGenerator + { + protected EmscriptenCodeGenerator(BindingContext context, IEnumerable units) + : base(context, units) + { + } + + public virtual MarshalPrinter GetMarshalManagedToNativePrinter(MarshalContext ctx) + { + return new EmscriptenMarshalManagedToNativePrinter(ctx); + } + + public virtual MarshalPrinter GetMarshalNativeToManagedPrinter(MarshalContext ctx) + { + return new EmscriptenMarshalNativeToManagedPrinter(ctx); + } + + public override bool VisitClassTemplateDecl(ClassTemplate template) + { + return true; + } + + public override bool VisitFunctionTemplateDecl(FunctionTemplate template) + { + return true; + } + } + + /// + /// Generates Emscripten C/C++ source files. + /// Embind documentation: https://emscripten.org/docs/porting/connecting_cpp_and_javascript/embind.html + /// + public class EmscriptenSources : EmscriptenCodeGenerator + { + public override string FileExtension => "cpp"; + + public EmscriptenSources(BindingContext context, IEnumerable units) + : base(context, units) + { + } + + public override void Process() + { + GenerateFilePreamble(CommentKind.BCPL); + + PushBlock(BlockKind.Includes); + { + WriteInclude(new CInclude() + { + File = "emscripten/bind.h", + Kind = CInclude.IncludeKind.Angled + }); + + foreach (var unit in TranslationUnits) + { + WriteInclude(unit.IncludePath, CInclude.IncludeKind.Angled); + } + } + PopBlock(NewLineKind.Always); + + var name = GetTranslationUnitName(TranslationUnit); + WriteLine($"extern \"C\" void embind_init_{name}()"); + WriteOpenBraceAndIndent(); + VisitNamespace(TranslationUnit); + UnindentAndWriteCloseBrace(); + } + + public override bool VisitClassDecl(Class @class) + { + if (@class.IsIncomplete) + return true; + + PushBlock(); + Write($"emscripten::class_<{@class.QualifiedOriginalName}"); + if (@class.HasBaseClass) + Write($", emscripten::base<{@class.BaseClass.QualifiedOriginalName}>"); + WriteLine($">(\"{@class.Name}\")"); + + VisitClassDeclContext(@class); + + WriteLineIndent(";"); + PopBlock(NewLineKind.BeforeNextBlock); + return true; + } + + public override void VisitClassConstructors(IEnumerable ctors) + { + var overloadCheck = new HashSet(); + foreach (var ctor in ctors) + { + if (overloadCheck.Contains(ctor.Parameters.Count)) + { + Console.WriteLine($"Ignoring overloaded ctor: {ctor.QualifiedOriginalName}"); + continue; + } + + var cppTypePrinter = new CppTypePrinter(Context) + { + PrintFlavorKind = CppTypePrintFlavorKind.Cpp + }; + cppTypePrinter.PushContext(TypePrinterContextKind.Native); + + var parameters = ctor.Parameters.Select(p => p.Type.Visit(cppTypePrinter).Type); + WriteLineIndent($".constructor<{string.Join(", ", parameters)}>()"); + + overloadCheck.Add(ctor.Parameters.Count); + } + } + + public override bool VisitMethodDecl(Method method) + { + Indent(); + var ret = VisitFunctionDecl(method); + Unindent(); + return ret; + } + + public override bool VisitFieldDecl(Field field) + { + WriteLineIndent($".field(\"{field.Name}\", &{field.Class.QualifiedOriginalName}::{field.OriginalName})"); + return true; + } + + public override void GenerateMethodGroup(List @group) + { + if (@group.Count > 1) + { + Console.WriteLine($"Ignoring method group: {@group.First().QualifiedOriginalName}"); + return; + } + + base.GenerateMethodGroup(@group); + } + + public override void GenerateFunctionGroup(List @group) + { + if (@group.Count > 1) + { + Console.WriteLine($"Ignoring function group: {@group.First().QualifiedOriginalName}"); + return; + } + + base.GenerateFunctionGroup(@group); + } + + public override void VisitDeclContextFunctions(DeclarationContext context) + { + PushBlock(); + base.VisitDeclContextFunctions(context); + PopBlock(NewLineKind.BeforeNextBlock); + } + + public override bool VisitFunctionDecl(Function function) + { + var prefix = function is Method ? ".function" : "emscripten::function"; + Write($"{prefix}(\"{function.Name}\", &{function.QualifiedOriginalName}"); + + var hasPointers = function.ReturnType.Type.IsPointer() || + function.Parameters.Any(p => p.Type.IsPointer()); + if (hasPointers) + Write(", emscripten::allow_raw_pointers()"); + + WriteLine(function is not Method ? ");" : $")"); + return true; + } + + public override bool VisitEnumDecl(Enumeration @enum) + { + if (@enum.IsIncomplete) + return false; + + PushBlock(); + + WriteLine($"emscripten::enum_<{@enum.Name}>(\"{@enum.QualifiedOriginalName}\")"); + foreach (var item in @enum.Items) + { + WriteLineIndent(@enum.IsScoped + ? $".value(\"{item.Name}\", {@enum.QualifiedOriginalName}::{item.OriginalName})" + : $".value(\"{item.Name}\", {item.QualifiedOriginalName})"); + } + WriteLineIndent(";"); + + PopBlock(NewLineKind.BeforeNextBlock); + return true; + } + + public override bool VisitTypedefDecl(TypedefDecl typedef) + { + return true; + } + } +} diff --git a/src/Generator/Generators/Emscripten/EmscriptenTypePrinter.cs b/src/Generator/Generators/Emscripten/EmscriptenTypePrinter.cs new file mode 100644 index 0000000000..b5d5cd8816 --- /dev/null +++ b/src/Generator/Generators/Emscripten/EmscriptenTypePrinter.cs @@ -0,0 +1,11 @@ +using CppSharp.Generators.C; + +namespace CppSharp.Generators.Emscripten +{ + public class EmscriptenTypePrinter : CppTypePrinter + { + public EmscriptenTypePrinter(BindingContext context) : base(context) + { + } + } +} diff --git a/src/Generator/Generators/NAPI/NAPIHelpers.cs b/src/Generator/Generators/NAPI/NAPIHelpers.cs index a1f4b93971..858c488cea 100644 --- a/src/Generator/Generators/NAPI/NAPIHelpers.cs +++ b/src/Generator/Generators/NAPI/NAPIHelpers.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.IO; using System.Linq; using CppSharp.AST; using CppSharp.AST.Extensions; @@ -9,11 +10,9 @@ namespace CppSharp.Generators.Cpp { - public class NAPICodeGenerator : CCodeGenerator + public class MethodGroupCodeGenerator : CCodeGenerator { - public override string FileExtension => "cpp"; - - public NAPICodeGenerator(BindingContext context, IEnumerable units) + protected MethodGroupCodeGenerator(BindingContext context, IEnumerable units) : base(context, units) { } @@ -43,9 +42,9 @@ public override bool VisitClassDecl(Class @class) return VisitClassDeclContext(@class); } - public override void VisitClassConstructors(Class @class) + public override void VisitClassConstructors(IEnumerable ctors) { - var constructors = @class.Constructors.Where(c => c.IsGenerated && !c.IsCopyConstructor) + var constructors = ctors.Where(c => c.IsGenerated && !c.IsCopyConstructor) .ToList(); if (!constructors.Any()) @@ -59,7 +58,7 @@ public static bool ShouldGenerate(Function function) if (!function.IsGenerated) return false; - if (!(function is Method method)) + if (function is not Method method) return true; if (method.IsConstructor || method.IsDestructor) @@ -88,10 +87,27 @@ public virtual void GenerateMethodGroup(List @group) foreach (var method in @group) { method.Visit(this); - return; } } + public static string GetTranslationUnitName(TranslationUnit unit) + { + var paths = unit.FileRelativePath.Split('/').ToList(); + paths = paths.Select(p => Path.GetFileNameWithoutExtension(p.ToLowerInvariant())).ToList(); + var name = string.Join('_', paths); + return name; + } + } + + public class NAPICodeGenerator : MethodGroupCodeGenerator + { + public override string FileExtension => "cpp"; + + public NAPICodeGenerator(BindingContext context, IEnumerable units) + : base(context, units) + { + } + public virtual MarshalPrinter GetMarshalManagedToNativePrinter(MarshalContext ctx) { return new NAPIMarshalManagedToNativePrinter(ctx); diff --git a/src/Generator/Generators/NAPI/NAPISources.cs b/src/Generator/Generators/NAPI/NAPISources.cs index b6676f8b11..a78d2948b4 100644 --- a/src/Generator/Generators/NAPI/NAPISources.cs +++ b/src/Generator/Generators/NAPI/NAPISources.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Generic; -using System.Globalization; using System.IO; using System.Linq; using CppSharp.AST; @@ -24,14 +23,6 @@ public NAPISources(BindingContext context, IEnumerable units) { } - public static string GetTranslationUnitName(TranslationUnit unit) - { - var paths = unit.FileRelativePath.Split('/').ToList(); - paths = paths.Select(p => Path.GetFileNameWithoutExtension(p.ToLowerInvariant())).ToList(); - var name = string.Join('_', paths); - return name; - } - public override void Process() { GenerateFilePreamble(CommentKind.BCPL); diff --git a/src/Generator/Generators/QuickJS/QuickJSSources.cs b/src/Generator/Generators/QuickJS/QuickJSSources.cs index 3facf63fd1..7f98a8017a 100644 --- a/src/Generator/Generators/QuickJS/QuickJSSources.cs +++ b/src/Generator/Generators/QuickJS/QuickJSSources.cs @@ -198,7 +198,7 @@ public QuickJSClassFuncDef(BindingContext context) : base(context, null) { } - public override void VisitClassConstructors(Class @class) + public override void VisitClassConstructors(IEnumerable ctors) { } diff --git a/src/Generator/Options.cs b/src/Generator/Options.cs index 0f0bc25790..df924b86f3 100644 --- a/src/Generator/Options.cs +++ b/src/Generator/Options.cs @@ -115,7 +115,7 @@ public bool DoAllModulesHaveLibraries() => /// /// Enable this option to enable generation of finalizers. Works in both CLI and - /// C# backends. + /// C# backends. /// /// /// Use to specify a filter so that @@ -125,7 +125,7 @@ public bool DoAllModulesHaveLibraries() => /// /// A filter that can restrict the classes for which finalizers are generated when - /// is true. + /// is true. /// /// /// The default filter performs no filtering so that whenever public readonly List DependentNameSpaces = new List(); public bool MarshalCharAsManagedChar { get; set; } + public bool MarshalConstCharArrayAsString { get; set; } = true; /// /// Use Span Struct instead of Managed Array diff --git a/src/Generator/Passes/CheckAmbiguousFunctions.cs b/src/Generator/Passes/CheckAmbiguousFunctions.cs index 964a12c694..a2001c0a7c 100644 --- a/src/Generator/Passes/CheckAmbiguousFunctions.cs +++ b/src/Generator/Passes/CheckAmbiguousFunctions.cs @@ -62,7 +62,7 @@ public override bool VisitFunctionDecl(AST.Function function) } if (function.IsAmbiguous) - Diagnostics.Message($"Found ambiguous overload: {function.QualifiedOriginalName}"); + Diagnostics.Debug($"Found ambiguous overload: {function.QualifiedOriginalName}"); return true; } diff --git a/src/Generator/Passes/CheckDuplicatedNamesPass.cs b/src/Generator/Passes/CheckDuplicatedNamesPass.cs index 1ccefa4261..0a2d7622ab 100644 --- a/src/Generator/Passes/CheckDuplicatedNamesPass.cs +++ b/src/Generator/Passes/CheckDuplicatedNamesPass.cs @@ -7,6 +7,7 @@ using CppSharp.Generators.C; using CppSharp.Generators.CLI; using CppSharp.Generators.CSharp; +using CppSharp.Generators.Emscripten; using CppSharp.Types; namespace CppSharp.Passes @@ -204,6 +205,9 @@ private TypePrinter GetTypePrinter(GeneratorKind kind, BindingContext context) case GeneratorKind.C: typePrinter = new CppTypePrinter(Context) { PrintFlavorKind = CppTypePrintFlavorKind.C }; break; + case GeneratorKind.Emscripten: + typePrinter = new EmscriptenTypePrinter(Context); + break;; case GeneratorKind.CPlusPlus: case GeneratorKind.QuickJS: case GeneratorKind.NAPI: diff --git a/src/Generator/Passes/CleanUnitPass.cs b/src/Generator/Passes/CleanUnitPass.cs index 4d1b3750d4..3afaa028fd 100644 --- a/src/Generator/Passes/CleanUnitPass.cs +++ b/src/Generator/Passes/CleanUnitPass.cs @@ -31,6 +31,11 @@ private Module GetModule(TranslationUnit unit) includeDir = "."; includeDir = Path.GetFullPath(includeDir); + // Added in https://github.com/mono/CppSharp/pull/1736, but causes us issues. + // return Options.Modules.FirstOrDefault( + // m => m.IncludeDirs.Any(i => Path.GetFullPath(i) == includeDir)) ?? + // Options.Modules[1]; + Module module = Options.Modules.Find( m => m.IncludeDirs.Any(i => Path.GetFullPath(i) == includeDir)); if (module == null) diff --git a/src/Generator/Passes/FieldToPropertyPass.cs b/src/Generator/Passes/FieldToPropertyPass.cs index d94adebb68..9b90a431b8 100644 --- a/src/Generator/Passes/FieldToPropertyPass.cs +++ b/src/Generator/Passes/FieldToPropertyPass.cs @@ -33,8 +33,7 @@ public override bool VisitFieldDecl(Field field) 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. diff --git a/src/Generator/Passes/GetterSetterToPropertyPass.cs b/src/Generator/Passes/GetterSetterToPropertyPass.cs index 62640744f0..4d49a4a4ab 100644 --- a/src/Generator/Passes/GetterSetterToPropertyPass.cs +++ b/src/Generator/Passes/GetterSetterToPropertyPass.cs @@ -21,19 +21,16 @@ static GetterSetterToPropertyPass() 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 @@ public override bool VisitClassDecl(Class @class) return false; } - protected virtual List GetProperties(Class @class) => - new List(); + protected virtual List GetProperties() => new(); protected IEnumerable GenerateProperties(Class @class) { - List 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 @@ protected IEnumerable GenerateProperties(Class @class) 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 @@ private IEnumerable CleanUp(Class @class, List properties) 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 @@ private IEnumerable CleanUp(Class @class, List properties) return properties; } - private static void GetProperty(List properties, Method method, + private static void CreateOrUpdateProperty(List 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 @@ private static void RenameConflictingMethods(Class @class, Property property) 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 @@ private static void CombineComments(Property property) BriefText = getter.Comment.BriefText, Text = getter.Comment.Text }; + if (getter.Comment.FullComment != null) { comment.FullComment = new FullComment(); @@ -295,20 +290,18 @@ private static void CombineComments(Property property) 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 @@ private static string GetPropertyNameFromSetter(string name) 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 @@ private static string GetFirstWord(string name) return new string(firstWord.ToArray()); } - private static readonly HashSet verbs = new HashSet(); + private static readonly HashSet Verbs = new(); } } diff --git a/src/Generator/Types/Std/Stdlib.CSharp.cs b/src/Generator/Types/Std/Stdlib.CSharp.cs index 9f46125c00..83df7b1cd2 100644 --- a/src/Generator/Types/Std/Stdlib.CSharp.cs +++ b/src/Generator/Types/Std/Stdlib.CSharp.cs @@ -227,8 +227,6 @@ public override void CSharpMarshalToManaged(CSharpMarshalContext ctx) 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) diff --git a/src/Generator/Utils/Options.cs b/src/Generator/Utils/Options.cs index f5740700f9..845c41db0a 100644 --- a/src/Generator/Utils/Options.cs +++ b/src/Generator/Utils/Options.cs @@ -710,7 +710,6 @@ public string OptionName get { return this.option; } } - [SecurityPermission(SecurityAction.LinkDemand, SerializationFormatter = true)] public override void GetObjectData(SerializationInfo info, StreamingContext context) { base.GetObjectData(info, context); diff --git a/src/Parser/ASTConverter.cs b/src/Parser/ASTConverter.cs index 5e682d4971..f32f63c75b 100644 --- a/src/Parser/ASTConverter.cs +++ b/src/Parser/ASTConverter.cs @@ -1719,6 +1719,8 @@ AST.CppAbi VisitCppAbi(CppAbi abi) return AST.CppAbi.iOS; case CppAbi.iOS64: return AST.CppAbi.iOS64; + case CppAbi.WebAssembly: + return AST.CppAbi.WebAssembly; default: throw new ArgumentOutOfRangeException("abi"); } @@ -2081,6 +2083,7 @@ public override AST.Declaration VisitNonTypeTemplateParameter(NonTypeTemplatePar nonTypeTemplateParameter.IsParameterPack = decl.IsParameterPack; nonTypeTemplateParameter.IsPackExpansion = decl.IsPackExpansion; nonTypeTemplateParameter.IsExpandedParameterPack = decl.IsExpandedParameterPack; + nonTypeTemplateParameter.Type = typeConverter.VisitQualified(decl.Type); return nonTypeTemplateParameter; } diff --git a/src/Parser/Parser.cs b/src/Parser/Parser.cs index fa1a889b65..66d5daceaa 100644 --- a/src/Parser/Parser.cs +++ b/src/Parser/Parser.cs @@ -59,7 +59,7 @@ public static ParserResult ParseLibrary(LinkerOptions options) /// /// Converts a native parser AST to a managed AST. /// - static public AST.ASTContext ConvertASTContext(ASTContext context) + public static AST.ASTContext ConvertASTContext(ASTContext context) { var converter = new ASTConverter(context); return converter.Convert(); diff --git a/src/Parser/ParserOptions.cs b/src/Parser/ParserOptions.cs index 41dffa66d3..7cda0375e3 100644 --- a/src/Parser/ParserOptions.cs +++ b/src/Parser/ParserOptions.cs @@ -5,9 +5,7 @@ using System.IO; using System.Linq; using System.Reflection; -using System.Runtime.InteropServices; using System.Text.RegularExpressions; -using LanguageVersion = CppSharp.Parser.LanguageVersion; namespace CppSharp.Parser { @@ -200,20 +198,22 @@ private void GetUnixCompilerInfo(string headersPath, out string compiler, var versions = Directory.EnumerateDirectories(Path.Combine(headersPath, "usr", "include", "c++")); - if (versions.Count() == 0) + if (!versions.Any()) throw new Exception("No valid GCC version found on system include paths"); - string gccVersionPath = versions.First(); + var gccVersionPath = versions.First(); longVersion = shortVersion = gccVersionPath.Substring( gccVersionPath.LastIndexOf(Path.DirectorySeparatorChar) + 1); return; } - var info = new ProcessStartInfo(Environment.GetEnvironmentVariable("CXX") ?? "gcc", "-v"); - info.RedirectStandardError = true; - info.CreateNoWindow = true; - info.UseShellExecute = false; + var info = new ProcessStartInfo(Environment.GetEnvironmentVariable("CXX") ?? "gcc", "-v") + { + RedirectStandardError = true, + CreateNoWindow = true, + UseShellExecute = false + }; var process = Process.Start(info); if (process == null) @@ -237,13 +237,14 @@ public void SetupLinux(string headersPath = "") NoBuiltinIncludes = true; NoStandardIncludes = true; - string compiler, longVersion, shortVersion; - GetUnixCompilerInfo(headersPath, out compiler, out longVersion, out shortVersion); + GetUnixCompilerInfo(headersPath, out var compiler, out var longVersion, out var shortVersion); AddSystemIncludeDirs(BuiltinsDir); - AddArguments($"-fgnuc-version={longVersion}"); - string majorVersion = shortVersion.Split('.')[0]; + var majorVersion = shortVersion.Split('.')[0]; + // Workaround https://github.com/llvm/llvm-project/issues/53152, remove once bug is fixed. + AddArguments(int.Parse(majorVersion) >= 11 ? $"-fgnuc-version=10.1" : $"-fgnuc-version={longVersion}"); + string[] versions = { longVersion, shortVersion, majorVersion }; string[] triples = { "x86_64-linux-gnu", "x86_64-pc-linux-gnu" }; if (compiler == "gcc") @@ -277,19 +278,23 @@ public void SetupLinux(string headersPath = "") 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) { - // do not remove the CppSharp prefix becase the Mono C# compiler breaks - if (!LanguageVersion.HasValue) - LanguageVersion = CppSharp.Parser.LanguageVersion.CPP14_GNU; + LanguageVersion ??= CppSharp.Parser.LanguageVersion.CPP14_GNU; // As of Clang revision 5e866e411caa we are required to pass "-fgnuc-version=" // to get the __GNUC__ symbol defined. macOS and Linux system headers require @@ -299,7 +304,7 @@ private void SetupArguments() // 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: @@ -373,18 +378,21 @@ public string BuiltinsDir { 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(); @@ -395,6 +403,16 @@ private void SetupIncludes() 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(); } } } diff --git a/src/Runtime/SymbolResolver.cs b/src/Runtime/SymbolResolver.cs index cc2c3680eb..19e1645bc2 100644 --- a/src/Runtime/SymbolResolver.cs +++ b/src/Runtime/SymbolResolver.cs @@ -1,5 +1,5 @@ /* Copyright (c) 2013 Xamarin, Inc and contributors - * + * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including @@ -7,10 +7,10 @@ * distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: - * + * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. - * + * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND @@ -80,8 +80,8 @@ public static IntPtr LoadImage(ref string name) break; } } - if (!File.Exists(attempted)) - continue; + if (attempted == null) + attempted = filename; var ptr = loadImage(attempted); diff --git a/tests2/Builtins.h b/tests/Builtins.h similarity index 97% rename from tests2/Builtins.h rename to tests/Builtins.h index 3aa8015cbf..9b270e5385 100644 --- a/tests2/Builtins.h +++ b/tests/Builtins.h @@ -1,3 +1,4 @@ +#include #include void ReturnsVoid () { } @@ -40,8 +41,10 @@ int16_t ReturnsInt16 () { return -5; } uint16_t ReturnsUInt16 () { return 5; } int32_t ReturnsInt32 () { return -5; } uint32_t ReturnsUInt32 () { return 5; } +#if !defined(__EMSCRIPTEN__) int64_t ReturnsInt64 () { return -5; } uint64_t ReturnsUInt64 () { return 5; } +#endif int8_t PassAndReturnsInt8 (int8_t v) { return v; } uint8_t PassAndReturnsUInt8 (uint8_t v) { return v; } diff --git a/tests2/Classes.h b/tests/Classes.h similarity index 100% rename from tests2/Classes.h rename to tests/Classes.h diff --git a/tests2/Classes2.h b/tests/Classes2.h similarity index 100% rename from tests2/Classes2.h rename to tests/Classes2.h diff --git a/tests2/Delegates.h b/tests/Delegates.h similarity index 100% rename from tests2/Delegates.h rename to tests/Delegates.h diff --git a/tests2/Enums.h b/tests/Enums.h similarity index 100% rename from tests2/Enums.h rename to tests/Enums.h diff --git a/tests/NamespacesBase/premake4.lua b/tests/NamespacesBase/premake4.lua deleted file mode 100644 index 0c46c42af1..0000000000 --- a/tests/NamespacesBase/premake4.lua +++ /dev/null @@ -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")) \ No newline at end of file diff --git a/tests2/Overloads.h b/tests/Overloads.h similarity index 100% rename from tests2/Overloads.h rename to tests/Overloads.h diff --git a/tests/CLI/CLI.Gen.cs b/tests/dotnet/CLI/CLI.Gen.cs similarity index 100% rename from tests/CLI/CLI.Gen.cs rename to tests/dotnet/CLI/CLI.Gen.cs diff --git a/tests/CLI/CLI.Gen.csproj b/tests/dotnet/CLI/CLI.Gen.csproj similarity index 100% rename from tests/CLI/CLI.Gen.csproj rename to tests/dotnet/CLI/CLI.Gen.csproj diff --git a/tests/CLI/CLI.Tests.CLI.csproj b/tests/dotnet/CLI/CLI.Tests.CLI.csproj similarity index 100% rename from tests/CLI/CLI.Tests.CLI.csproj rename to tests/dotnet/CLI/CLI.Tests.CLI.csproj diff --git a/tests/CLI/CLI.Tests.cs b/tests/dotnet/CLI/CLI.Tests.cs similarity index 100% rename from tests/CLI/CLI.Tests.cs rename to tests/dotnet/CLI/CLI.Tests.cs diff --git a/tests/CLI/CLI.cpp b/tests/dotnet/CLI/CLI.cpp similarity index 100% rename from tests/CLI/CLI.cpp rename to tests/dotnet/CLI/CLI.cpp diff --git a/tests/CLI/CLI.h b/tests/dotnet/CLI/CLI.h similarity index 100% rename from tests/CLI/CLI.h rename to tests/dotnet/CLI/CLI.h diff --git a/tests/CLI/NestedEnumInClassTest/ClassWithNestedEnum.cpp b/tests/dotnet/CLI/NestedEnumInClassTest/ClassWithNestedEnum.cpp similarity index 100% rename from tests/CLI/NestedEnumInClassTest/ClassWithNestedEnum.cpp rename to tests/dotnet/CLI/NestedEnumInClassTest/ClassWithNestedEnum.cpp diff --git a/tests/CLI/NestedEnumInClassTest/ClassWithNestedEnum.h b/tests/dotnet/CLI/NestedEnumInClassTest/ClassWithNestedEnum.h similarity index 100% rename from tests/CLI/NestedEnumInClassTest/ClassWithNestedEnum.h rename to tests/dotnet/CLI/NestedEnumInClassTest/ClassWithNestedEnum.h diff --git a/tests/CLI/NestedEnumInClassTest/NestedEnumConsumer.cpp b/tests/dotnet/CLI/NestedEnumInClassTest/NestedEnumConsumer.cpp similarity index 100% rename from tests/CLI/NestedEnumInClassTest/NestedEnumConsumer.cpp rename to tests/dotnet/CLI/NestedEnumInClassTest/NestedEnumConsumer.cpp diff --git a/tests/CLI/NestedEnumInClassTest/NestedEnumConsumer.h b/tests/dotnet/CLI/NestedEnumInClassTest/NestedEnumConsumer.h similarity index 100% rename from tests/CLI/NestedEnumInClassTest/NestedEnumConsumer.h rename to tests/dotnet/CLI/NestedEnumInClassTest/NestedEnumConsumer.h diff --git a/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/Employee.cpp b/tests/dotnet/CLI/UseTemplateTypeFromIgnoredClassTemplate/Employee.cpp similarity index 100% rename from tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/Employee.cpp rename to tests/dotnet/CLI/UseTemplateTypeFromIgnoredClassTemplate/Employee.cpp diff --git a/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/Employee.h b/tests/dotnet/CLI/UseTemplateTypeFromIgnoredClassTemplate/Employee.h similarity index 100% rename from tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/Employee.h rename to tests/dotnet/CLI/UseTemplateTypeFromIgnoredClassTemplate/Employee.h diff --git a/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeForwardDecl.h b/tests/dotnet/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeForwardDecl.h similarity index 100% rename from tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeForwardDecl.h rename to tests/dotnet/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeForwardDecl.h diff --git a/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.cpp b/tests/dotnet/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.cpp similarity index 100% rename from tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.cpp rename to tests/dotnet/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.cpp diff --git a/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.h b/tests/dotnet/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.h similarity index 100% rename from tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.h rename to tests/dotnet/CLI/UseTemplateTypeFromIgnoredClassTemplate/EmployeeOrg.h diff --git a/tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/IgnoredClassTemplateForEmployee.h b/tests/dotnet/CLI/UseTemplateTypeFromIgnoredClassTemplate/IgnoredClassTemplateForEmployee.h similarity index 100% rename from tests/CLI/UseTemplateTypeFromIgnoredClassTemplate/IgnoredClassTemplateForEmployee.h rename to tests/dotnet/CLI/UseTemplateTypeFromIgnoredClassTemplate/IgnoredClassTemplateForEmployee.h diff --git a/tests/CLI/premake4.lua b/tests/dotnet/CLI/premake4.lua similarity index 100% rename from tests/CLI/premake4.lua rename to tests/dotnet/CLI/premake4.lua diff --git a/tests/CSharp/AnonTypes.h b/tests/dotnet/CSharp/AnonTypes.h similarity index 100% rename from tests/CSharp/AnonTypes.h rename to tests/dotnet/CSharp/AnonTypes.h diff --git a/tests/CSharp/AnotherUnit.cpp b/tests/dotnet/CSharp/AnotherUnit.cpp similarity index 100% rename from tests/CSharp/AnotherUnit.cpp rename to tests/dotnet/CSharp/AnotherUnit.cpp diff --git a/tests/CSharp/AnotherUnit.h b/tests/dotnet/CSharp/AnotherUnit.h similarity index 100% rename from tests/CSharp/AnotherUnit.h rename to tests/dotnet/CSharp/AnotherUnit.h diff --git a/tests/CSharp/CSharp.CSharp.csproj b/tests/dotnet/CSharp/CSharp.CSharp.csproj similarity index 65% rename from tests/CSharp/CSharp.CSharp.csproj rename to tests/dotnet/CSharp/CSharp.CSharp.csproj index a253523095..6a6c4bf76a 100644 --- a/tests/CSharp/CSharp.CSharp.csproj +++ b/tests/dotnet/CSharp/CSharp.CSharp.csproj @@ -1,4 +1,7 @@  + + 0108 + diff --git a/tests/CSharp/CSharp.Gen.cs b/tests/dotnet/CSharp/CSharp.Gen.cs similarity index 100% rename from tests/CSharp/CSharp.Gen.cs rename to tests/dotnet/CSharp/CSharp.Gen.cs diff --git a/tests/CSharp/CSharp.Gen.csproj b/tests/dotnet/CSharp/CSharp.Gen.csproj similarity index 100% rename from tests/CSharp/CSharp.Gen.csproj rename to tests/dotnet/CSharp/CSharp.Gen.csproj diff --git a/tests/CSharp/CSharp.Tests.CSharp.csproj b/tests/dotnet/CSharp/CSharp.Tests.CSharp.csproj similarity index 100% rename from tests/CSharp/CSharp.Tests.CSharp.csproj rename to tests/dotnet/CSharp/CSharp.Tests.CSharp.csproj diff --git a/tests/CSharp/CSharp.Tests.cs b/tests/dotnet/CSharp/CSharp.Tests.cs similarity index 99% rename from tests/CSharp/CSharp.Tests.cs rename to tests/dotnet/CSharp/CSharp.Tests.cs index 185c1d518a..7050fa744c 100644 --- a/tests/CSharp/CSharp.Tests.cs +++ b/tests/dotnet/CSharp/CSharp.Tests.cs @@ -346,6 +346,10 @@ public void TestDefaultArguments() methodsWithDefaultValues.DefaultWithSpecialization(); methodsWithDefaultValues.DefaultOverloadedImplicitCtor(); methodsWithDefaultValues.DefaultWithParamNamedSameAsMethod(5); + Assert.That(methodsWithDefaultValues.DefaultIntAssignedAnEnumWithBinaryOperatorAndFlags(), Is.EqualTo((int)(Bar.Items.Item1 | Bar.Items.Item2))); + Assert.That(methodsWithDefaultValues.DefaultWithConstantFlags(), Is.EqualTo(CSharp.CSharp.ConstFlag1 | CSharp.CSharp.ConstFlag2 | CSharp.CSharp.ConstFlag3)); + Assert.IsTrue(methodsWithDefaultValues.DefaultWithPointerToEnum()); + Assert.AreEqual(CSharp.CSharp.DefaultSmallPODInstance.__Instance, methodsWithDefaultValues.DefaultWithNonPrimitiveType().__Instance); } } @@ -1999,4 +2003,11 @@ public void TestCallByValueCopyConstructor() Assert.That(CallByValueCopyConstructor.CopyConstructorCalls, Is.EqualTo(1)); Assert.That(CallByValueCopyConstructor.DestructorCalls, Is.EqualTo(2)); } + + [Test] + public void TestPointerToClass() + { + Assert.IsTrue(CSharp.CSharp.PointerToClass.IsDefaultInstance); + Assert.IsTrue(CSharp.CSharp.PointerToClass.IsValid); + } } diff --git a/tests/CSharp/CSharp.cpp b/tests/dotnet/CSharp/CSharp.cpp similarity index 96% rename from tests/CSharp/CSharp.cpp rename to tests/dotnet/CSharp/CSharp.cpp index 33ff64b040..8d1d091260 100644 --- a/tests/CSharp/CSharp.cpp +++ b/tests/dotnet/CSharp/CSharp.cpp @@ -568,6 +568,8 @@ MethodsWithDefaultValues::QMargins::QMargins(int left, int top, int right, int b { } +struct SmallPOD DefaultSmallPODInstance; + const char* MethodsWithDefaultValues::stringConstant = "test"; int MethodsWithDefaultValues::intConstant = 5; @@ -808,6 +810,26 @@ int MethodsWithDefaultValues::DefaultWithParamNamedSameAsMethod(int DefaultWithP return 1; } +int MethodsWithDefaultValues::defaultIntAssignedAnEnumWithBinaryOperatorAndFlags(int f) +{ + return f; +} + +int MethodsWithDefaultValues::defaultWithConstantFlags(int f) +{ + return f; +} + +bool MethodsWithDefaultValues::defaultWithPointerToEnum(UntypedFlags* f1, int* f2) +{ + return (f1 == NULL || *f1 == (UntypedFlags)0) && (f2 == NULL || *f2 == 0); +} + +SmallPOD* MethodsWithDefaultValues::defaultWithNonPrimitiveType(SmallPOD& pod) +{ + return &pod; +} + int MethodsWithDefaultValues::getA() { return m_foo.A; @@ -1299,7 +1321,7 @@ TestString::TestString() : unicodeConst(L"ქართული ენა"), uni { } -TestChar32String::TestChar32String() : +TestChar32String::TestChar32String() : thirtyTwoBitConst(U"ქართული ენა") { static std::u32string nonConst = U"Test String"; @@ -1307,8 +1329,8 @@ TestChar32String::TestChar32String() : } TestChar32String::~TestChar32String() {} -void TestChar32String::UpdateString(const char32_t* s) -{ +void TestChar32String::UpdateString(const char32_t* s) +{ static std::u32string nativeOwnedMemory = s; thirtyTwoBitConst = nativeOwnedMemory.data(); } @@ -1316,8 +1338,8 @@ void TestChar32String::UpdateString(const char32_t* s) const char32_t* TestChar32String::RetrieveString() { return thirtyTwoBitConst; } void TestChar32String::functionPointerUTF32(void(*ptr)(const char32_t*)) {} -TestChar16String::TestChar16String() : - sixteenBitConst(u"ქართული ენა") +TestChar16String::TestChar16String() : + sixteenBitConst(u"ქართული ენა") { static std::u16string nonConst = u"Test String"; sixteenBitNonConst = &nonConst[0]; @@ -1325,10 +1347,10 @@ TestChar16String::TestChar16String() : TestChar16String::~TestChar16String() {} -void TestChar16String::UpdateString(const char16_t* s) -{ +void TestChar16String::UpdateString(const char16_t* s) +{ static std::u16string nativeOwnedMemory = s; - sixteenBitConst = nativeOwnedMemory.data(); + sixteenBitConst = nativeOwnedMemory.data(); } const char16_t* TestChar16String::RetrieveString() { return sixteenBitConst; } @@ -1667,7 +1689,7 @@ const unsigned ClassCustomTypeAlignmentOffsets[5] offsetof(ClassCustomTypeAlignment, align8), }; -const unsigned ClassCustomObjectAlignmentOffsets[2] { +const unsigned ClassCustomObjectAlignmentOffsets[2] { offsetof(ClassCustomObjectAlignment, boolean), offsetof(ClassCustomObjectAlignment, charAligned8), }; @@ -1776,3 +1798,21 @@ void CallByValueCopyConstructorFunction(CallByValueCopyConstructor s) { s.a = 99999; } +static PointerTester internalPointerTesterInstance; + +PointerTester::PointerTester() +{ + a = 0; +} + +bool PointerTester::IsDefaultInstance() +{ + return this == &internalPointerTesterInstance; +} + +bool PointerTester::IsValid() +{ + return a == 0; +} + +PointerTester* PointerToClass = &internalPointerTesterInstance; diff --git a/tests/CSharp/CSharp.h b/tests/dotnet/CSharp/CSharp.h similarity index 97% rename from tests/CSharp/CSharp.h rename to tests/dotnet/CSharp/CSharp.h index 6bd021b68f..7986dbe14f 100644 --- a/tests/CSharp/CSharp.h +++ b/tests/dotnet/CSharp/CSharp.h @@ -405,6 +405,12 @@ enum class Empty : unsigned long long int class _ClassWithLeadingUnderscore { }; +const int ConstFlag1 = 1; +const int ConstFlag2 = 2; +const int ConstFlag3 = 4; + +extern DLL_API struct SmallPOD DefaultSmallPODInstance; + class DLL_API MethodsWithDefaultValues : public Quux { public: @@ -480,6 +486,10 @@ class DLL_API MethodsWithDefaultValues : public Quux void defaultWithSpecialization(IndependentFields specialization = IndependentFields()); void defaultOverloadedImplicitCtor(P p); void defaultOverloadedImplicitCtor(Qux q = Qux()); + int defaultIntAssignedAnEnumWithBinaryOperatorAndFlags(int f = Bar::Item1 | Bar::Item2); + int defaultWithConstantFlags(int f = ConstFlag1 | ConstFlag2 | ConstFlag3); + bool defaultWithPointerToEnum(UntypedFlags* f1 = NULL, int* f2 = NULL); + SmallPOD* defaultWithNonPrimitiveType(SmallPOD& pod = DefaultSmallPODInstance); int DefaultWithParamNamedSameAsMethod(int DefaultWithParamNamedSameAsMethod, const Foo& defaultArg = Foo()); int getA(); private: @@ -1082,9 +1092,9 @@ class DLL_API VariablesWithInitializer { static constexpr const char* StringArray1[1] { "Str" "F,\"or" }; static constexpr const char* StringArray3[3] { "Str" "F,\"or", "C#", String }; static constexpr const char* StringArray30[30] { - "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", - "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", - "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", + "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", + "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", + "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", "Str", }; static constexpr const char* StringArray3EmptyInitList[3] { }; static constexpr const wchar_t* WideStringArray[2] { L"Str", L"C#" }; @@ -1278,7 +1288,7 @@ struct StructTestArrayTypeFromTypedef #define MY_MACRO_TEST2_4 (1 << 3) #define MY_MACRO_TEST2_ALL (1 << 4) - 1 -#define SIGNED_MACRO_VALUES_TO_ENUM_TEST_1 1 << 5 +#define SIGNED_MACRO_VALUES_TO_ENUM_TEST_1 1 << 5 #define SIGNED_MACRO_VALUES_TO_ENUM_TEST_2 1 << 22 #define SIGNED_MACRO_VALUES_TO_ENUM_TEST_3 1L << 32 #define SIGNED_MACRO_VALUES_TO_ENUM_TEST_4 -1 @@ -1465,9 +1475,9 @@ struct DLL_API ConversionFunctions short field = 100; }; -struct DLL_API ClassCustomTypeAlignment +struct DLL_API ClassCustomTypeAlignment { - struct alignas(1) Align1 { }; + struct alignas(1) Align1 { }; struct alignas(8) Align8 { }; struct alignas(16) Align16 { double a; @@ -1476,7 +1486,7 @@ struct DLL_API ClassCustomTypeAlignment bool boolean; Align16 align16; - Align1 align1; + Align1 align1; double dbl; Align8 align8; }; @@ -1524,7 +1534,7 @@ DLL_API extern const unsigned StructWithEmbeddedArrayOfStructObjectAlignmentOffs DLL_API const char* TestCSharpString(const char* in, CS_OUT const char** out); DLL_API const wchar_t* TestCSharpStringWide(const wchar_t* in, CS_OUT const wchar_t** out); -DLL_API const char16_t* TestCSharpString16(const char16_t* in, CS_OUT const char16_t** out); +DLL_API const char16_t* TestCSharpString16(const char16_t* in, CS_OUT const char16_t** out); DLL_API const char32_t* TestCSharpString32(const char32_t* in, CS_OUT const char32_t** out); struct DLL_API FTIStruct { int a; }; @@ -1595,3 +1605,13 @@ struct DLL_API CallByValueCopyConstructor { }; DLL_API void CallByValueCopyConstructorFunction(CallByValueCopyConstructor s); +class DLL_API PointerTester +{ + int a; +public: + PointerTester(); + bool IsDefaultInstance(); + bool IsValid(); +}; + +DLL_API extern PointerTester* PointerToClass; diff --git a/tests/CSharp/CSharpPartialMethods.cs b/tests/dotnet/CSharp/CSharpPartialMethods.cs similarity index 100% rename from tests/CSharp/CSharpPartialMethods.cs rename to tests/dotnet/CSharp/CSharpPartialMethods.cs diff --git a/tests/CSharp/CSharpTemplates.cpp b/tests/dotnet/CSharp/CSharpTemplates.cpp similarity index 100% rename from tests/CSharp/CSharpTemplates.cpp rename to tests/dotnet/CSharp/CSharpTemplates.cpp diff --git a/tests/CSharp/CSharpTemplates.h b/tests/dotnet/CSharp/CSharpTemplates.h similarity index 100% rename from tests/CSharp/CSharpTemplates.h rename to tests/dotnet/CSharp/CSharpTemplates.h diff --git a/tests/CSharp/ExcludedUnit.hpp b/tests/dotnet/CSharp/ExcludedUnit.hpp similarity index 100% rename from tests/CSharp/ExcludedUnit.hpp rename to tests/dotnet/CSharp/ExcludedUnit.hpp diff --git a/tests/CSharp/premake4.lua b/tests/dotnet/CSharp/premake4.lua similarity index 100% rename from tests/CSharp/premake4.lua rename to tests/dotnet/CSharp/premake4.lua diff --git a/tests/Common/AnotherUnit.cpp b/tests/dotnet/Common/AnotherUnit.cpp similarity index 100% rename from tests/Common/AnotherUnit.cpp rename to tests/dotnet/Common/AnotherUnit.cpp diff --git a/tests/Common/AnotherUnit.h b/tests/dotnet/Common/AnotherUnit.h similarity index 100% rename from tests/Common/AnotherUnit.h rename to tests/dotnet/Common/AnotherUnit.h diff --git a/tests/Common/Common.CSharp.csproj b/tests/dotnet/Common/Common.CSharp.csproj similarity index 100% rename from tests/Common/Common.CSharp.csproj rename to tests/dotnet/Common/Common.CSharp.csproj diff --git a/tests/Common/Common.Gen.cs b/tests/dotnet/Common/Common.Gen.cs similarity index 100% rename from tests/Common/Common.Gen.cs rename to tests/dotnet/Common/Common.Gen.cs diff --git a/tests/Common/Common.Gen.csproj b/tests/dotnet/Common/Common.Gen.csproj similarity index 100% rename from tests/Common/Common.Gen.csproj rename to tests/dotnet/Common/Common.Gen.csproj diff --git a/tests/Common/Common.Tests.CLI.csproj b/tests/dotnet/Common/Common.Tests.CLI.csproj similarity index 100% rename from tests/Common/Common.Tests.CLI.csproj rename to tests/dotnet/Common/Common.Tests.CLI.csproj diff --git a/tests/Common/Common.Tests.CSharp.csproj b/tests/dotnet/Common/Common.Tests.CSharp.csproj similarity index 100% rename from tests/Common/Common.Tests.CSharp.csproj rename to tests/dotnet/Common/Common.Tests.CSharp.csproj diff --git a/tests/Common/Common.Tests.cs b/tests/dotnet/Common/Common.Tests.cs similarity index 100% rename from tests/Common/Common.Tests.cs rename to tests/dotnet/Common/Common.Tests.cs diff --git a/tests/Common/Common.cpp b/tests/dotnet/Common/Common.cpp similarity index 99% rename from tests/Common/Common.cpp rename to tests/dotnet/Common/Common.cpp index 04d63cdd09..47076a023d 100644 --- a/tests/Common/Common.cpp +++ b/tests/dotnet/Common/Common.cpp @@ -1273,4 +1273,4 @@ extern "C" s.field2 = 10; return s; } -} // extern "C" \ No newline at end of file +} // extern "C" diff --git a/tests/Common/Common.h b/tests/dotnet/Common/Common.h similarity index 100% rename from tests/Common/Common.h rename to tests/dotnet/Common/Common.h diff --git a/tests/Common/interface.h b/tests/dotnet/Common/interface.h similarity index 100% rename from tests/Common/interface.h rename to tests/dotnet/Common/interface.h diff --git a/tests/Common/premake4.lua b/tests/dotnet/Common/premake4.lua similarity index 100% rename from tests/Common/premake4.lua rename to tests/dotnet/Common/premake4.lua diff --git a/tests/Directory.Build.props b/tests/dotnet/Directory.Build.props similarity index 83% rename from tests/Directory.Build.props rename to tests/dotnet/Directory.Build.props index 9b32f3ecd5..5402b2c443 100644 --- a/tests/Directory.Build.props +++ b/tests/dotnet/Directory.Build.props @@ -1,5 +1,5 @@ - + diff --git a/tests/Empty/Empty.Gen.cs b/tests/dotnet/Empty/Empty.Gen.cs similarity index 100% rename from tests/Empty/Empty.Gen.cs rename to tests/dotnet/Empty/Empty.Gen.cs diff --git a/tests/Empty/Empty.Tests.cs b/tests/dotnet/Empty/Empty.Tests.cs similarity index 100% rename from tests/Empty/Empty.Tests.cs rename to tests/dotnet/Empty/Empty.Tests.cs diff --git a/tests/Empty/Empty.cpp b/tests/dotnet/Empty/Empty.cpp similarity index 100% rename from tests/Empty/Empty.cpp rename to tests/dotnet/Empty/Empty.cpp diff --git a/tests/Empty/Empty.h b/tests/dotnet/Empty/Empty.h similarity index 100% rename from tests/Empty/Empty.h rename to tests/dotnet/Empty/Empty.h diff --git a/tests/Empty/premake4.lua b/tests/dotnet/Empty/premake4.lua similarity index 100% rename from tests/Empty/premake4.lua rename to tests/dotnet/Empty/premake4.lua diff --git a/tests/Encodings/Encodings.CSharp.csproj b/tests/dotnet/Encodings/Encodings.CSharp.csproj similarity index 100% rename from tests/Encodings/Encodings.CSharp.csproj rename to tests/dotnet/Encodings/Encodings.CSharp.csproj diff --git a/tests/Encodings/Encodings.Gen.cs b/tests/dotnet/Encodings/Encodings.Gen.cs similarity index 100% rename from tests/Encodings/Encodings.Gen.cs rename to tests/dotnet/Encodings/Encodings.Gen.cs diff --git a/tests/Encodings/Encodings.Gen.csproj b/tests/dotnet/Encodings/Encodings.Gen.csproj similarity index 100% rename from tests/Encodings/Encodings.Gen.csproj rename to tests/dotnet/Encodings/Encodings.Gen.csproj diff --git a/tests/Encodings/Encodings.Tests.CSharp.csproj b/tests/dotnet/Encodings/Encodings.Tests.CSharp.csproj similarity index 100% rename from tests/Encodings/Encodings.Tests.CSharp.csproj rename to tests/dotnet/Encodings/Encodings.Tests.CSharp.csproj diff --git a/tests/Encodings/Encodings.Tests.cs b/tests/dotnet/Encodings/Encodings.Tests.cs similarity index 100% rename from tests/Encodings/Encodings.Tests.cs rename to tests/dotnet/Encodings/Encodings.Tests.cs diff --git a/tests/Encodings/Encodings.cpp b/tests/dotnet/Encodings/Encodings.cpp similarity index 100% rename from tests/Encodings/Encodings.cpp rename to tests/dotnet/Encodings/Encodings.cpp diff --git a/tests/Encodings/Encodings.h b/tests/dotnet/Encodings/Encodings.h similarity index 100% rename from tests/Encodings/Encodings.h rename to tests/dotnet/Encodings/Encodings.h diff --git a/tests/Encodings/premake4.lua b/tests/dotnet/Encodings/premake4.lua similarity index 100% rename from tests/Encodings/premake4.lua rename to tests/dotnet/Encodings/premake4.lua diff --git a/tests/NamespacesBase/NamespacesBase.cpp b/tests/dotnet/NamespacesBase/NamespacesBase.cpp similarity index 100% rename from tests/NamespacesBase/NamespacesBase.cpp rename to tests/dotnet/NamespacesBase/NamespacesBase.cpp diff --git a/tests/NamespacesBase/NamespacesBase.h b/tests/dotnet/NamespacesBase/NamespacesBase.h similarity index 100% rename from tests/NamespacesBase/NamespacesBase.h rename to tests/dotnet/NamespacesBase/NamespacesBase.h diff --git a/tests/dotnet/NamespacesBase/premake4.lua b/tests/dotnet/NamespacesBase/premake4.lua new file mode 100644 index 0000000000..632b1083a9 --- /dev/null +++ b/tests/dotnet/NamespacesBase/premake4.lua @@ -0,0 +1,3 @@ +group "Tests/Namespaces" + SetupTestNativeProject("NamespacesBase") + targetdir (path.join(gendir, "NamespacesDerived")) \ No newline at end of file diff --git a/tests/NamespacesBase/test.cs b/tests/dotnet/NamespacesBase/test.cs similarity index 100% rename from tests/NamespacesBase/test.cs rename to tests/dotnet/NamespacesBase/test.cs diff --git a/tests/NamespacesDerived/Independent.h b/tests/dotnet/NamespacesDerived/Independent.h similarity index 100% rename from tests/NamespacesDerived/Independent.h rename to tests/dotnet/NamespacesDerived/Independent.h diff --git a/tests/NamespacesDerived/NamespacesDerived.Gen.cs b/tests/dotnet/NamespacesDerived/NamespacesDerived.Gen.cs similarity index 100% rename from tests/NamespacesDerived/NamespacesDerived.Gen.cs rename to tests/dotnet/NamespacesDerived/NamespacesDerived.Gen.cs diff --git a/tests/NamespacesDerived/NamespacesDerived.Gen.csproj b/tests/dotnet/NamespacesDerived/NamespacesDerived.Gen.csproj similarity index 100% rename from tests/NamespacesDerived/NamespacesDerived.Gen.csproj rename to tests/dotnet/NamespacesDerived/NamespacesDerived.Gen.csproj diff --git a/tests/NamespacesDerived/NamespacesDerived.Tests.CSharp.csproj b/tests/dotnet/NamespacesDerived/NamespacesDerived.Tests.CSharp.csproj similarity index 65% rename from tests/NamespacesDerived/NamespacesDerived.Tests.CSharp.csproj rename to tests/dotnet/NamespacesDerived/NamespacesDerived.Tests.CSharp.csproj index b6509a70d3..d1aefe5089 100644 --- a/tests/NamespacesDerived/NamespacesDerived.Tests.CSharp.csproj +++ b/tests/dotnet/NamespacesDerived/NamespacesDerived.Tests.CSharp.csproj @@ -4,10 +4,10 @@ - ..\..\build\gen\NamespacesDerived\NamespacesBase.dll + ..\..\..\build\gen\NamespacesDerived\NamespacesBase.dll - ..\..\build\gen\NamespacesDerived\NamespacesDerived.dll + ..\..\..\build\gen\NamespacesDerived\NamespacesDerived.dll \ No newline at end of file diff --git a/tests/NamespacesDerived/NamespacesDerived.Tests.cs b/tests/dotnet/NamespacesDerived/NamespacesDerived.Tests.cs similarity index 100% rename from tests/NamespacesDerived/NamespacesDerived.Tests.cs rename to tests/dotnet/NamespacesDerived/NamespacesDerived.Tests.cs diff --git a/tests/NamespacesDerived/NamespacesDerived.cpp b/tests/dotnet/NamespacesDerived/NamespacesDerived.cpp similarity index 100% rename from tests/NamespacesDerived/NamespacesDerived.cpp rename to tests/dotnet/NamespacesDerived/NamespacesDerived.cpp diff --git a/tests/NamespacesDerived/NamespacesDerived.h b/tests/dotnet/NamespacesDerived/NamespacesDerived.h similarity index 100% rename from tests/NamespacesDerived/NamespacesDerived.h rename to tests/dotnet/NamespacesDerived/NamespacesDerived.h diff --git a/tests/NamespacesDerived/premake4.lua b/tests/dotnet/NamespacesDerived/premake4.lua similarity index 100% rename from tests/NamespacesDerived/premake4.lua rename to tests/dotnet/NamespacesDerived/premake4.lua diff --git a/tests/Native/AST.h b/tests/dotnet/Native/AST.h similarity index 100% rename from tests/Native/AST.h rename to tests/dotnet/Native/AST.h diff --git a/tests/Native/ASTExtensions.h b/tests/dotnet/Native/ASTExtensions.h similarity index 100% rename from tests/Native/ASTExtensions.h rename to tests/dotnet/Native/ASTExtensions.h diff --git a/tests/Native/Enums.h b/tests/dotnet/Native/Enums.h similarity index 100% rename from tests/Native/Enums.h rename to tests/dotnet/Native/Enums.h diff --git a/tests/Native/Passes.h b/tests/dotnet/Native/Passes.h similarity index 100% rename from tests/Native/Passes.h rename to tests/dotnet/Native/Passes.h diff --git a/tests/Native/Templates.h b/tests/dotnet/Native/Templates.h similarity index 100% rename from tests/Native/Templates.h rename to tests/dotnet/Native/Templates.h diff --git a/tests/Native/linux/libexpat.so.0 b/tests/dotnet/Native/linux/libexpat.so.0 similarity index 100% rename from tests/Native/linux/libexpat.so.0 rename to tests/dotnet/Native/linux/libexpat.so.0 diff --git a/tests/Native/macos/libexpat.dylib b/tests/dotnet/Native/macos/libexpat.dylib similarity index 100% rename from tests/Native/macos/libexpat.dylib rename to tests/dotnet/Native/macos/libexpat.dylib diff --git a/tests/Native/windows/libexpat.dll b/tests/dotnet/Native/windows/libexpat.dll similarity index 100% rename from tests/Native/windows/libexpat.dll rename to tests/dotnet/Native/windows/libexpat.dll diff --git a/tests/StandardLib/StandardLib.Gen.cs b/tests/dotnet/StandardLib/StandardLib.Gen.cs similarity index 100% rename from tests/StandardLib/StandardLib.Gen.cs rename to tests/dotnet/StandardLib/StandardLib.Gen.cs diff --git a/tests/StandardLib/StandardLib.Gen.csproj b/tests/dotnet/StandardLib/StandardLib.Gen.csproj similarity index 100% rename from tests/StandardLib/StandardLib.Gen.csproj rename to tests/dotnet/StandardLib/StandardLib.Gen.csproj diff --git a/tests/StandardLib/StandardLib.Tests.CLI.csproj b/tests/dotnet/StandardLib/StandardLib.Tests.CLI.csproj similarity index 100% rename from tests/StandardLib/StandardLib.Tests.CLI.csproj rename to tests/dotnet/StandardLib/StandardLib.Tests.CLI.csproj diff --git a/tests/StandardLib/StandardLib.Tests.cs b/tests/dotnet/StandardLib/StandardLib.Tests.cs similarity index 100% rename from tests/StandardLib/StandardLib.Tests.cs rename to tests/dotnet/StandardLib/StandardLib.Tests.cs diff --git a/tests/StandardLib/StandardLib.cpp b/tests/dotnet/StandardLib/StandardLib.cpp similarity index 100% rename from tests/StandardLib/StandardLib.cpp rename to tests/dotnet/StandardLib/StandardLib.cpp diff --git a/tests/StandardLib/StandardLib.h b/tests/dotnet/StandardLib/StandardLib.h similarity index 100% rename from tests/StandardLib/StandardLib.h rename to tests/dotnet/StandardLib/StandardLib.h diff --git a/tests/StandardLib/premake4.lua b/tests/dotnet/StandardLib/premake4.lua similarity index 100% rename from tests/StandardLib/premake4.lua rename to tests/dotnet/StandardLib/premake4.lua diff --git a/tests/Test.Bindings.props b/tests/dotnet/Test.Bindings.props similarity index 100% rename from tests/Test.Bindings.props rename to tests/dotnet/Test.Bindings.props diff --git a/tests/Test.Common.props b/tests/dotnet/Test.Common.props similarity index 100% rename from tests/Test.Common.props rename to tests/dotnet/Test.Common.props diff --git a/tests/Test.Generator.props b/tests/dotnet/Test.Generator.props similarity index 100% rename from tests/Test.Generator.props rename to tests/dotnet/Test.Generator.props diff --git a/tests/Test.props b/tests/dotnet/Test.props similarity index 100% rename from tests/Test.props rename to tests/dotnet/Test.props diff --git a/tests/Tests.h b/tests/dotnet/Tests.h similarity index 100% rename from tests/Tests.h rename to tests/dotnet/Tests.h diff --git a/tests/VTables/VTables.CSharp.csproj b/tests/dotnet/VTables/VTables.CSharp.csproj similarity index 100% rename from tests/VTables/VTables.CSharp.csproj rename to tests/dotnet/VTables/VTables.CSharp.csproj diff --git a/tests/VTables/VTables.Gen.cs b/tests/dotnet/VTables/VTables.Gen.cs similarity index 100% rename from tests/VTables/VTables.Gen.cs rename to tests/dotnet/VTables/VTables.Gen.cs diff --git a/tests/VTables/VTables.Gen.csproj b/tests/dotnet/VTables/VTables.Gen.csproj similarity index 100% rename from tests/VTables/VTables.Gen.csproj rename to tests/dotnet/VTables/VTables.Gen.csproj diff --git a/tests/VTables/VTables.Tests.CSharp.csproj b/tests/dotnet/VTables/VTables.Tests.CSharp.csproj similarity index 100% rename from tests/VTables/VTables.Tests.CSharp.csproj rename to tests/dotnet/VTables/VTables.Tests.CSharp.csproj diff --git a/tests/VTables/VTables.Tests.cs b/tests/dotnet/VTables/VTables.Tests.cs similarity index 100% rename from tests/VTables/VTables.Tests.cs rename to tests/dotnet/VTables/VTables.Tests.cs diff --git a/tests/VTables/VTables.cpp b/tests/dotnet/VTables/VTables.cpp similarity index 100% rename from tests/VTables/VTables.cpp rename to tests/dotnet/VTables/VTables.cpp diff --git a/tests/VTables/VTables.h b/tests/dotnet/VTables/VTables.h similarity index 100% rename from tests/VTables/VTables.h rename to tests/dotnet/VTables/VTables.h diff --git a/tests/VTables/premake4.lua b/tests/dotnet/VTables/premake4.lua similarity index 100% rename from tests/VTables/premake4.lua rename to tests/dotnet/VTables/premake4.lua diff --git a/tests2/quickjs/.gitignore b/tests/emscripten/.gitignore similarity index 100% rename from tests2/quickjs/.gitignore rename to tests/emscripten/.gitignore diff --git a/tests/emscripten/premake5.lua b/tests/emscripten/premake5.lua new file mode 100644 index 0000000000..8fa7a73885 --- /dev/null +++ b/tests/emscripten/premake5.lua @@ -0,0 +1,21 @@ + +workspace "emscripten" + configurations { "debug", "release" } + location "gen" + symbols "On" + optimize "Off" + + project "test" + kind "SharedLib" + language "C++" + files + { + "gen/**.cpp", + } + includedirs + { + "..", + "../../include" + } + linkoptions { "--bind -sENVIRONMENT=node -sMODULARIZE=1 -sEXPORT_ALL -sEXPORT_ES6=1 -sUSE_ES6_IMPORT_META=1" } + targetextension ".mjs" \ No newline at end of file diff --git a/tests/emscripten/test.mjs b/tests/emscripten/test.mjs new file mode 100644 index 0000000000..95b8b0bf0b --- /dev/null +++ b/tests/emscripten/test.mjs @@ -0,0 +1,114 @@ +import wasmModule from "./gen/bin/debug/libtest.mjs"; +import { eq, ascii, floateq } from "./utils.mjs" + +const test = await wasmModule({ + onRuntimeInitialized() { + + } +}); + +function builtins() { + eq(test.ReturnsVoid(), undefined) + + eq(test.ReturnsBool(), true) + eq(test.PassAndReturnsBool(false), false) + + eq(test.ReturnsNullptr(), null) + eq(test.PassAndReturnsNullptr(null), null) + + eq(test.ReturnsChar(), ascii('a')); + eq(test.ReturnsSChar(), ascii('a')); + eq(test.ReturnsUChar(), ascii('a')); + + eq(test.PassAndReturnsChar(ascii('a')), ascii('a')); + eq(test.PassAndReturnsSChar(ascii('b')), ascii('b')); + eq(test.PassAndReturnsUChar(ascii('c')), ascii('c')); + + // TODO: add wchar_t tests + + eq(test.ReturnsFloat(), 5.0); + eq(test.ReturnsDouble(), -5.0); + //eq(test.ReturnsLongDouble(), -5.0); + + floateq(test.PassAndReturnsFloat(1.32), 1.32); + floateq(test.PassAndReturnsDouble(1.32), 1.32); + //float(test.PassAndReturnsLongDouble(1.32), 1.32); + + eq(test.ReturnsInt8(), -5); + eq(test.ReturnsUInt8(), 5); + eq(test.ReturnsInt16(), -5); + eq(test.ReturnsUInt16(), 5); + eq(test.ReturnsInt32(), -5); + eq(test.ReturnsUInt32(), 5); + + // TODO: + // https://github.com/WebAssembly/proposals/issues/7 + // https://github.com/emscripten-core/emscripten/issues/11140 + //eq(test.ReturnsInt64(), -5n); + //eq(test.ReturnsUInt64(), 5n); + + const int8 = { min: -(2 ** 7), max: (2 ** 7) - 1 }; + eq(test.PassAndReturnsInt8(int8.min), int8.min); + eq(test.PassAndReturnsInt8(int8.max), int8.max); + + const uint8 = { min: 0, max: (2 ** 8) - 1 }; + eq(test.PassAndReturnsUInt8(uint8.min), uint8.min); + eq(test.PassAndReturnsUInt8(uint8.max), uint8.max); + + const int16 = { min: -(2 ** 15), max: (2 ** 15) - 1 }; + eq(test.PassAndReturnsInt16(int16.min), int16.min); + eq(test.PassAndReturnsInt16(int16.max), int16.max); + + const uint16 = { min: 0, max: (2 ** 16) - 1 }; + eq(test.PassAndReturnsUInt16(uint16.min), uint16.min); + eq(test.PassAndReturnsUInt16(uint16.max), uint16.max); + + const int32 = { min: -(2 ** 31), max: (2 ** 31) - 1 }; + eq(test.PassAndReturnsInt32(int32.min), int32.min); + eq(test.PassAndReturnsInt32(int32.max), int32.max); + + const uint32 = { min: 0, max: (2 ** 32) - 1 }; + eq(test.PassAndReturnsUInt32(uint32.min), uint32.min); + eq(test.PassAndReturnsUInt32(uint32.max), uint32.max); + + //const int64 = { min: BigInt(2 ** 63) * -1n, max: BigInt(2 ** 63) - 1n }; + //eq(test.PassAndReturnsInt64(int64.min), int64.min); + //eq(test.PassAndReturnsInt64(int64.max), int64.max); + + //const uint64 = { min: BigInt(0), max: BigInt(2 ** 64) - 1n }; + //eq(test.PassAndReturnsUInt64(uint64.min), uint64.min); + //eq(test.PassAndReturnsUInt64(uint64.max), uint64.max); +} + +function enums() { + eq(test.Enum0.Item0.value, 0); + eq(test.Enum0.Item1.value, 1); + eq(test.Enum0.Item2.value, 5); + + eq(test.ReturnsEnum(), test.Enum0.Item0); + eq(test.PassAndReturnsEnum(test.Enum0.Item1), test.Enum0.Item1); +} + +function classes() { + var c = new test.Class(); + eq(typeof (c), "object") + eq(c.ReturnsVoid(), undefined) + eq(c.ReturnsInt(), 0) + eq(c.PassAndReturnsClassPtr(null), null) + + var c1 = new test.ClassWithSingleInheritance(); + eq(c1.__proto__.constructor.name, 'ClassWithSingleInheritance') + eq(c1.__proto__.__proto__.constructor.name, 'Class') + eq(c1.ReturnsVoid(), undefined); + eq(c1.ReturnsInt(), 0); + eq(c1.ChildMethod(), 2); + + var classWithField = new test.ClassWithField(); + eq(classWithField.ReturnsField(), 10); + eq(classWithField.Field, 10); +} + + +builtins(); +enums(); +classes(); \ No newline at end of file diff --git a/tests/emscripten/test.sh b/tests/emscripten/test.sh new file mode 100755 index 0000000000..52807e87dd --- /dev/null +++ b/tests/emscripten/test.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash +set -e +dir=$(cd "$(dirname "$0")"; pwd) +rootdir="$dir/../.." +dotnet_configuration=Release +configuration=debug +platform=x64 +jsinterp=node + +red=`tput setaf 1` +green=`tput setaf 2` +reset=`tput sgr0` + +generate=true + +if [ $generate = true ]; then + echo "${green}Generating bindings${reset}" + dotnet $rootdir/bin/${dotnet_configuration}_${platform}/CppSharp.CLI.dll \ + --gen=emscripten --platform=emscripten --arch=wasm32 \ + -I$dir/.. -I$rootdir/include -o $dir/gen -m tests $dir/../*.h +fi + +echo "${green}Building generated binding files${reset}" +premake=$rootdir/build/premake.sh +config=$configuration $premake --file=$dir/premake5.lua gmake +emmake make -C $dir/gen +echo + +echo "${green}Executing JS tests with Node${reset}" +$jsinterp $dir/test.mjs \ No newline at end of file diff --git a/tests/emscripten/utils.mjs b/tests/emscripten/utils.mjs new file mode 100644 index 0000000000..fb0eb6c73d --- /dev/null +++ b/tests/emscripten/utils.mjs @@ -0,0 +1,21 @@ +export function assert(actual, expected, message) { + if (arguments.length == 1) + expected = true; + + if (actual === expected) + return; + + if (actual !== null && expected !== null + && typeof actual == 'object' && typeof expected == 'object' + && actual.toString() === expected.toString()) + return; + + throw Error("assertion failed: got |" + actual + "|" + + ", expected |" + expected + "|" + + (message ? " (" + message + ")" : "")); +} + +export const eq = assert; +export const floateq = (actual, expected) => { assert(Math.abs(actual - expected) < 0.01) } + +export const ascii = v => v.charCodeAt(0) diff --git a/tests2/napi/.gitignore b/tests/napi/.gitignore similarity index 100% rename from tests2/napi/.gitignore rename to tests/napi/.gitignore diff --git a/tests2/napi/premake5.lua b/tests/napi/premake5.lua similarity index 100% rename from tests2/napi/premake5.lua rename to tests/napi/premake5.lua diff --git a/tests2/napi/test.js b/tests/napi/test.js similarity index 100% rename from tests2/napi/test.js rename to tests/napi/test.js diff --git a/tests2/napi/test.sh b/tests/napi/test.sh similarity index 100% rename from tests2/napi/test.sh rename to tests/napi/test.sh diff --git a/tests/quickjs/.gitignore b/tests/quickjs/.gitignore new file mode 100644 index 0000000000..36316b019c --- /dev/null +++ b/tests/quickjs/.gitignore @@ -0,0 +1,4 @@ +gen +*.so +*.dylib +*.dll diff --git a/tests2/quickjs/premake5.lua b/tests/quickjs/premake5.lua similarity index 100% rename from tests2/quickjs/premake5.lua rename to tests/quickjs/premake5.lua diff --git a/tests2/quickjs/test-prop.js b/tests/quickjs/test-prop.js similarity index 100% rename from tests2/quickjs/test-prop.js rename to tests/quickjs/test-prop.js diff --git a/tests2/quickjs/test.js b/tests/quickjs/test.js similarity index 100% rename from tests2/quickjs/test.js rename to tests/quickjs/test.js diff --git a/tests2/quickjs/test.sh b/tests/quickjs/test.sh similarity index 100% rename from tests2/quickjs/test.sh rename to tests/quickjs/test.sh diff --git a/tests2/test.sh b/tests/test.sh similarity index 80% rename from tests2/test.sh rename to tests/test.sh index 622401efcf..f5abc712b9 100755 --- a/tests2/test.sh +++ b/tests/test.sh @@ -4,3 +4,4 @@ dir=$(cd "$(dirname "$0")"; pwd) $dir/napi/test.sh $dir/quickjs/test.sh +$dir/emscripten/test.sh diff --git a/tests2/ts/.gitignore b/tests/ts/.gitignore similarity index 100% rename from tests2/ts/.gitignore rename to tests/ts/.gitignore diff --git a/tests2/ts/test.sh b/tests/ts/test.sh similarity index 100% rename from tests2/ts/test.sh rename to tests/ts/test.sh diff --git a/tests2/ts/test.ts b/tests/ts/test.ts similarity index 100% rename from tests2/ts/test.ts rename to tests/ts/test.ts diff --git a/tests2/ts/tsconfig.json b/tests/ts/tsconfig.json similarity index 100% rename from tests2/ts/tsconfig.json rename to tests/ts/tsconfig.json