mono / CppSharp

Tools and libraries to glue C/C++ APIs to high-level languages
MIT License
3.11k stars 510 forks source link

C# Code generation fails in GenerateFieldGetter method #1720

Open imaras opened 1 year ago

imaras commented 1 year ago
Description

If I try to generate C# code from:

class my_optional_u32
{
public:
    my_optional_u32() 
    {
        m_Object = {};
    }

    void set_value(uint32_t value) 
    {
        m_Object = value;
    }

    void set_null() 
    {
        m_Object = {};
    }

    uint32_t value() 
    {
        return m_Object.value();
    }

    bool has_value() 
    {
        return m_Object.has_value();
    }

private:
    std::optional<uint32_t> m_Object;
};

struct my_struct
{
    uint16_t Property1;
    uint16_t Property2;
    uint8_t Property3;
    my_optional_u32 Property4;
};

generation fails in https://github.com/mono/CppSharp/blob/main/src/Generator/Generators/CSharp/CSharpSources.cs line 1366

var name = ((Class)field.Namespace).Layout.Fields.First( f => f.FieldPtr == field.OriginalPtr).Name;

when generating property getter for field Property1. Collection Fields contains no elements.

OS: Windows

Used headers

optional

tritao commented 1 year ago

Thanks for reporting this.

imaras commented 1 year ago

I've managed to fix the issue by adding line bellow in Setup method

driver.ParserOptions.LanguageVersion = LanguageVersion.CPP17_GNU;

Reason why this is fix for the reported issue is that if LanguageVersion is unspecified in the process of code generation it gets set to LanguageVersion.CPP14_GNU and optional is not supported by this C++ version, as can be seen from https://en.cppreference.com/w/cpp/header/optional.

tritao commented 1 year ago

If you don't mind I'll keep this open in the meanwhile, since we should not be crashing regardless.

tritao commented 1 year ago

Reason why this is fix for the reported issue is that if LanguageVersion is unspecified in the process of code generation it gets set to LanguageVersion.CPP14_GNU and optional is not supported by this C++ version, as can be seen from

I think if that was the case, shouldn't you have gotten a parser error instead?

imaras commented 1 year ago

Printing parser error would be the way to go. At the moment exception call stack is printed.

Parsing libraries...
Parsed 'mylibrary.dll'
Parsing code...
Parsed 'myheader.h, optional'
Processing code...
Generating code...
Unhandled exception. System.InvalidOperationException: Sequence contains no matching element
   at System.Linq.ThrowHelper.ThrowNoMatchException()
   at System.Linq.Enumerable.First[TSource](IEnumerable`1 source, Func`2 predicate)
   at CppSharp.Generators.CSharp.CSharpSources.GenerateFieldGetter(Field field, Class class, QualifiedType returnType)
   at CppSharp.Generators.CSharp.CSharpSourcesExtensions.GenerateField(CSharpSources gen, Class class, Field field, Action`3 generate, Boolean isVoid)
   at CppSharp.Generators.CSharp.CSharpSources.GeneratePropertyGetter[T](T decl, Class class, Boolean isAbstract, Property property)
   at CppSharp.Generators.CSharp.CSharpSources.GenerateProperties(Class class)
   at CppSharp.Generators.CSharp.CSharpSources.GenerateClassProperties(Class class)
   at CppSharp.Generators.CSharp.CSharpSources.VisitClassDecl(Class class)
   at CppSharp.AST.Class.Visit[T](IDeclVisitor`1 visitor)
   at CppSharp.Generators.CSharp.CSharpSources.VisitDeclContext(DeclarationContext context)
   at CppSharp.Generators.CodeGenerator.VisitNamespace(Namespace namespace)
   at CppSharp.Generators.CSharp.CSharpSources.VisitNamespace(Namespace namespace)
   at CppSharp.AST.Namespace.Visit[T](IDeclVisitor`1 visitor)
   at CppSharp.Generators.CSharp.CSharpSources.VisitDeclContext(DeclarationContext context)
   at CppSharp.Generators.CodeGenerator.VisitNamespace(Namespace namespace)
   at CppSharp.Generators.CSharp.CSharpSources.VisitNamespace(Namespace namespace)
   at CppSharp.AST.Namespace.Visit[T](IDeclVisitor`1 visitor)
   at CppSharp.Generators.CSharp.CSharpSources.VisitDeclContext(DeclarationContext context)
   at CppSharp.Generators.CodeGenerator.VisitNamespace(Namespace namespace)
   at CppSharp.Generators.CSharp.CSharpSources.VisitNamespace(Namespace namespace)
   at CppSharp.Generators.CodeGenerator.VisitTranslationUnit(TranslationUnit unit)
   at CppSharp.AST.TranslationUnit.Visit[T](IDeclVisitor`1 visitor)
   at CppSharp.Generators.CSharp.CSharpSources.Process()
   at CppSharp.Generators.Generator.GenerateModule(Module module)
   at CppSharp.Generators.Generator.Generate()
   at CppSharp.Driver.GenerateCode()
   at CppSharp.ConsoleDriver.Run(ILibrary library)
   at Program.<Main>$(String[] args)