From 357f8844d6c6894baa84a7b1e47ea8001330c3c6 Mon Sep 17 00:00:00 2001 From: David Maas Date: Sun, 19 Dec 2021 00:25:28 -0600 Subject: [PATCH] Added verification to highlight records which have a vtable but no constructors since they can't be initialized from C# yet. Relates to https://github.com/MochiLibraries/Biohazrd/issues/31 --- .../CSharpTranslationVerifier.cs | 8 +++ .../CSharpTranslationVerifierTests.cs | 58 +++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/Biohazrd.CSharp/#Transformations/CSharpTranslationVerifier.cs b/Biohazrd.CSharp/#Transformations/CSharpTranslationVerifier.cs index dcd827f..b8c6bc3 100644 --- a/Biohazrd.CSharp/#Transformations/CSharpTranslationVerifier.cs +++ b/Biohazrd.CSharp/#Transformations/CSharpTranslationVerifier.cs @@ -1,6 +1,7 @@ using Biohazrd.CSharp.Metadata; using Biohazrd.Expressions; using Biohazrd.Transformation; +using ClangSharp; using ClangSharp.Pathogen; using System.Collections.Immutable; using System.Linq; @@ -298,6 +299,13 @@ protected override TransformationResult TransformRecord(TransformationContext co else if (declaration.VTable is not null && declaration.VTableField is null) { declaration = declaration.WithError("Records should not have a VTable without a VTable field."); } + // We don't currently provide a way to initialize a virtual type without a constructor + // https://github.com/MochiLibraries/Biohazrd/issues/31 + if (declaration.VTable is not null + && !declaration.Members.OfType().Any(f => f.SpecialFunctionKind is SpecialFunctionKind.Constructor) + && declaration.Declaration is not CXXRecordDecl { IsAbstract: true }) + { declaration = declaration.WithWarning("Virtual records without a constructor cannot be initialized from C#. See https://github.com/MochiLibraries/Biohazrd/issues/31"); } + return base.TransformRecord(context, declaration); } diff --git a/Tests/Biohazrd.CSharp.Tests/CSharpTranslationVerifierTests.cs b/Tests/Biohazrd.CSharp.Tests/CSharpTranslationVerifierTests.cs index aabad80..5d88536 100644 --- a/Tests/Biohazrd.CSharp.Tests/CSharpTranslationVerifierTests.cs +++ b/Tests/Biohazrd.CSharp.Tests/CSharpTranslationVerifierTests.cs @@ -385,5 +385,63 @@ public void Constant_UnsupportedConstantNotOk() // Unsupported constants should mention the failure reason Assert.Single(constant.Diagnostics.Where(d => d.Message.Contains(nameof(Constant_UnsupportedConstantNotOk)))); } + + [Fact] + [RelatedIssue("https://github.com/MochiLibraries/Biohazrd/issues/31")] + public void Record_CannotInitializeConstructorlessVirtual() + { + TranslatedLibrary library = CreateLibrary + (@" +class MyClass +{ +public: + virtual void Test() { } +}; +" + ); + + Assert.Empty(library.FindDeclaration("MyClass").Diagnostics); + library = new CSharpTranslationVerifier().Transform(library); + Assert.Contains(library.FindDeclaration("MyClass").Diagnostics, d => d.Severity >= Severity.Warning); + } + + [Fact] + [RelatedIssue("https://github.com/MochiLibraries/Biohazrd/issues/31")] + public void Record_CannotInitializeConstructorlessVirtual_IgnoreAbstract() + { + TranslatedLibrary library = CreateLibrary + (@" +class MyClass +{ +public: + virtual void Test() = 0; +}; +" + ); + + Assert.Empty(library.FindDeclaration("MyClass").Diagnostics); + library = new CSharpTranslationVerifier().Transform(library); + Assert.Empty(library.FindDeclaration("MyClass").Diagnostics); + } + + [Fact] + [RelatedIssue("https://github.com/MochiLibraries/Biohazrd/issues/31")] + public void Record_CannotInitializeConstructorlessVirtual_ExplicitConstructorOk() + { + TranslatedLibrary library = CreateLibrary + (@" +class MyClass +{ +public: + MyClass() { } + virtual void Test() { } +}; +" + ); + + Assert.Empty(library.FindDeclaration("MyClass").Diagnostics); + library = new CSharpTranslationVerifier().Transform(library); + Assert.Empty(library.FindDeclaration("MyClass").Diagnostics); + } } }