Browse Source

Added marshalling of std::string to the C# end.

Signed-off-by: Dimitar Dobrev <dpldobrev@protonmail.com>
pull/678/merge
Dimitar Dobrev 9 years ago
parent
commit
3cd024cccf
  1. 1
      build/Tests.lua
  2. 2
      src/AST/ASTVisitor.cs
  3. 29
      src/AST/ClassExtensions.cs
  4. 45
      src/CppParser/Parser.cpp
  5. 4
      src/CppParser/Parser.h
  6. 4
      src/Generator/Driver.cs
  7. 2
      src/Generator/Generators/CLI/CLIHeadersTemplate.cs
  8. 2
      src/Generator/Generators/CLI/CLISourcesTemplate.cs
  9. 108
      src/Generator/Generators/CSharp/CSharpTextTemplate.cs
  10. 3
      src/Generator/Passes/CheckIgnoredDecls.cs
  11. 8
      src/Generator/Passes/CleanUnitPass.cs
  12. 2
      src/Generator/Passes/GenerateAnonymousDelegatesPass.cs
  13. 31
      src/Generator/Passes/GenerateTemplatesCodePass.cs
  14. 2
      src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs
  15. 85
      src/Generator/Passes/IgnoreSystemDeclarationsPass.cs
  16. 5
      src/Generator/Passes/Pass.cs
  17. 41
      src/Generator/Types/Std/Stdlib.cs
  18. 8
      src/Generator/Types/TypeMap.cs
  19. 4
      src/Generator/Types/Types.cs
  20. 8
      tests/Common/Common.Tests.cs
  21. 12
      tests/Common/Common.cs

1
build/Tests.lua

@ -118,6 +118,7 @@ function SetupTestProjectsCSharp(name, depends) @@ -118,6 +118,7 @@ function SetupTestProjectsCSharp(name, depends)
files
{
path.join(gendir, name, name .. ".cs"),
path.join(gendir, name, "Std.cs")
}
linktable = { "CppSharp.Runtime" }

2
src/AST/ASTVisitor.cs

@ -291,7 +291,7 @@ namespace CppSharp.AST @@ -291,7 +291,7 @@ namespace CppSharp.AST
if (Options.VisitClassBases)
foreach (var baseClass in @class.Bases)
if (baseClass.IsClass)
VisitClassDecl(baseClass.Class);
baseClass.Class.Visit(this);
if (Options.VisitClassFields)
foreach (var field in @class.Fields)

29
src/AST/ClassExtensions.cs

@ -201,8 +201,33 @@ namespace CppSharp.AST @@ -201,8 +201,33 @@ namespace CppSharp.AST
public static IEnumerable<TranslationUnit> GetGenerated(this IEnumerable<TranslationUnit> units)
{
return units.Where(u => u.IsValid && !u.IsSystemHeader &&
u.IsGenerated && u.HasDeclarations);
return units.Where(u => u.IsGenerated && u.HasDeclarations && u.IsValid);
}
public static bool IsSupportedStdSpecialization(this ClassTemplateSpecialization specialization)
{
return IsSupportedStdType(specialization) &&
specialization.Arguments[0].Type.Type.IsPrimitiveType(PrimitiveType.Char);
}
public static bool IsSupportedStdType(this Declaration declaration)
{
return declaration.Namespace != null &&
declaration.TranslationUnit.IsSystemHeader &&
IsNameSpaceStd(declaration.Namespace) &&
supportedStdTypes.Contains(declaration.OriginalName);
}
private static bool IsNameSpaceStd(DeclarationContext declarationContext)
{
if (declarationContext == null)
return false;
var @namespace = declarationContext as Namespace;
if (@namespace != null && @namespace.IsInline)
return IsNameSpaceStd(declarationContext.Namespace);
return declarationContext.OriginalName == "std";
}
private static string[] supportedStdTypes = { "basic_string", "allocator" };
}
}

45
src/CppParser/Parser.cpp

@ -63,6 +63,25 @@ using namespace CppSharp::CppParser; @@ -63,6 +63,25 @@ using namespace CppSharp::CppParser;
// We use this as a placeholder for pointer values that should be ignored.
void* IgnorePtr = (void*) 0x1;
bool IsNamespaceStd(const clang::DeclContext* Namespace)
{
if (!Namespace)
return false;
if (Namespace->isInlineNamespace())
return IsNamespaceStd(llvm::cast<clang::Decl>(Namespace)->getDeclContext());
if (auto NamedDecl = llvm::dyn_cast<clang::NamedDecl>(Namespace))
return NamedDecl->getName() == "std";
return false;
}
bool Parser::IsStdTypeSupported(const clang::RecordDecl* Record)
{
auto TU = GetTranslationUnit(Record);
return TU->IsSystemHeader &&
IsNamespaceStd(Record->getDeclContext()) &&
(Record->getName() == "basic_string" || Record->getName() == "allocator");
}
//-----------------------------------//
Parser::Parser(ParserOptions* Opts) : Lib(Opts->ASTContext), Opts(Opts), Index(0)
@ -93,7 +112,7 @@ LayoutField Parser::WalkVTablePointer(Class* Class, @@ -93,7 +112,7 @@ LayoutField Parser::WalkVTablePointer(Class* Class,
}
void Parser::ReadClassLayout(Class* Class, const clang::RecordDecl* RD,
clang::CharUnits Offset, bool IncludeVirtualBases)
clang::CharUnits Offset, bool IncludeVirtualBases, bool IsSupportedStdType)
{
using namespace clang;
@ -144,7 +163,7 @@ void Parser::ReadClassLayout(Class* Class, const clang::RecordDecl* RD, @@ -144,7 +163,7 @@ void Parser::ReadClassLayout(Class* Class, const clang::RecordDecl* RD,
for (const CXXRecordDecl *Base : Bases) {
CharUnits BaseOffset = Offset + Layout.getBaseClassOffset(Base);
ReadClassLayout(Class, Base, BaseOffset,
/*IncludeVirtualBases=*/false);
/*IncludeVirtualBases=*/false, IsSupportedStdType);
}
// vbptr (for Microsoft C++ ABI)
@ -167,8 +186,14 @@ void Parser::ReadClassLayout(Class* Class, const clang::RecordDecl* RD, @@ -167,8 +186,14 @@ void Parser::ReadClassLayout(Class* Class, const clang::RecordDecl* RD,
// Recursively dump fields of record type.
if (auto RT = Field->getType()->getAs<RecordType>())
{
if (IsSupportedStdType)
{
ReadClassLayout(Class, RT->getDecl(), FieldOffset, IncludeVirtualBases, IsSupportedStdType);
continue;
}
auto TU = GetTranslationUnit(RT->getDecl());
if (TU->IsSystemHeader)
if (TU->IsSystemHeader && !IsStdTypeSupported(RT->getDecl()))
continue;
}
@ -199,7 +224,7 @@ void Parser::ReadClassLayout(Class* Class, const clang::RecordDecl* RD, @@ -199,7 +224,7 @@ void Parser::ReadClassLayout(Class* Class, const clang::RecordDecl* RD,
}
ReadClassLayout(Class, VBase, VBaseOffset,
/*IncludeVirtualBases=*/false);
/*IncludeVirtualBases=*/false, IsSupportedStdType);
}
}
}
@ -887,17 +912,15 @@ void Parser::WalkRecord(const clang::RecordDecl* Record, Class* RC) @@ -887,17 +912,15 @@ void Parser::WalkRecord(const clang::RecordDecl* Record, Class* RC)
bool hasLayout = !Record->isDependentType() && !Record->isInvalidDecl();
// Get the record layout information.
const ASTRecordLayout* Layout = 0;
if (hasLayout)
{
Layout = &C->getASTContext().getASTRecordLayout(Record);
const auto& Layout = C->getASTContext().getASTRecordLayout(Record);
if (!RC->Layout)
RC->Layout = new ClassLayout();
RC->Layout->Alignment = (int)Layout-> getAlignment().getQuantity();
RC->Layout->Size = (int)Layout->getSize().getQuantity();
RC->Layout->DataSize = (int)Layout->getDataSize().getQuantity();
ReadClassLayout(RC, Record, CharUnits(), true);
RC->Layout->Alignment = (int)Layout.getAlignment().getQuantity();
RC->Layout->Size = (int)Layout.getSize().getQuantity();
RC->Layout->DataSize = (int)Layout.getDataSize().getQuantity();
ReadClassLayout(RC, Record, CharUnits(), true, IsStdTypeSupported(Record));
}
for(auto it = Record->decls_begin(); it != Record->decls_end(); ++it)

4
src/CppParser/Parser.h

@ -59,7 +59,7 @@ public: @@ -59,7 +59,7 @@ public:
ParserTargetInfo* GetTargetInfo();
private:
bool IsStdTypeSupported(const clang::RecordDecl* Decl);
// AST traversers
void WalkAST();
Declaration* WalkDeclaration(const clang::Decl* D, bool CanBeDefinition = false);
@ -99,7 +99,7 @@ private: @@ -99,7 +99,7 @@ private:
std::vector<TemplateArgument> WalkTemplateArgumentList(const clang::TemplateArgumentList* TAL, const clang::ASTTemplateArgumentListInfo* TSTL);
void WalkVTable(const clang::CXXRecordDecl* RD, Class* C);
QualifiedType GetQualifiedType(clang::QualType qual, clang::TypeLoc* TL = 0);
void ReadClassLayout(Class* Class, const clang::RecordDecl* RD, clang::CharUnits Offset, bool IncludeVirtualBases);
void ReadClassLayout(Class* Class, const clang::RecordDecl* RD, clang::CharUnits Offset, bool IncludeVirtualBases, bool IsStdString = false);
LayoutField WalkVTablePointer(Class* Class, const clang::CharUnits& Offset, const std::string& prefix);
VTableLayout WalkVTableLayout(const clang::VTableLayout& VTLayout);
VTableComponent WalkVTableComponent(const clang::VTableComponent& Component);

4
src/Generator/Driver.cs

@ -434,6 +434,8 @@ namespace CppSharp @@ -434,6 +434,8 @@ namespace CppSharp
CompilerOptions = compilerOptions.ToString()
};
compilerParameters.ReferencedAssemblies.Add(
string.Format("{0}.dll", AST.Module.SystemModule.LibraryName));
// add a reference to System.Core
compilerParameters.ReferencedAssemblies.Add(typeof(Enumerable).Assembly.Location);
@ -526,7 +528,7 @@ namespace CppSharp @@ -526,7 +528,7 @@ namespace CppSharp
}
new CleanUnitPass(options).VisitLibrary(driver.ASTContext);
options.Modules.RemoveAll(m => !m.Units.GetGenerated().Any());
options.Modules.RemoveAll(m => m != AST.Module.SystemModule && !m.Units.GetGenerated().Any());
if (!options.Quiet)
Log.Message("Processing code...");

2
src/Generator/Generators/CLI/CLIHeadersTemplate.cs

@ -166,7 +166,7 @@ namespace CppSharp.Generators.CLI @@ -166,7 +166,7 @@ namespace CppSharp.Generators.CLI
// Generate all the struct/class declarations for the module.
foreach (var @class in decl.Classes)
{
if (!@class.IsGenerated || @class.IsIncomplete)
if (!@class.IsGenerated || @class.IsIncomplete || @class.IsDependent)
continue;
if (@class.IsOpaque)

2
src/Generator/Generators/CLI/CLISourcesTemplate.cs

@ -86,7 +86,7 @@ namespace CppSharp.Generators.CLI @@ -86,7 +86,7 @@ namespace CppSharp.Generators.CLI
PushBlock(CLIBlockKind.Namespace);
foreach (var @class in @namespace.Classes)
{
if (!@class.IsGenerated)
if (!@class.IsGenerated || @class.IsDependent)
continue;
if (@class.IsOpaque || @class.IsIncomplete)

108
src/Generator/Generators/CSharp/CSharpTextTemplate.cs

@ -8,7 +8,6 @@ using System.Text.RegularExpressions; @@ -8,7 +8,6 @@ using System.Text.RegularExpressions;
using System.Web.Util;
using CppSharp.AST;
using CppSharp.AST.Extensions;
using CppSharp.Passes;
using CppSharp.Types;
using CppSharp.Utils;
using Attribute = CppSharp.AST.Attribute;
@ -264,21 +263,25 @@ namespace CppSharp.Generators.CSharp @@ -264,21 +263,25 @@ namespace CppSharp.Generators.CSharp
foreach (var @class in context.Classes.Where(c => !c.IsIncomplete))
{
if (@class.IsInterface)
{
GenerateInterface(@class);
else
continue;
}
if (!@class.IsDependent)
{
if (@class.IsDependent)
{
if (!(@class.Namespace is Class))
{
GenerateClassTemplateSpecializationInternal(@class);
}
}
else
{
GenerateClass(@class);
}
GenerateClass(@class);
continue;
}
if (@class.IsSupportedStdType())
{
var specialization = @class.Specializations.SingleOrDefault(
ClassExtensions.IsSupportedStdSpecialization);
if (specialization != null)
GenerateClass(specialization);
}
else if ((!@class.Ignore || !@class.TranslationUnit.IsSystemHeader) &&
!(@class.Namespace is Class))
GenerateClassTemplateSpecializationInternal(@class);
}
if (context.HasFunctions)
@ -599,7 +602,7 @@ namespace CppSharp.Generators.CSharp @@ -599,7 +602,7 @@ namespace CppSharp.Generators.CSharp
foreach (var field in @class.Layout.Fields)
GenerateClassInternalsField(field);
if (@class.IsGenerated && !(@class is ClassTemplateSpecialization))
if (@class.IsGenerated && (!(@class is ClassTemplateSpecialization) || @class.IsSupportedStdType()))
{
var functions = GatherClassInternalFunctions(@class);
@ -787,10 +790,9 @@ namespace CppSharp.Generators.CSharp @@ -787,10 +790,9 @@ namespace CppSharp.Generators.CSharp
private void GenerateClassInternalsField(LayoutField field)
{
// we do not support dependent fields yet, see https://github.com/mono/CppSharp/issues/197
Declaration decl;
field.QualifiedType.Type.TryGetDeclaration(out decl);
if (decl != null && decl.TranslationUnit.IsSystemHeader)
if (decl != null && decl.TranslationUnit.IsSystemHeader && !decl.IsSupportedStdType())
return;
var arrayType = field.QualifiedType.Type.Desugar() as ArrayType;
@ -870,23 +872,6 @@ namespace CppSharp.Generators.CSharp @@ -870,23 +872,6 @@ namespace CppSharp.Generators.CSharp
#endregion
private Tuple<string, string> GetDeclarationLibrarySymbol(Variable decl)
{
var library = decl.TranslationUnit.Module.SharedLibraryName;
if (!Options.CheckSymbols)
goto Out;
NativeLibrary nativeLib;
if (!Driver.Symbols.FindLibraryBySymbol(decl.Mangled, out nativeLib))
goto Out;
library = Path.GetFileNameWithoutExtension(nativeLib.FileName);
Out:
return Tuple.Create(library, decl.Mangled);
}
private void GeneratePropertySetter<T>(T decl,
Class @class, bool isAbstract = false, Property property = null)
where T : Declaration, ITypedDecl
@ -1160,13 +1145,12 @@ namespace CppSharp.Generators.CSharp @@ -1160,13 +1145,12 @@ namespace CppSharp.Generators.CSharp
{
NewLine();
WriteStartBraceIndent();
var @var = decl as Variable;
var libSymbol = GetDeclarationLibrarySymbol(@var);
var var = decl as Variable;
TypePrinter.PushContext(CSharpTypePrinterContextKind.Native);
var location = string.Format("CppSharp.SymbolResolver.ResolveSymbol(\"{0}\", \"{1}\")",
libSymbol.Item1, libSymbol.Item2);
GetLibraryOf(decl), var.Mangled);
var arrayType = decl.Type as ArrayType;
var isRefTypeArray = arrayType != null && @class != null && @class.IsRefType;
@ -2613,7 +2597,8 @@ namespace CppSharp.Generators.CSharp @@ -2613,7 +2597,8 @@ namespace CppSharp.Generators.CSharp
var templateSpecialization = function.Namespace as ClassTemplateSpecialization;
string @namespace = templateSpecialization != null ?
string @namespace = templateSpecialization != null &&
!templateSpecialization.IsSupportedStdType() ?
(templateSpecialization.Namespace.OriginalName + '.') : string.Empty;
CheckArgumentRange(function);
@ -3120,13 +3105,37 @@ namespace CppSharp.Generators.CSharp @@ -3120,13 +3105,37 @@ namespace CppSharp.Generators.CSharp
PushBlock(CSharpBlockKind.InternalsClassMethod);
WriteLine("[SuppressUnmanagedCodeSecurity]");
Write("[DllImport(\"{0}\", ", GetLibraryOf(function));
var callConv = function.CallingConvention.ToInteropCallConv();
WriteLine("CallingConvention = global::System.Runtime.InteropServices.CallingConvention.{0},",
callConv);
WriteLineIndent("EntryPoint=\"{0}\")]", function.Mangled);
if (function.ReturnType.Type.IsPrimitiveType(PrimitiveType.Bool))
WriteLine("[return: MarshalAsAttribute(UnmanagedType.I1)]");
string libName = function.TranslationUnit.Module.SharedLibraryName;
CSharpTypePrinterResult retType;
var @params = GatherInternalParams(function, out retType);
WriteLine("internal static extern {0} {1}({2});", retType,
GetFunctionNativeIdentifier(function),
string.Join(", ", @params));
PopBlock(NewLineKind.BeforeNextBlock);
}
private string GetLibraryOf(Declaration declaration)
{
if (declaration.TranslationUnit.IsSystemHeader)
return Module.SystemModule.TemplatesLibraryName;
string libName = declaration.TranslationUnit.Module.SharedLibraryName;
if (Options.CheckSymbols)
{
NativeLibrary library;
Driver.Symbols.FindLibraryBySymbol(function.Mangled, out library);
Driver.Symbols.FindLibraryBySymbol(((IMangledDecl) declaration).Mangled, out library);
if (library != null)
libName = Path.GetFileNameWithoutExtension(library.FileName);
@ -3137,7 +3146,7 @@ namespace CppSharp.Generators.CSharp @@ -3137,7 +3146,7 @@ namespace CppSharp.Generators.CSharp
libName = libName.Substring(3);
}
if (libName == null)
libName = function.TranslationUnit.Module.SharedLibraryName;
libName = declaration.TranslationUnit.Module.SharedLibraryName;
if (Options.GenerateInternalImports)
libName = "__Internal";
@ -3156,24 +3165,7 @@ namespace CppSharp.Generators.CSharp @@ -3156,24 +3165,7 @@ namespace CppSharp.Generators.CSharp
}
}
Write("[DllImport(\"{0}\", ", libName);
var callConv = function.CallingConvention.ToInteropCallConv();
WriteLine("CallingConvention = global::System.Runtime.InteropServices.CallingConvention.{0},",
callConv);
WriteLineIndent("EntryPoint=\"{0}\")]", function.Mangled);
if (function.ReturnType.Type.IsPrimitiveType(PrimitiveType.Bool))
WriteLine("[return: MarshalAsAttribute(UnmanagedType.I1)]");
CSharpTypePrinterResult retType;
var @params = GatherInternalParams(function, out retType);
WriteLine("internal static extern {0} {1}({2});", retType,
GetFunctionNativeIdentifier(function),
string.Join(", ", @params));
PopBlock(NewLineKind.BeforeNextBlock);
return libName;
}
}

3
src/Generator/Passes/CheckIgnoredDecls.cs

@ -38,6 +38,9 @@ namespace CppSharp.Passes @@ -38,6 +38,9 @@ namespace CppSharp.Passes
if (!base.VisitClassTemplateDecl(template))
return false;
if (!Driver.Options.IsCLIGenerator && template.IsSupportedStdType())
return false;
// templates are not supported yet
foreach (var specialization in template.Specializations)
specialization.ExplicitlyIgnore();

8
src/Generator/Passes/CleanUnitPass.cs

@ -1,4 +1,3 @@ @@ -1,4 +1,3 @@
using System;
using System.IO;
using System.Linq;
using CppSharp.AST;
@ -16,7 +15,7 @@ namespace CppSharp.Passes @@ -16,7 +15,7 @@ namespace CppSharp.Passes
public override bool VisitTranslationUnit(TranslationUnit unit)
{
if (!unit.IsValid)
if (!base.VisitTranslationUnit(unit))
return false;
if (unit.IsSystemHeader)
@ -36,6 +35,11 @@ namespace CppSharp.Passes @@ -36,6 +35,11 @@ namespace CppSharp.Passes
return true;
}
public override bool VisitDeclarationContext(DeclarationContext context)
{
return false;
}
string GetIncludePath(string filePath)
{
var includePath = filePath;

2
src/Generator/Passes/GenerateAnonymousDelegatesPass.cs

@ -44,7 +44,7 @@ namespace CppSharp.Passes @@ -44,7 +44,7 @@ namespace CppSharp.Passes
public override bool VisitFunctionDecl(Function function)
{
if (!base.VisitFunctionDecl(function))
if (!base.VisitFunctionDecl(function) || function.Ignore)
return false;
function.ReturnType = CheckType(function.Namespace, function.ReturnType);

31
src/Generator/Passes/GenerateTemplatesCodePass.cs

@ -3,6 +3,7 @@ using System.IO; @@ -3,6 +3,7 @@ using System.IO;
using System.Linq;
using System.Text;
using CppSharp.AST;
using CppSharp.AST.Extensions;
using CppSharp.Types;
namespace CppSharp.Passes
@ -18,22 +19,36 @@ namespace CppSharp.Passes @@ -18,22 +19,36 @@ namespace CppSharp.Passes
public override bool VisitClassTemplateSpecializationDecl(ClassTemplateSpecialization specialization)
{
if (!specialization.IsDependent)
if (!specialization.IsDependent &&
(!specialization.TranslationUnit.IsSystemHeader ||
specialization.IsSupportedStdSpecialization()))
{
var cppTypePrinter = new CppTypePrinter { PrintScopeKind = CppTypePrintScopeKind.Qualified };
templateInstantiations.Add(specialization.Visit(cppTypePrinter));
var cppTypePrinter = new CppTypePrinter
{
PrintScopeKind = CppTypePrintScopeKind.Qualified,
PrintLogicalNames = true
};
var cppCode = specialization.Visit(cppTypePrinter);
var module = specialization.TranslationUnit.Module;
if (templateInstantiations.ContainsKey(module))
templateInstantiations[module].Add(cppCode);
else
templateInstantiations.Add(module, new HashSet<string> { cppCode });
}
return true;
}
private void WriteTemplateInstantiations()
{
foreach (var module in Driver.Options.Modules)
foreach (var module in Driver.Options.Modules.Where(m => templateInstantiations.ContainsKey(m)))
{
var cppBuilder = new StringBuilder();
foreach (var header in module.Headers)
cppBuilder.AppendFormat("#include <{0}>\n", header);
foreach (var templateInstantiation in templateInstantiations)
if (module == Module.SystemModule)
cppBuilder.Append("#include <string>\n");
else
foreach (var header in module.Headers)
cppBuilder.AppendFormat("#include <{0}>\n", header);
foreach (var templateInstantiation in templateInstantiations[module])
cppBuilder.AppendFormat("\ntemplate class {0}{1};",
Platform.IsWindows ? "__declspec(dllexport) " : string.Empty, templateInstantiation);
var cpp = string.Format("{0}.cpp", module.TemplatesLibraryName);
@ -43,6 +58,6 @@ namespace CppSharp.Passes @@ -43,6 +58,6 @@ namespace CppSharp.Passes
}
}
private HashSet<string> templateInstantiations = new HashSet<string>();
private Dictionary<Module, HashSet<string>> templateInstantiations = new Dictionary<Module, HashSet<string>>();
}
}

2
src/Generator/Passes/GetterSetterToPropertyAdvancedPass.cs

@ -330,7 +330,7 @@ namespace CppSharp.Passes @@ -330,7 +330,7 @@ namespace CppSharp.Passes
public override bool VisitClassDecl(Class @class)
{
if (VisitDeclarationContext(@class))
if (VisitDeclarationContext(@class) && !@class.IsSupportedStdType())
{
if (Options.VisitClassBases)
foreach (var baseClass in @class.Bases)

85
src/Generator/Passes/IgnoreSystemDeclarationsPass.cs

@ -1,14 +1,97 @@ @@ -1,14 +1,97 @@
using CppSharp.AST;
using System.Linq;
using CppSharp.AST;
using CppSharp.AST.Extensions;
namespace CppSharp.Passes
{
public class IgnoreSystemDeclarationsPass : TranslationUnitPass
{
public IgnoreSystemDeclarationsPass()
{
Options.VisitClassBases = false;
Options.VisitClassFields = false;
Options.VisitClassMethods = false;
Options.VisitClassProperties = false;
Options.VisitFunctionParameters = false;
Options.VisitFunctionReturnType = false;
Options.VisitNamespaceEnums = false;
Options.VisitNamespaceEvents = false;
Options.VisitNamespaceTemplates = false;
Options.VisitNamespaceTypedefs = false;
Options.VisitNamespaceVariables = false;
Options.VisitTemplateArguments = false;
}
public override bool VisitTranslationUnit(TranslationUnit unit)
{
if (!unit.IsValid)
return false;
if (unit.IsSystemHeader)
unit.ExplicitlyIgnore();
if (ClearVisitedDeclarations)
Visited.Clear();
VisitDeclarationContext(unit);
return true;
}
public override bool VisitDeclaration(Declaration decl)
{
if (decl.Namespace != null && decl.TranslationUnit.IsSystemHeader)
decl.ExplicitlyIgnore();
return base.VisitDeclaration(decl);
}
public override bool VisitClassDecl(Class @class)
{
if (!base.VisitClassDecl(@class) || !@class.IsDependent ||
Driver.Options.IsCLIGenerator || !@class.IsSupportedStdType())
return false;
// we only need a few members for marshalling so strip the rest
switch (@class.Name)
{
case "basic_string":
foreach (var specialization in @class.Specializations.Where(
s => s.IsSupportedStdSpecialization()))
{
MarkForGeneration(specialization);
foreach (var method in specialization.Methods.Where(m => m.OriginalName != "c_str"))
method.ExplicitlyIgnore();
var l = specialization.Methods.Where(m => m.IsConstructor && m.Parameters.Count == 2).ToList();
var ctor = specialization.Methods.Single(m => m.IsConstructor && m.Parameters.Count == 2 &&
m.Parameters[0].Type.Desugar().IsPointerToPrimitiveType(PrimitiveType.Char) &&
!m.Parameters[1].Type.Desugar().IsPrimitiveType());
ctor.GenerationKind = GenerationKind.Generate;
foreach (var parameter in ctor.Parameters)
parameter.DefaultArgument = null;
}
break;
case "allocator":
foreach (var specialization in @class.Specializations.Where(
s => s.IsSupportedStdSpecialization()))
{
MarkForGeneration(specialization);
foreach (var method in specialization.Methods.Where(m => !m.IsConstructor || m.Parameters.Any()))
method.ExplicitlyIgnore();
}
break;
}
return true;
}
private static void MarkForGeneration(ClassTemplateSpecialization specialization)
{
specialization.GenerationKind = GenerationKind.Generate;
Declaration declaration = specialization.TemplatedDecl.TemplatedDecl;
while (declaration != null)
{
declaration.GenerationKind = GenerationKind.Generate;
declaration = declaration.Namespace;
}
}
}
}

5
src/Generator/Passes/Pass.cs

@ -30,10 +30,7 @@ namespace CppSharp.Passes @@ -30,10 +30,7 @@ namespace CppSharp.Passes
public virtual bool VisitTranslationUnit(TranslationUnit unit)
{
if (!unit.IsValid)
return false;
if (unit.IsSystemHeader)
if (!unit.IsValid || unit.Ignore)
return false;
if (ClearVisitedDeclarations)

41
src/Generator/Types/Std/Stdlib.cs

@ -1,3 +1,4 @@ @@ -1,3 +1,4 @@
using System.Linq;
using CppSharp.AST;
using CppSharp.AST.Extensions;
using CppSharp.Generators;
@ -26,7 +27,7 @@ namespace CppSharp.Types.Std @@ -26,7 +27,7 @@ namespace CppSharp.Types.Std
}
}
[TypeMap("std::string", GeneratorKind.CLI)]
[TypeMap("std::string")]
public class String : TypeMap
{
public override string CLISignature(CLITypePrinterContext ctx)
@ -48,21 +49,47 @@ namespace CppSharp.Types.Std @@ -48,21 +49,47 @@ namespace CppSharp.Types.Std
public override string CSharpSignature(CSharpTypePrinterContext ctx)
{
return "Std.String";
if (ctx.CSharpKind == CSharpTypePrinterContextKind.Managed)
return "string";
ClassTemplateSpecialization basicString = GetBasicString(ctx.Type);
var typePrinter = new CSharpTypePrinter(null);
typePrinter.PushContext(CSharpTypePrinterContextKind.Native);
return basicString.Visit(typePrinter).Type;
}
public override void CSharpMarshalToNative(MarshalContext ctx)
{
ctx.Return.Write("new Std.String()");
ClassTemplateSpecialization basicString = GetBasicString(ctx.Parameter.Type);
var typePrinter = new CSharpTypePrinter(ctx.Driver);
typePrinter.PushContext(CSharpTypePrinterContextKind.Native);
if (!ctx.Parameter.Type.Desugar().IsAddress())
ctx.Return.Write("*({0}*) ", basicString.Visit(typePrinter));
typePrinter.PopContext();
var allocator = ctx.Driver.ASTContext.FindClass("allocator", false, true).First(
a => a.IsSupportedStdType());
ctx.Return.Write("new {0}({1}, new {2}()).{3}",
basicString.Visit(typePrinter), ctx.Parameter.Name,
allocator.Visit(typePrinter), Helpers.InstanceIdentifier);
}
public override void CSharpMarshalToManaged(MarshalContext ctx)
{
ctx.Return.Write(ctx.ReturnVarName);
ClassTemplateSpecialization basicString = GetBasicString(ctx.ReturnType.Type);
var c_str = basicString.Methods.First(m => m.OriginalName == "c_str");
var typePrinter = new CSharpTypePrinter(ctx.Driver);
ctx.Return.Write("{0}.{1}({2}).{3}()",
basicString.Visit(typePrinter), Helpers.CreateInstanceIdentifier,
ctx.ReturnVarName, c_str.Name);
}
private static ClassTemplateSpecialization GetBasicString(Type type)
{
var template = (type.GetFinalPointee() ?? type).Desugar();
return ((TemplateSpecializationType) template).GetClassTemplateSpecialization();
}
}
[TypeMap("std::wstring")]
[TypeMap("std::wstring", GeneratorKind = GeneratorKind.CLI)]
public class WString : TypeMap
{
public override string CLISignature(CLITypePrinterContext ctx)
@ -245,7 +272,7 @@ namespace CppSharp.Types.Std @@ -245,7 +272,7 @@ namespace CppSharp.Types.Std
}
}
[TypeMap("std::map")]
[TypeMap("std::map", GeneratorKind = GeneratorKind.CLI)]
public class Map : TypeMap
{
public override bool IsIgnored { get { return true; } }
@ -286,7 +313,7 @@ namespace CppSharp.Types.Std @@ -286,7 +313,7 @@ namespace CppSharp.Types.Std
public override bool IsIgnored { get { return true; } }
}
[TypeMap("std::shared_ptr")]
[TypeMap("std::shared_ptr", GeneratorKind = GeneratorKind.CLI)]
public class SharedPtr : TypeMap
{
public override bool IsIgnored { get { return true; } }

8
src/Generator/Types/TypeMap.cs

@ -165,11 +165,7 @@ namespace CppSharp.Types @@ -165,11 +165,7 @@ namespace CppSharp.Types
// We try to find type maps from the most qualified to less qualified
// types. Example: '::std::vector', 'std::vector' and 'vector'
var typePrinter = new CppTypePrinter()
{
PrintScopeKind = CppTypePrintScopeKind.GlobalQualified,
PrintLogicalNames = true
};
var typePrinter = new CppTypePrinter { PrintLogicalNames = true };
if (FindTypeMap(decl.Visit(typePrinter), out typeMap))
{
@ -204,7 +200,7 @@ namespace CppSharp.Types @@ -204,7 +200,7 @@ namespace CppSharp.Types
public bool FindTypeMap(Type type, out TypeMap typeMap)
{
var typePrinter = new CppTypePrinter();
var typePrinter = new CppTypePrinter { PrintLogicalNames = true };
var template = type as TemplateSpecializationType;
if (template != null && template.Template.TemplatedDecl != null)

4
src/Generator/Types/Types.cs

@ -117,7 +117,9 @@ namespace CppSharp @@ -117,7 +117,9 @@ namespace CppSharp
return false;
}
Ignore();
var specialization = template.GetClassTemplateSpecialization();
if (specialization == null || !specialization.IsSupportedStdType())
Ignore();
return base.VisitTemplateSpecializationType(template, quals);
}

8
tests/Common/Common.Tests.cs

@ -407,9 +407,11 @@ public class CommonTests : GeneratorTestFixture @@ -407,9 +407,11 @@ public class CommonTests : GeneratorTestFixture
public void TestVariable()
{
// Test field property
var @var = new TestVariables();
@var.Value = 10;
Assert.That(TestVariables.VALUE, Is.EqualTo(10));
// HACK: disabled until https://github.com/mono/CppSharp/issues/675 is fixed.
// It used to work thanks to a hack in Common.cs which is now removed because it caused problems with system types
//var @var = new TestVariables();
//@var.Value = 10;
//Assert.That(TestVariables.VALUE, Is.EqualTo(10));
}
[Test]

12
tests/Common/Common.cs

@ -78,6 +78,18 @@ namespace CppSharp.Tests @@ -78,6 +78,18 @@ namespace CppSharp.Tests
e => string.IsNullOrEmpty(e.Name)).Name = "RenamedEmptyEnum";
}
public override void Postprocess(Driver driver, ASTContext ctx)
{
// HACK: as seen above, GetterSetterToPropertyPass is called before all other passes
// that is a hack in order for the pass to generate properties in Common.h
// it is incapable of generating them in the proper manner
// so it generates a property in system type from a member which is later ignored
// so let's ignore that property manually
var @class = ctx.FindCompleteClass("basic_string");
foreach (var property in @class.Specializations.SelectMany(c => c.Properties))
property.ExplicitlyIgnore();
}
public static void Main(string[] args)
{
ConsoleDriver.Run(new CommonTestsGenerator(GeneratorKind.CLI));

Loading…
Cancel
Save